162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* ------------------------------------------------------------
362306a36Sopenharmony_ci * ibmvscsi.c
462306a36Sopenharmony_ci * (C) Copyright IBM Corporation 1994, 2004
562306a36Sopenharmony_ci * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
662306a36Sopenharmony_ci *          Santiago Leon (santil@us.ibm.com)
762306a36Sopenharmony_ci *          Dave Boutcher (sleddog@us.ibm.com)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * ------------------------------------------------------------
1062306a36Sopenharmony_ci * Emulation of a SCSI host adapter for Virtual I/O devices
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * This driver supports the SCSI adapter implemented by the IBM
1362306a36Sopenharmony_ci * Power5 firmware.  That SCSI adapter is not a physical adapter,
1462306a36Sopenharmony_ci * but allows Linux SCSI peripheral drivers to directly
1562306a36Sopenharmony_ci * access devices in another logical partition on the physical system.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * The virtual adapter(s) are present in the open firmware device
1862306a36Sopenharmony_ci * tree just like real adapters.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * One of the capabilities provided on these systems is the ability
2162306a36Sopenharmony_ci * to DMA between partitions.  The architecture states that for VSCSI,
2262306a36Sopenharmony_ci * the server side is allowed to DMA to and from the client.  The client
2362306a36Sopenharmony_ci * is never trusted to DMA to or from the server directly.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * Messages are sent between partitions on a "Command/Response Queue"
2662306a36Sopenharmony_ci * (CRQ), which is just a buffer of 16 byte entries in the receiver's
2762306a36Sopenharmony_ci * Senders cannot access the buffer directly, but send messages by
2862306a36Sopenharmony_ci * making a hypervisor call and passing in the 16 bytes.  The hypervisor
2962306a36Sopenharmony_ci * puts the message in the next 16 byte space in round-robin fashion,
3062306a36Sopenharmony_ci * turns on the high order bit of the message (the valid bit), and
3162306a36Sopenharmony_ci * generates an interrupt to the receiver (if interrupts are turned on.)
3262306a36Sopenharmony_ci * The receiver just turns off the valid bit when they have copied out
3362306a36Sopenharmony_ci * the message.
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit
3662306a36Sopenharmony_ci * (IU) (as defined in the T10 standard available at www.t10.org), gets
3762306a36Sopenharmony_ci * a DMA address for the message, and sends it to the server as the
3862306a36Sopenharmony_ci * payload of a CRQ message.  The server DMAs the SRP IU and processes it,
3962306a36Sopenharmony_ci * including doing any additional data transfers.  When it is done, it
4062306a36Sopenharmony_ci * DMAs the SRP response back to the same address as the request came from,
4162306a36Sopenharmony_ci * and sends a CRQ message back to inform the client that the request has
4262306a36Sopenharmony_ci * completed.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * TODO: This is currently pretty tied to the IBM pSeries hypervisor
4562306a36Sopenharmony_ci * interfaces.  It would be really nice to abstract this above an RDMA
4662306a36Sopenharmony_ci * layer.
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include <linux/module.h>
5062306a36Sopenharmony_ci#include <linux/moduleparam.h>
5162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
5262306a36Sopenharmony_ci#include <linux/delay.h>
5362306a36Sopenharmony_ci#include <linux/slab.h>
5462306a36Sopenharmony_ci#include <linux/of.h>
5562306a36Sopenharmony_ci#include <linux/pm.h>
5662306a36Sopenharmony_ci#include <linux/kthread.h>
5762306a36Sopenharmony_ci#include <asm/firmware.h>
5862306a36Sopenharmony_ci#include <asm/vio.h>
5962306a36Sopenharmony_ci#include <scsi/scsi.h>
6062306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h>
6162306a36Sopenharmony_ci#include <scsi/scsi_host.h>
6262306a36Sopenharmony_ci#include <scsi/scsi_device.h>
6362306a36Sopenharmony_ci#include <scsi/scsi_transport_srp.h>
6462306a36Sopenharmony_ci#include "ibmvscsi.h"
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* The values below are somewhat arbitrary default values, but
6762306a36Sopenharmony_ci * OS/400 will use 3 busses (disks, CDs, tapes, I think.)
6862306a36Sopenharmony_ci * Note that there are 3 bits of channel value, 6 bits of id, and
6962306a36Sopenharmony_ci * 5 bits of LUN.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistatic int max_id = 64;
7262306a36Sopenharmony_cistatic int max_channel = 3;
7362306a36Sopenharmony_cistatic int init_timeout = 300;
7462306a36Sopenharmony_cistatic int login_timeout = 60;
7562306a36Sopenharmony_cistatic int info_timeout = 30;
7662306a36Sopenharmony_cistatic int abort_timeout = 60;
7762306a36Sopenharmony_cistatic int reset_timeout = 60;
7862306a36Sopenharmony_cistatic int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
7962306a36Sopenharmony_cistatic int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
8062306a36Sopenharmony_cistatic int fast_fail = 1;
8162306a36Sopenharmony_cistatic int client_reserve = 1;
8262306a36Sopenharmony_cistatic char partition_name[96] = "UNKNOWN";
8362306a36Sopenharmony_cistatic unsigned int partition_number = -1;
8462306a36Sopenharmony_cistatic LIST_HEAD(ibmvscsi_head);
8562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ibmvscsi_driver_lock);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic struct scsi_transport_template *ibmvscsi_transport_template;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define IBMVSCSI_VERSION "1.5.9"
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciMODULE_DESCRIPTION("IBM Virtual SCSI");
9262306a36Sopenharmony_ciMODULE_AUTHOR("Dave Boutcher");
9362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
9462306a36Sopenharmony_ciMODULE_VERSION(IBMVSCSI_VERSION);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cimodule_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
9762306a36Sopenharmony_ciMODULE_PARM_DESC(max_id, "Largest ID value for each channel [Default=64]");
9862306a36Sopenharmony_cimodule_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
9962306a36Sopenharmony_ciMODULE_PARM_DESC(max_channel, "Largest channel value [Default=3]");
10062306a36Sopenharmony_cimodule_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
10162306a36Sopenharmony_ciMODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
10262306a36Sopenharmony_cimodule_param_named(max_requests, max_requests, int, S_IRUGO);
10362306a36Sopenharmony_ciMODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
10462306a36Sopenharmony_cimodule_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR);
10562306a36Sopenharmony_ciMODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]");
10662306a36Sopenharmony_cimodule_param_named(client_reserve, client_reserve, int, S_IRUGO );
10762306a36Sopenharmony_ciMODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release");
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic void ibmvscsi_handle_crq(struct viosrp_crq *crq,
11062306a36Sopenharmony_ci				struct ibmvscsi_host_data *hostdata);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/* ------------------------------------------------------------
11362306a36Sopenharmony_ci * Routines for managing the command/response queue
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ci/**
11662306a36Sopenharmony_ci * ibmvscsi_handle_event: - Interrupt handler for crq events
11762306a36Sopenharmony_ci * @irq:	number of irq to handle, not used
11862306a36Sopenharmony_ci * @dev_instance: ibmvscsi_host_data of host that received interrupt
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * Disables interrupts and schedules srp_task
12162306a36Sopenharmony_ci * Always returns IRQ_HANDLED
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_cistatic irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata =
12662306a36Sopenharmony_ci	    (struct ibmvscsi_host_data *)dev_instance;
12762306a36Sopenharmony_ci	vio_disable_interrupts(to_vio_dev(hostdata->dev));
12862306a36Sopenharmony_ci	tasklet_schedule(&hostdata->srp_task);
12962306a36Sopenharmony_ci	return IRQ_HANDLED;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/**
13362306a36Sopenharmony_ci * ibmvscsi_release_crq_queue() - Deallocates data and unregisters CRQ
13462306a36Sopenharmony_ci * @queue:		crq_queue to initialize and register
13562306a36Sopenharmony_ci * @hostdata:		ibmvscsi_host_data of host
13662306a36Sopenharmony_ci * @max_requests:	maximum requests (unused)
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
13962306a36Sopenharmony_ci * the crq with the hypervisor.
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_cistatic void ibmvscsi_release_crq_queue(struct crq_queue *queue,
14262306a36Sopenharmony_ci				       struct ibmvscsi_host_data *hostdata,
14362306a36Sopenharmony_ci				       int max_requests)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	long rc = 0;
14662306a36Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
14762306a36Sopenharmony_ci	free_irq(vdev->irq, (void *)hostdata);
14862306a36Sopenharmony_ci	tasklet_kill(&hostdata->srp_task);
14962306a36Sopenharmony_ci	do {
15062306a36Sopenharmony_ci		if (rc)
15162306a36Sopenharmony_ci			msleep(100);
15262306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
15362306a36Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
15462306a36Sopenharmony_ci	dma_unmap_single(hostdata->dev,
15562306a36Sopenharmony_ci			 queue->msg_token,
15662306a36Sopenharmony_ci			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
15762306a36Sopenharmony_ci	free_page((unsigned long)queue->msgs);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/**
16162306a36Sopenharmony_ci * crq_queue_next_crq: - Returns the next entry in message queue
16262306a36Sopenharmony_ci * @queue:	crq_queue to use
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * Returns pointer to next entry in queue, or NULL if there are no new
16562306a36Sopenharmony_ci * entried in the CRQ.
16662306a36Sopenharmony_ci */
16762306a36Sopenharmony_cistatic struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct viosrp_crq *crq;
17062306a36Sopenharmony_ci	unsigned long flags;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	spin_lock_irqsave(&queue->lock, flags);
17362306a36Sopenharmony_ci	crq = &queue->msgs[queue->cur];
17462306a36Sopenharmony_ci	if (crq->valid != VIOSRP_CRQ_FREE) {
17562306a36Sopenharmony_ci		if (++queue->cur == queue->size)
17662306a36Sopenharmony_ci			queue->cur = 0;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		/* Ensure the read of the valid bit occurs before reading any
17962306a36Sopenharmony_ci		 * other bits of the CRQ entry
18062306a36Sopenharmony_ci		 */
18162306a36Sopenharmony_ci		rmb();
18262306a36Sopenharmony_ci	} else
18362306a36Sopenharmony_ci		crq = NULL;
18462306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->lock, flags);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return crq;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/**
19062306a36Sopenharmony_ci * ibmvscsi_send_crq: - Send a CRQ
19162306a36Sopenharmony_ci * @hostdata:	the adapter
19262306a36Sopenharmony_ci * @word1:	the first 64 bits of the data
19362306a36Sopenharmony_ci * @word2:	the second 64 bits of the data
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cistatic int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
19662306a36Sopenharmony_ci			     u64 word1, u64 word2)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/*
20162306a36Sopenharmony_ci	 * Ensure the command buffer is flushed to memory before handing it
20262306a36Sopenharmony_ci	 * over to the VIOS to prevent it from fetching any stale data.
20362306a36Sopenharmony_ci	 */
20462306a36Sopenharmony_ci	mb();
20562306a36Sopenharmony_ci	return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/**
20962306a36Sopenharmony_ci * ibmvscsi_task: - Process srps asynchronously
21062306a36Sopenharmony_ci * @data:	ibmvscsi_host_data of host
21162306a36Sopenharmony_ci */
21262306a36Sopenharmony_cistatic void ibmvscsi_task(void *data)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
21562306a36Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
21662306a36Sopenharmony_ci	struct viosrp_crq *crq;
21762306a36Sopenharmony_ci	int done = 0;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	while (!done) {
22062306a36Sopenharmony_ci		/* Pull all the valid messages off the CRQ */
22162306a36Sopenharmony_ci		while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
22262306a36Sopenharmony_ci			ibmvscsi_handle_crq(crq, hostdata);
22362306a36Sopenharmony_ci			crq->valid = VIOSRP_CRQ_FREE;
22462306a36Sopenharmony_ci			wmb();
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		vio_enable_interrupts(vdev);
22862306a36Sopenharmony_ci		crq = crq_queue_next_crq(&hostdata->queue);
22962306a36Sopenharmony_ci		if (crq != NULL) {
23062306a36Sopenharmony_ci			vio_disable_interrupts(vdev);
23162306a36Sopenharmony_ci			ibmvscsi_handle_crq(crq, hostdata);
23262306a36Sopenharmony_ci			crq->valid = VIOSRP_CRQ_FREE;
23362306a36Sopenharmony_ci			wmb();
23462306a36Sopenharmony_ci		} else {
23562306a36Sopenharmony_ci			done = 1;
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic void gather_partition_info(void)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	const char *ppartition_name;
24362306a36Sopenharmony_ci	const __be32 *p_number_ptr;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* Retrieve information about this partition */
24662306a36Sopenharmony_ci	if (!of_root)
24762306a36Sopenharmony_ci		return;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	of_node_get(of_root);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	ppartition_name = of_get_property(of_root, "ibm,partition-name", NULL);
25262306a36Sopenharmony_ci	if (ppartition_name)
25362306a36Sopenharmony_ci		strscpy(partition_name, ppartition_name,
25462306a36Sopenharmony_ci				sizeof(partition_name));
25562306a36Sopenharmony_ci	p_number_ptr = of_get_property(of_root, "ibm,partition-no", NULL);
25662306a36Sopenharmony_ci	if (p_number_ptr)
25762306a36Sopenharmony_ci		partition_number = of_read_number(p_number_ptr, 1);
25862306a36Sopenharmony_ci	of_node_put(of_root);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic void set_adapter_info(struct ibmvscsi_host_data *hostdata)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	memset(&hostdata->madapter_info, 0x00,
26462306a36Sopenharmony_ci			sizeof(hostdata->madapter_info));
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	dev_info(hostdata->dev, "SRP_VERSION: %s\n", SRP_VERSION);
26762306a36Sopenharmony_ci	strcpy(hostdata->madapter_info.srp_version, SRP_VERSION);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	strncpy(hostdata->madapter_info.partition_name, partition_name,
27062306a36Sopenharmony_ci			sizeof(hostdata->madapter_info.partition_name));
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	hostdata->madapter_info.partition_number =
27362306a36Sopenharmony_ci					cpu_to_be32(partition_number);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	hostdata->madapter_info.mad_version = cpu_to_be32(SRP_MAD_VERSION_1);
27662306a36Sopenharmony_ci	hostdata->madapter_info.os_type = cpu_to_be32(SRP_MAD_OS_LINUX);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/**
28062306a36Sopenharmony_ci * ibmvscsi_reset_crq_queue() - resets a crq after a failure
28162306a36Sopenharmony_ci * @queue:	crq_queue to initialize and register
28262306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_cistatic int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
28562306a36Sopenharmony_ci				    struct ibmvscsi_host_data *hostdata)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	int rc = 0;
28862306a36Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* Close the CRQ */
29162306a36Sopenharmony_ci	do {
29262306a36Sopenharmony_ci		if (rc)
29362306a36Sopenharmony_ci			msleep(100);
29462306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
29562306a36Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* Clean out the queue */
29862306a36Sopenharmony_ci	memset(queue->msgs, 0x00, PAGE_SIZE);
29962306a36Sopenharmony_ci	queue->cur = 0;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	set_adapter_info(hostdata);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* And re-open it again */
30462306a36Sopenharmony_ci	rc = plpar_hcall_norets(H_REG_CRQ,
30562306a36Sopenharmony_ci				vdev->unit_address,
30662306a36Sopenharmony_ci				queue->msg_token, PAGE_SIZE);
30762306a36Sopenharmony_ci	if (rc == H_CLOSED) {
30862306a36Sopenharmony_ci		/* Adapter is good, but other end is not ready */
30962306a36Sopenharmony_ci		dev_warn(hostdata->dev, "Partner adapter not ready\n");
31062306a36Sopenharmony_ci	} else if (rc != 0) {
31162306a36Sopenharmony_ci		dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci	return rc;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/**
31762306a36Sopenharmony_ci * ibmvscsi_init_crq_queue() - Initializes and registers CRQ with hypervisor
31862306a36Sopenharmony_ci * @queue:		crq_queue to initialize and register
31962306a36Sopenharmony_ci * @hostdata:		ibmvscsi_host_data of host
32062306a36Sopenharmony_ci * @max_requests:	maximum requests (unused)
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * Allocates a page for messages, maps it for dma, and registers
32362306a36Sopenharmony_ci * the crq with the hypervisor.
32462306a36Sopenharmony_ci * Returns zero on success.
32562306a36Sopenharmony_ci */
32662306a36Sopenharmony_cistatic int ibmvscsi_init_crq_queue(struct crq_queue *queue,
32762306a36Sopenharmony_ci				   struct ibmvscsi_host_data *hostdata,
32862306a36Sopenharmony_ci				   int max_requests)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	int rc;
33162306a36Sopenharmony_ci	int retrc;
33262306a36Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (!queue->msgs)
33762306a36Sopenharmony_ci		goto malloc_failed;
33862306a36Sopenharmony_ci	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	queue->msg_token = dma_map_single(hostdata->dev, queue->msgs,
34162306a36Sopenharmony_ci					  queue->size * sizeof(*queue->msgs),
34262306a36Sopenharmony_ci					  DMA_BIDIRECTIONAL);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (dma_mapping_error(hostdata->dev, queue->msg_token))
34562306a36Sopenharmony_ci		goto map_failed;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	gather_partition_info();
34862306a36Sopenharmony_ci	set_adapter_info(hostdata);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	retrc = rc = plpar_hcall_norets(H_REG_CRQ,
35162306a36Sopenharmony_ci				vdev->unit_address,
35262306a36Sopenharmony_ci				queue->msg_token, PAGE_SIZE);
35362306a36Sopenharmony_ci	if (rc == H_RESOURCE)
35462306a36Sopenharmony_ci		/* maybe kexecing and resource is busy. try a reset */
35562306a36Sopenharmony_ci		rc = ibmvscsi_reset_crq_queue(queue,
35662306a36Sopenharmony_ci					      hostdata);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (rc == H_CLOSED) {
35962306a36Sopenharmony_ci		/* Adapter is good, but other end is not ready */
36062306a36Sopenharmony_ci		dev_warn(hostdata->dev, "Partner adapter not ready\n");
36162306a36Sopenharmony_ci		retrc = 0;
36262306a36Sopenharmony_ci	} else if (rc != 0) {
36362306a36Sopenharmony_ci		dev_warn(hostdata->dev, "Error %d opening adapter\n", rc);
36462306a36Sopenharmony_ci		goto reg_crq_failed;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	queue->cur = 0;
36862306a36Sopenharmony_ci	spin_lock_init(&queue->lock);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
37162306a36Sopenharmony_ci		     (unsigned long)hostdata);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (request_irq(vdev->irq,
37462306a36Sopenharmony_ci			ibmvscsi_handle_event,
37562306a36Sopenharmony_ci			0, "ibmvscsi", (void *)hostdata) != 0) {
37662306a36Sopenharmony_ci		dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
37762306a36Sopenharmony_ci			vdev->irq);
37862306a36Sopenharmony_ci		goto req_irq_failed;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	rc = vio_enable_interrupts(vdev);
38262306a36Sopenharmony_ci	if (rc != 0) {
38362306a36Sopenharmony_ci		dev_err(hostdata->dev, "Error %d enabling interrupts!!!\n", rc);
38462306a36Sopenharmony_ci		goto req_irq_failed;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	return retrc;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci      req_irq_failed:
39062306a36Sopenharmony_ci	tasklet_kill(&hostdata->srp_task);
39162306a36Sopenharmony_ci	rc = 0;
39262306a36Sopenharmony_ci	do {
39362306a36Sopenharmony_ci		if (rc)
39462306a36Sopenharmony_ci			msleep(100);
39562306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
39662306a36Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
39762306a36Sopenharmony_ci      reg_crq_failed:
39862306a36Sopenharmony_ci	dma_unmap_single(hostdata->dev,
39962306a36Sopenharmony_ci			 queue->msg_token,
40062306a36Sopenharmony_ci			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
40162306a36Sopenharmony_ci      map_failed:
40262306a36Sopenharmony_ci	free_page((unsigned long)queue->msgs);
40362306a36Sopenharmony_ci      malloc_failed:
40462306a36Sopenharmony_ci	return -1;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci/**
40862306a36Sopenharmony_ci * ibmvscsi_reenable_crq_queue() - reenables a crq after
40962306a36Sopenharmony_ci * @queue:	crq_queue to initialize and register
41062306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
41162306a36Sopenharmony_ci */
41262306a36Sopenharmony_cistatic int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
41362306a36Sopenharmony_ci				       struct ibmvscsi_host_data *hostdata)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	int rc = 0;
41662306a36Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	set_adapter_info(hostdata);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Re-enable the CRQ */
42162306a36Sopenharmony_ci	do {
42262306a36Sopenharmony_ci		if (rc)
42362306a36Sopenharmony_ci			msleep(100);
42462306a36Sopenharmony_ci		rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
42562306a36Sopenharmony_ci	} while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (rc)
42862306a36Sopenharmony_ci		dev_err(hostdata->dev, "Error %d enabling adapter\n", rc);
42962306a36Sopenharmony_ci	return rc;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/* ------------------------------------------------------------
43362306a36Sopenharmony_ci * Routines for the event pool and event structs
43462306a36Sopenharmony_ci */
43562306a36Sopenharmony_ci/**
43662306a36Sopenharmony_ci * initialize_event_pool: - Allocates and initializes the event pool for a host
43762306a36Sopenharmony_ci * @pool:	event_pool to be initialized
43862306a36Sopenharmony_ci * @size:	Number of events in pool
43962306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data who owns the event pool
44062306a36Sopenharmony_ci *
44162306a36Sopenharmony_ci * Returns zero on success.
44262306a36Sopenharmony_ci */
44362306a36Sopenharmony_cistatic int initialize_event_pool(struct event_pool *pool,
44462306a36Sopenharmony_ci				 int size, struct ibmvscsi_host_data *hostdata)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	int i;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	pool->size = size;
44962306a36Sopenharmony_ci	pool->next = 0;
45062306a36Sopenharmony_ci	pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL);
45162306a36Sopenharmony_ci	if (!pool->events)
45262306a36Sopenharmony_ci		return -ENOMEM;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	pool->iu_storage =
45562306a36Sopenharmony_ci	    dma_alloc_coherent(hostdata->dev,
45662306a36Sopenharmony_ci			       pool->size * sizeof(*pool->iu_storage),
45762306a36Sopenharmony_ci			       &pool->iu_token, GFP_KERNEL);
45862306a36Sopenharmony_ci	if (!pool->iu_storage) {
45962306a36Sopenharmony_ci		kfree(pool->events);
46062306a36Sopenharmony_ci		return -ENOMEM;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	for (i = 0; i < pool->size; ++i) {
46462306a36Sopenharmony_ci		struct srp_event_struct *evt = &pool->events[i];
46562306a36Sopenharmony_ci		memset(&evt->crq, 0x00, sizeof(evt->crq));
46662306a36Sopenharmony_ci		atomic_set(&evt->free, 1);
46762306a36Sopenharmony_ci		evt->crq.valid = VIOSRP_CRQ_CMD_RSP;
46862306a36Sopenharmony_ci		evt->crq.IU_length = cpu_to_be16(sizeof(*evt->xfer_iu));
46962306a36Sopenharmony_ci		evt->crq.IU_data_ptr = cpu_to_be64(pool->iu_token +
47062306a36Sopenharmony_ci			sizeof(*evt->xfer_iu) * i);
47162306a36Sopenharmony_ci		evt->xfer_iu = pool->iu_storage + i;
47262306a36Sopenharmony_ci		evt->hostdata = hostdata;
47362306a36Sopenharmony_ci		evt->ext_list = NULL;
47462306a36Sopenharmony_ci		evt->ext_list_token = 0;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/**
48162306a36Sopenharmony_ci * release_event_pool() - Frees memory of an event pool of a host
48262306a36Sopenharmony_ci * @pool:	event_pool to be released
48362306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data who owns the even pool
48462306a36Sopenharmony_ci *
48562306a36Sopenharmony_ci * Returns zero on success.
48662306a36Sopenharmony_ci */
48762306a36Sopenharmony_cistatic void release_event_pool(struct event_pool *pool,
48862306a36Sopenharmony_ci			       struct ibmvscsi_host_data *hostdata)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	int i, in_use = 0;
49162306a36Sopenharmony_ci	for (i = 0; i < pool->size; ++i) {
49262306a36Sopenharmony_ci		if (atomic_read(&pool->events[i].free) != 1)
49362306a36Sopenharmony_ci			++in_use;
49462306a36Sopenharmony_ci		if (pool->events[i].ext_list) {
49562306a36Sopenharmony_ci			dma_free_coherent(hostdata->dev,
49662306a36Sopenharmony_ci				  SG_ALL * sizeof(struct srp_direct_buf),
49762306a36Sopenharmony_ci				  pool->events[i].ext_list,
49862306a36Sopenharmony_ci				  pool->events[i].ext_list_token);
49962306a36Sopenharmony_ci		}
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci	if (in_use)
50262306a36Sopenharmony_ci		dev_warn(hostdata->dev, "releasing event pool with %d "
50362306a36Sopenharmony_ci			 "events still in use?\n", in_use);
50462306a36Sopenharmony_ci	kfree(pool->events);
50562306a36Sopenharmony_ci	dma_free_coherent(hostdata->dev,
50662306a36Sopenharmony_ci			  pool->size * sizeof(*pool->iu_storage),
50762306a36Sopenharmony_ci			  pool->iu_storage, pool->iu_token);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci/**
51162306a36Sopenharmony_ci * valid_event_struct: - Determines if event is valid.
51262306a36Sopenharmony_ci * @pool:	event_pool that contains the event
51362306a36Sopenharmony_ci * @evt:	srp_event_struct to be checked for validity
51462306a36Sopenharmony_ci *
51562306a36Sopenharmony_ci * Returns zero if event is invalid, one otherwise.
51662306a36Sopenharmony_ci*/
51762306a36Sopenharmony_cistatic int valid_event_struct(struct event_pool *pool,
51862306a36Sopenharmony_ci				struct srp_event_struct *evt)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	int index = evt - pool->events;
52162306a36Sopenharmony_ci	if (index < 0 || index >= pool->size)	/* outside of bounds */
52262306a36Sopenharmony_ci		return 0;
52362306a36Sopenharmony_ci	if (evt != pool->events + index)	/* unaligned */
52462306a36Sopenharmony_ci		return 0;
52562306a36Sopenharmony_ci	return 1;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci/**
52962306a36Sopenharmony_ci * free_event_struct() - Changes status of event to "free"
53062306a36Sopenharmony_ci * @pool:	event_pool that contains the event
53162306a36Sopenharmony_ci * @evt:	srp_event_struct to be modified
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_cistatic void free_event_struct(struct event_pool *pool,
53462306a36Sopenharmony_ci				       struct srp_event_struct *evt)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	if (!valid_event_struct(pool, evt)) {
53762306a36Sopenharmony_ci		dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p "
53862306a36Sopenharmony_ci			"(not in pool %p)\n", evt, pool->events);
53962306a36Sopenharmony_ci		return;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci	if (atomic_inc_return(&evt->free) != 1) {
54262306a36Sopenharmony_ci		dev_err(evt->hostdata->dev, "Freeing event_struct %p "
54362306a36Sopenharmony_ci			"which is not in use!\n", evt);
54462306a36Sopenharmony_ci		return;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci/**
54962306a36Sopenharmony_ci * get_event_struct() - Gets the next free event in pool
55062306a36Sopenharmony_ci * @pool:	event_pool that contains the events to be searched
55162306a36Sopenharmony_ci *
55262306a36Sopenharmony_ci * Returns the next event in "free" state, and NULL if none are free.
55362306a36Sopenharmony_ci * Note that no synchronization is done here, we assume the host_lock
55462306a36Sopenharmony_ci * will syncrhonze things.
55562306a36Sopenharmony_ci*/
55662306a36Sopenharmony_cistatic struct srp_event_struct *get_event_struct(struct event_pool *pool)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	int i;
55962306a36Sopenharmony_ci	int poolsize = pool->size;
56062306a36Sopenharmony_ci	int offset = pool->next;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	for (i = 0; i < poolsize; i++) {
56362306a36Sopenharmony_ci		offset = (offset + 1) % poolsize;
56462306a36Sopenharmony_ci		if (!atomic_dec_if_positive(&pool->events[offset].free)) {
56562306a36Sopenharmony_ci			pool->next = offset;
56662306a36Sopenharmony_ci			return &pool->events[offset];
56762306a36Sopenharmony_ci		}
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n");
57162306a36Sopenharmony_ci	return NULL;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci/**
57562306a36Sopenharmony_ci * init_event_struct: Initialize fields in an event struct that are always
57662306a36Sopenharmony_ci *                    required.
57762306a36Sopenharmony_ci * @evt_struct: The event
57862306a36Sopenharmony_ci * @done:       Routine to call when the event is responded to
57962306a36Sopenharmony_ci * @format:     SRP or MAD format
58062306a36Sopenharmony_ci * @timeout:    timeout value set in the CRQ
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_cistatic void init_event_struct(struct srp_event_struct *evt_struct,
58362306a36Sopenharmony_ci			      void (*done) (struct srp_event_struct *),
58462306a36Sopenharmony_ci			      u8 format,
58562306a36Sopenharmony_ci			      int timeout)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	evt_struct->cmnd = NULL;
58862306a36Sopenharmony_ci	evt_struct->cmnd_done = NULL;
58962306a36Sopenharmony_ci	evt_struct->sync_srp = NULL;
59062306a36Sopenharmony_ci	evt_struct->crq.format = format;
59162306a36Sopenharmony_ci	evt_struct->crq.timeout = cpu_to_be16(timeout);
59262306a36Sopenharmony_ci	evt_struct->done = done;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci/* ------------------------------------------------------------
59662306a36Sopenharmony_ci * Routines for receiving SCSI responses from the hosting partition
59762306a36Sopenharmony_ci */
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci/*
60062306a36Sopenharmony_ci * set_srp_direction: Set the fields in the srp related to data
60162306a36Sopenharmony_ci *     direction and number of buffers based on the direction in
60262306a36Sopenharmony_ci *     the scsi_cmnd and the number of buffers
60362306a36Sopenharmony_ci */
60462306a36Sopenharmony_cistatic void set_srp_direction(struct scsi_cmnd *cmd,
60562306a36Sopenharmony_ci			      struct srp_cmd *srp_cmd,
60662306a36Sopenharmony_ci			      int numbuf)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	u8 fmt;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (numbuf == 0)
61162306a36Sopenharmony_ci		return;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (numbuf == 1)
61462306a36Sopenharmony_ci		fmt = SRP_DATA_DESC_DIRECT;
61562306a36Sopenharmony_ci	else {
61662306a36Sopenharmony_ci		fmt = SRP_DATA_DESC_INDIRECT;
61762306a36Sopenharmony_ci		numbuf = min(numbuf, MAX_INDIRECT_BUFS);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		if (cmd->sc_data_direction == DMA_TO_DEVICE)
62062306a36Sopenharmony_ci			srp_cmd->data_out_desc_cnt = numbuf;
62162306a36Sopenharmony_ci		else
62262306a36Sopenharmony_ci			srp_cmd->data_in_desc_cnt = numbuf;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE)
62662306a36Sopenharmony_ci		srp_cmd->buf_fmt = fmt << 4;
62762306a36Sopenharmony_ci	else
62862306a36Sopenharmony_ci		srp_cmd->buf_fmt = fmt;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci/**
63262306a36Sopenharmony_ci * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
63362306a36Sopenharmony_ci * @cmd:	srp_cmd whose additional_data member will be unmapped
63462306a36Sopenharmony_ci * @evt_struct: the event
63562306a36Sopenharmony_ci * @dev:	device for which the memory is mapped
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_cistatic void unmap_cmd_data(struct srp_cmd *cmd,
63862306a36Sopenharmony_ci			   struct srp_event_struct *evt_struct,
63962306a36Sopenharmony_ci			   struct device *dev)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	u8 out_fmt, in_fmt;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	out_fmt = cmd->buf_fmt >> 4;
64462306a36Sopenharmony_ci	in_fmt = cmd->buf_fmt & ((1U << 4) - 1);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC)
64762306a36Sopenharmony_ci		return;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (evt_struct->cmnd)
65062306a36Sopenharmony_ci		scsi_dma_unmap(evt_struct->cmnd);
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic int map_sg_list(struct scsi_cmnd *cmd, int nseg,
65462306a36Sopenharmony_ci		       struct srp_direct_buf *md)
65562306a36Sopenharmony_ci{
65662306a36Sopenharmony_ci	int i;
65762306a36Sopenharmony_ci	struct scatterlist *sg;
65862306a36Sopenharmony_ci	u64 total_length = 0;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	scsi_for_each_sg(cmd, sg, nseg, i) {
66162306a36Sopenharmony_ci		struct srp_direct_buf *descr = md + i;
66262306a36Sopenharmony_ci		descr->va = cpu_to_be64(sg_dma_address(sg));
66362306a36Sopenharmony_ci		descr->len = cpu_to_be32(sg_dma_len(sg));
66462306a36Sopenharmony_ci		descr->key = 0;
66562306a36Sopenharmony_ci		total_length += sg_dma_len(sg);
66662306a36Sopenharmony_ci 	}
66762306a36Sopenharmony_ci	return total_length;
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci/**
67162306a36Sopenharmony_ci * map_sg_data: - Maps dma for a scatterlist and initializes descriptor fields
67262306a36Sopenharmony_ci * @cmd:	struct scsi_cmnd with the scatterlist
67362306a36Sopenharmony_ci * @evt_struct:	struct srp_event_struct to map
67462306a36Sopenharmony_ci * @srp_cmd:	srp_cmd that contains the memory descriptor
67562306a36Sopenharmony_ci * @dev:	device for which to map dma memory
67662306a36Sopenharmony_ci *
67762306a36Sopenharmony_ci * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
67862306a36Sopenharmony_ci * Returns 1 on success.
67962306a36Sopenharmony_ci*/
68062306a36Sopenharmony_cistatic int map_sg_data(struct scsi_cmnd *cmd,
68162306a36Sopenharmony_ci		       struct srp_event_struct *evt_struct,
68262306a36Sopenharmony_ci		       struct srp_cmd *srp_cmd, struct device *dev)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	int sg_mapped;
68662306a36Sopenharmony_ci	u64 total_length = 0;
68762306a36Sopenharmony_ci	struct srp_direct_buf *data =
68862306a36Sopenharmony_ci		(struct srp_direct_buf *) srp_cmd->add_data;
68962306a36Sopenharmony_ci	struct srp_indirect_buf *indirect =
69062306a36Sopenharmony_ci		(struct srp_indirect_buf *) data;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	sg_mapped = scsi_dma_map(cmd);
69362306a36Sopenharmony_ci	if (!sg_mapped)
69462306a36Sopenharmony_ci		return 1;
69562306a36Sopenharmony_ci	else if (sg_mapped < 0)
69662306a36Sopenharmony_ci		return 0;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	set_srp_direction(cmd, srp_cmd, sg_mapped);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/* special case; we can use a single direct descriptor */
70162306a36Sopenharmony_ci	if (sg_mapped == 1) {
70262306a36Sopenharmony_ci		map_sg_list(cmd, sg_mapped, data);
70362306a36Sopenharmony_ci		return 1;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	indirect->table_desc.va = 0;
70762306a36Sopenharmony_ci	indirect->table_desc.len = cpu_to_be32(sg_mapped *
70862306a36Sopenharmony_ci					       sizeof(struct srp_direct_buf));
70962306a36Sopenharmony_ci	indirect->table_desc.key = 0;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (sg_mapped <= MAX_INDIRECT_BUFS) {
71262306a36Sopenharmony_ci		total_length = map_sg_list(cmd, sg_mapped,
71362306a36Sopenharmony_ci					   &indirect->desc_list[0]);
71462306a36Sopenharmony_ci		indirect->len = cpu_to_be32(total_length);
71562306a36Sopenharmony_ci		return 1;
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* get indirect table */
71962306a36Sopenharmony_ci	if (!evt_struct->ext_list) {
72062306a36Sopenharmony_ci		evt_struct->ext_list = dma_alloc_coherent(dev,
72162306a36Sopenharmony_ci					   SG_ALL * sizeof(struct srp_direct_buf),
72262306a36Sopenharmony_ci					   &evt_struct->ext_list_token, 0);
72362306a36Sopenharmony_ci		if (!evt_struct->ext_list) {
72462306a36Sopenharmony_ci			if (!firmware_has_feature(FW_FEATURE_CMO))
72562306a36Sopenharmony_ci				sdev_printk(KERN_ERR, cmd->device,
72662306a36Sopenharmony_ci				            "Can't allocate memory "
72762306a36Sopenharmony_ci				            "for indirect table\n");
72862306a36Sopenharmony_ci			scsi_dma_unmap(cmd);
72962306a36Sopenharmony_ci			return 0;
73062306a36Sopenharmony_ci		}
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	indirect->len = cpu_to_be32(total_length);
73662306a36Sopenharmony_ci	indirect->table_desc.va = cpu_to_be64(evt_struct->ext_list_token);
73762306a36Sopenharmony_ci	indirect->table_desc.len = cpu_to_be32(sg_mapped *
73862306a36Sopenharmony_ci					       sizeof(indirect->desc_list[0]));
73962306a36Sopenharmony_ci	memcpy(indirect->desc_list, evt_struct->ext_list,
74062306a36Sopenharmony_ci	       MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
74162306a36Sopenharmony_ci 	return 1;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci/**
74562306a36Sopenharmony_ci * map_data_for_srp_cmd: - Calls functions to map data for srp cmds
74662306a36Sopenharmony_ci * @cmd:	struct scsi_cmnd with the memory to be mapped
74762306a36Sopenharmony_ci * @evt_struct:	struct srp_event_struct to map
74862306a36Sopenharmony_ci * @srp_cmd:	srp_cmd that contains the memory descriptor
74962306a36Sopenharmony_ci * @dev:	dma device for which to map dma memory
75062306a36Sopenharmony_ci *
75162306a36Sopenharmony_ci * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds
75262306a36Sopenharmony_ci * Returns 1 on success.
75362306a36Sopenharmony_ci*/
75462306a36Sopenharmony_cistatic int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
75562306a36Sopenharmony_ci				struct srp_event_struct *evt_struct,
75662306a36Sopenharmony_ci				struct srp_cmd *srp_cmd, struct device *dev)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	switch (cmd->sc_data_direction) {
75962306a36Sopenharmony_ci	case DMA_FROM_DEVICE:
76062306a36Sopenharmony_ci	case DMA_TO_DEVICE:
76162306a36Sopenharmony_ci		break;
76262306a36Sopenharmony_ci	case DMA_NONE:
76362306a36Sopenharmony_ci		return 1;
76462306a36Sopenharmony_ci	case DMA_BIDIRECTIONAL:
76562306a36Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
76662306a36Sopenharmony_ci			    "Can't map DMA_BIDIRECTIONAL to read/write\n");
76762306a36Sopenharmony_ci		return 0;
76862306a36Sopenharmony_ci	default:
76962306a36Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
77062306a36Sopenharmony_ci			    "Unknown data direction 0x%02x; can't map!\n",
77162306a36Sopenharmony_ci			    cmd->sc_data_direction);
77262306a36Sopenharmony_ci		return 0;
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return map_sg_data(cmd, evt_struct, srp_cmd, dev);
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci/**
77962306a36Sopenharmony_ci * purge_requests: Our virtual adapter just shut down.  purge any sent requests
78062306a36Sopenharmony_ci * @hostdata:    the adapter
78162306a36Sopenharmony_ci * @error_code:  error code to return as the 'result'
78262306a36Sopenharmony_ci */
78362306a36Sopenharmony_cistatic void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	struct srp_event_struct *evt;
78662306a36Sopenharmony_ci	unsigned long flags;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
78962306a36Sopenharmony_ci	while (!list_empty(&hostdata->sent)) {
79062306a36Sopenharmony_ci		evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
79162306a36Sopenharmony_ci		list_del(&evt->list);
79262306a36Sopenharmony_ci		del_timer(&evt->timer);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
79562306a36Sopenharmony_ci		if (evt->cmnd) {
79662306a36Sopenharmony_ci			evt->cmnd->result = (error_code << 16);
79762306a36Sopenharmony_ci			unmap_cmd_data(&evt->iu.srp.cmd, evt,
79862306a36Sopenharmony_ci				       evt->hostdata->dev);
79962306a36Sopenharmony_ci			if (evt->cmnd_done)
80062306a36Sopenharmony_ci				evt->cmnd_done(evt->cmnd);
80162306a36Sopenharmony_ci		} else if (evt->done && evt->crq.format != VIOSRP_MAD_FORMAT &&
80262306a36Sopenharmony_ci			   evt->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
80362306a36Sopenharmony_ci			evt->done(evt);
80462306a36Sopenharmony_ci		free_event_struct(&evt->hostdata->pool, evt);
80562306a36Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
80862306a36Sopenharmony_ci}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci/**
81162306a36Sopenharmony_ci * ibmvscsi_set_request_limit - Set the adapter request_limit in response to
81262306a36Sopenharmony_ci * an adapter failure, reset, or SRP Login. Done under host lock to prevent
81362306a36Sopenharmony_ci * race with SCSI command submission.
81462306a36Sopenharmony_ci * @hostdata:	adapter to adjust
81562306a36Sopenharmony_ci * @limit:	new request limit
81662306a36Sopenharmony_ci */
81762306a36Sopenharmony_cistatic void ibmvscsi_set_request_limit(struct ibmvscsi_host_data *hostdata, int limit)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	unsigned long flags;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
82262306a36Sopenharmony_ci	atomic_set(&hostdata->request_limit, limit);
82362306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/**
82762306a36Sopenharmony_ci * ibmvscsi_reset_host - Reset the connection to the server
82862306a36Sopenharmony_ci * @hostdata:	struct ibmvscsi_host_data to reset
82962306a36Sopenharmony_ci*/
83062306a36Sopenharmony_cistatic void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	scsi_block_requests(hostdata->host);
83362306a36Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata, 0);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	purge_requests(hostdata, DID_ERROR);
83662306a36Sopenharmony_ci	hostdata->action = IBMVSCSI_HOST_ACTION_RESET;
83762306a36Sopenharmony_ci	wake_up(&hostdata->work_wait_q);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/**
84162306a36Sopenharmony_ci * ibmvscsi_timeout - Internal command timeout handler
84262306a36Sopenharmony_ci * @t:	struct srp_event_struct that timed out
84362306a36Sopenharmony_ci *
84462306a36Sopenharmony_ci * Called when an internally generated command times out
84562306a36Sopenharmony_ci*/
84662306a36Sopenharmony_cistatic void ibmvscsi_timeout(struct timer_list *t)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	struct srp_event_struct *evt_struct = from_timer(evt_struct, t, timer);
84962306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
85262306a36Sopenharmony_ci		evt_struct->iu.srp.cmd.opcode);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	ibmvscsi_reset_host(hostdata);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/* ------------------------------------------------------------
85962306a36Sopenharmony_ci * Routines for sending and receiving SRPs
86062306a36Sopenharmony_ci */
86162306a36Sopenharmony_ci/**
86262306a36Sopenharmony_ci * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
86362306a36Sopenharmony_ci * @evt_struct:	evt_struct to be sent
86462306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
86562306a36Sopenharmony_ci * @timeout:	timeout in seconds - 0 means do not time command
86662306a36Sopenharmony_ci *
86762306a36Sopenharmony_ci * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
86862306a36Sopenharmony_ci * Note that this routine assumes that host_lock is held for synchronization
86962306a36Sopenharmony_ci*/
87062306a36Sopenharmony_cistatic int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
87162306a36Sopenharmony_ci				   struct ibmvscsi_host_data *hostdata,
87262306a36Sopenharmony_ci				   unsigned long timeout)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&evt_struct->crq;
87562306a36Sopenharmony_ci	int request_status = 0;
87662306a36Sopenharmony_ci	int rc;
87762306a36Sopenharmony_ci	int srp_req = 0;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* If we have exhausted our request limit, just fail this request,
88062306a36Sopenharmony_ci	 * unless it is for a reset or abort.
88162306a36Sopenharmony_ci	 * Note that there are rare cases involving driver generated requests
88262306a36Sopenharmony_ci	 * (such as task management requests) that the mid layer may think we
88362306a36Sopenharmony_ci	 * can handle more requests (can_queue) when we actually can't
88462306a36Sopenharmony_ci	 */
88562306a36Sopenharmony_ci	if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
88662306a36Sopenharmony_ci		srp_req = 1;
88762306a36Sopenharmony_ci		request_status =
88862306a36Sopenharmony_ci			atomic_dec_if_positive(&hostdata->request_limit);
88962306a36Sopenharmony_ci		/* If request limit was -1 when we started, it is now even
89062306a36Sopenharmony_ci		 * less than that
89162306a36Sopenharmony_ci		 */
89262306a36Sopenharmony_ci		if (request_status < -1)
89362306a36Sopenharmony_ci			goto send_error;
89462306a36Sopenharmony_ci		/* Otherwise, we may have run out of requests. */
89562306a36Sopenharmony_ci		/* If request limit was 0 when we started the adapter is in the
89662306a36Sopenharmony_ci		 * process of performing a login with the server adapter, or
89762306a36Sopenharmony_ci		 * we may have run out of requests.
89862306a36Sopenharmony_ci		 */
89962306a36Sopenharmony_ci		else if (request_status == -1 &&
90062306a36Sopenharmony_ci		         evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
90162306a36Sopenharmony_ci			goto send_busy;
90262306a36Sopenharmony_ci		/* Abort and reset calls should make it through.
90362306a36Sopenharmony_ci		 * Nothing except abort and reset should use the last two
90462306a36Sopenharmony_ci		 * slots unless we had two or less to begin with.
90562306a36Sopenharmony_ci		 */
90662306a36Sopenharmony_ci		else if (request_status < 2 &&
90762306a36Sopenharmony_ci		         evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
90862306a36Sopenharmony_ci			/* In the case that we have less than two requests
90962306a36Sopenharmony_ci			 * available, check the server limit as a combination
91062306a36Sopenharmony_ci			 * of the request limit and the number of requests
91162306a36Sopenharmony_ci			 * in-flight (the size of the send list).  If the
91262306a36Sopenharmony_ci			 * server limit is greater than 2, return busy so
91362306a36Sopenharmony_ci			 * that the last two are reserved for reset and abort.
91462306a36Sopenharmony_ci			 */
91562306a36Sopenharmony_ci			int server_limit = request_status;
91662306a36Sopenharmony_ci			struct srp_event_struct *tmp_evt;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci			list_for_each_entry(tmp_evt, &hostdata->sent, list) {
91962306a36Sopenharmony_ci				server_limit++;
92062306a36Sopenharmony_ci			}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci			if (server_limit > 2)
92362306a36Sopenharmony_ci				goto send_busy;
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	/* Copy the IU into the transfer area */
92862306a36Sopenharmony_ci	*evt_struct->xfer_iu = evt_struct->iu;
92962306a36Sopenharmony_ci	evt_struct->xfer_iu->srp.rsp.tag = (u64)evt_struct;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	/* Add this to the sent list.  We need to do this
93262306a36Sopenharmony_ci	 * before we actually send
93362306a36Sopenharmony_ci	 * in case it comes back REALLY fast
93462306a36Sopenharmony_ci	 */
93562306a36Sopenharmony_ci	list_add_tail(&evt_struct->list, &hostdata->sent);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	timer_setup(&evt_struct->timer, ibmvscsi_timeout, 0);
93862306a36Sopenharmony_ci	if (timeout) {
93962306a36Sopenharmony_ci		evt_struct->timer.expires = jiffies + (timeout * HZ);
94062306a36Sopenharmony_ci		add_timer(&evt_struct->timer);
94162306a36Sopenharmony_ci	}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	rc = ibmvscsi_send_crq(hostdata, be64_to_cpu(crq_as_u64[0]),
94462306a36Sopenharmony_ci			       be64_to_cpu(crq_as_u64[1]));
94562306a36Sopenharmony_ci	if (rc != 0) {
94662306a36Sopenharmony_ci		list_del(&evt_struct->list);
94762306a36Sopenharmony_ci		del_timer(&evt_struct->timer);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
95062306a36Sopenharmony_ci		 * Firmware will send a CRQ with a transport event (0xFF) to
95162306a36Sopenharmony_ci		 * tell this client what has happened to the transport.  This
95262306a36Sopenharmony_ci		 * will be handled in ibmvscsi_handle_crq()
95362306a36Sopenharmony_ci		 */
95462306a36Sopenharmony_ci		if (rc == H_CLOSED) {
95562306a36Sopenharmony_ci			dev_warn(hostdata->dev, "send warning. "
95662306a36Sopenharmony_ci			         "Receive queue closed, will retry.\n");
95762306a36Sopenharmony_ci			goto send_busy;
95862306a36Sopenharmony_ci		}
95962306a36Sopenharmony_ci		dev_err(hostdata->dev, "send error %d\n", rc);
96062306a36Sopenharmony_ci		if (srp_req)
96162306a36Sopenharmony_ci			atomic_inc(&hostdata->request_limit);
96262306a36Sopenharmony_ci		goto send_error;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	return 0;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci send_busy:
96862306a36Sopenharmony_ci	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	free_event_struct(&hostdata->pool, evt_struct);
97162306a36Sopenharmony_ci	if (srp_req && request_status != -1)
97262306a36Sopenharmony_ci		atomic_inc(&hostdata->request_limit);
97362306a36Sopenharmony_ci	return SCSI_MLQUEUE_HOST_BUSY;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci send_error:
97662306a36Sopenharmony_ci	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (evt_struct->cmnd != NULL) {
97962306a36Sopenharmony_ci		evt_struct->cmnd->result = DID_ERROR << 16;
98062306a36Sopenharmony_ci		evt_struct->cmnd_done(evt_struct->cmnd);
98162306a36Sopenharmony_ci	} else if (evt_struct->done)
98262306a36Sopenharmony_ci		evt_struct->done(evt_struct);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	free_event_struct(&hostdata->pool, evt_struct);
98562306a36Sopenharmony_ci	return 0;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci/**
98962306a36Sopenharmony_ci * handle_cmd_rsp: -  Handle responses from commands
99062306a36Sopenharmony_ci * @evt_struct:	srp_event_struct to be handled
99162306a36Sopenharmony_ci *
99262306a36Sopenharmony_ci * Used as a callback by when sending scsi cmds.
99362306a36Sopenharmony_ci * Gets called by ibmvscsi_handle_crq()
99462306a36Sopenharmony_ci*/
99562306a36Sopenharmony_cistatic void handle_cmd_rsp(struct srp_event_struct *evt_struct)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
99862306a36Sopenharmony_ci	struct scsi_cmnd *cmnd = evt_struct->cmnd;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	if (unlikely(rsp->opcode != SRP_RSP)) {
100162306a36Sopenharmony_ci		if (printk_ratelimit())
100262306a36Sopenharmony_ci			dev_warn(evt_struct->hostdata->dev,
100362306a36Sopenharmony_ci				 "bad SRP RSP type %#02x\n", rsp->opcode);
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (cmnd) {
100762306a36Sopenharmony_ci		cmnd->result |= rsp->status;
100862306a36Sopenharmony_ci		if (scsi_status_is_check_condition(cmnd->result))
100962306a36Sopenharmony_ci			memcpy(cmnd->sense_buffer,
101062306a36Sopenharmony_ci			       rsp->data,
101162306a36Sopenharmony_ci			       be32_to_cpu(rsp->sense_data_len));
101262306a36Sopenharmony_ci		unmap_cmd_data(&evt_struct->iu.srp.cmd,
101362306a36Sopenharmony_ci			       evt_struct,
101462306a36Sopenharmony_ci			       evt_struct->hostdata->dev);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci		if (rsp->flags & SRP_RSP_FLAG_DOOVER)
101762306a36Sopenharmony_ci			scsi_set_resid(cmnd,
101862306a36Sopenharmony_ci				       be32_to_cpu(rsp->data_out_res_cnt));
101962306a36Sopenharmony_ci		else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
102062306a36Sopenharmony_ci			scsi_set_resid(cmnd, be32_to_cpu(rsp->data_in_res_cnt));
102162306a36Sopenharmony_ci	}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (evt_struct->cmnd_done)
102462306a36Sopenharmony_ci		evt_struct->cmnd_done(cmnd);
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci/**
102862306a36Sopenharmony_ci * lun_from_dev: - Returns the lun of the scsi device
102962306a36Sopenharmony_ci * @dev:	struct scsi_device
103062306a36Sopenharmony_ci *
103162306a36Sopenharmony_ci*/
103262306a36Sopenharmony_cistatic inline u16 lun_from_dev(struct scsi_device *dev)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun;
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci/**
103862306a36Sopenharmony_ci * ibmvscsi_queuecommand_lck() - The queuecommand function of the scsi template
103962306a36Sopenharmony_ci * @cmnd:	struct scsi_cmnd to be executed
104062306a36Sopenharmony_ci * @done:	Callback function to be called when cmd is completed
104162306a36Sopenharmony_ci*/
104262306a36Sopenharmony_cistatic int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	void (*done)(struct scsi_cmnd *) = scsi_done;
104562306a36Sopenharmony_ci	struct srp_cmd *srp_cmd;
104662306a36Sopenharmony_ci	struct srp_event_struct *evt_struct;
104762306a36Sopenharmony_ci	struct srp_indirect_buf *indirect;
104862306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host);
104962306a36Sopenharmony_ci	u16 lun = lun_from_dev(cmnd->device);
105062306a36Sopenharmony_ci	u8 out_fmt, in_fmt;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	cmnd->result = (DID_OK << 16);
105362306a36Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
105462306a36Sopenharmony_ci	if (!evt_struct)
105562306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	/* Set up the actual SRP IU */
105862306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(evt_struct->iu.srp) != SRP_MAX_IU_LEN);
105962306a36Sopenharmony_ci	memset(&evt_struct->iu.srp, 0x00, sizeof(evt_struct->iu.srp));
106062306a36Sopenharmony_ci	srp_cmd = &evt_struct->iu.srp.cmd;
106162306a36Sopenharmony_ci	srp_cmd->opcode = SRP_CMD;
106262306a36Sopenharmony_ci	memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
106362306a36Sopenharmony_ci	int_to_scsilun(lun, &srp_cmd->lun);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
106662306a36Sopenharmony_ci		if (!firmware_has_feature(FW_FEATURE_CMO))
106762306a36Sopenharmony_ci			sdev_printk(KERN_ERR, cmnd->device,
106862306a36Sopenharmony_ci			            "couldn't convert cmd to srp_cmd\n");
106962306a36Sopenharmony_ci		free_event_struct(&hostdata->pool, evt_struct);
107062306a36Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	init_event_struct(evt_struct,
107462306a36Sopenharmony_ci			  handle_cmd_rsp,
107562306a36Sopenharmony_ci			  VIOSRP_SRP_FORMAT,
107662306a36Sopenharmony_ci			  scsi_cmd_to_rq(cmnd)->timeout / HZ);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	evt_struct->cmnd = cmnd;
107962306a36Sopenharmony_ci	evt_struct->cmnd_done = done;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	/* Fix up dma address of the buffer itself */
108262306a36Sopenharmony_ci	indirect = (struct srp_indirect_buf *) srp_cmd->add_data;
108362306a36Sopenharmony_ci	out_fmt = srp_cmd->buf_fmt >> 4;
108462306a36Sopenharmony_ci	in_fmt = srp_cmd->buf_fmt & ((1U << 4) - 1);
108562306a36Sopenharmony_ci	if ((in_fmt == SRP_DATA_DESC_INDIRECT ||
108662306a36Sopenharmony_ci	     out_fmt == SRP_DATA_DESC_INDIRECT) &&
108762306a36Sopenharmony_ci	    indirect->table_desc.va == 0) {
108862306a36Sopenharmony_ci		indirect->table_desc.va =
108962306a36Sopenharmony_ci			cpu_to_be64(be64_to_cpu(evt_struct->crq.IU_data_ptr) +
109062306a36Sopenharmony_ci			offsetof(struct srp_cmd, add_data) +
109162306a36Sopenharmony_ci			offsetof(struct srp_indirect_buf, desc_list));
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_cistatic DEF_SCSI_QCMD(ibmvscsi_queuecommand)
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci/* ------------------------------------------------------------
110062306a36Sopenharmony_ci * Routines for driver initialization
110162306a36Sopenharmony_ci */
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci/**
110462306a36Sopenharmony_ci * map_persist_bufs: - Pre-map persistent data for adapter logins
110562306a36Sopenharmony_ci * @hostdata:   ibmvscsi_host_data of host
110662306a36Sopenharmony_ci *
110762306a36Sopenharmony_ci * Map the capabilities and adapter info DMA buffers to avoid runtime failures.
110862306a36Sopenharmony_ci * Return 1 on error, 0 on success.
110962306a36Sopenharmony_ci */
111062306a36Sopenharmony_cistatic int map_persist_bufs(struct ibmvscsi_host_data *hostdata)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps,
111462306a36Sopenharmony_ci					     sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) {
111762306a36Sopenharmony_ci		dev_err(hostdata->dev, "Unable to map capabilities buffer!\n");
111862306a36Sopenharmony_ci		return 1;
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	hostdata->adapter_info_addr = dma_map_single(hostdata->dev,
112262306a36Sopenharmony_ci						     &hostdata->madapter_info,
112362306a36Sopenharmony_ci						     sizeof(hostdata->madapter_info),
112462306a36Sopenharmony_ci						     DMA_BIDIRECTIONAL);
112562306a36Sopenharmony_ci	if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) {
112662306a36Sopenharmony_ci		dev_err(hostdata->dev, "Unable to map adapter info buffer!\n");
112762306a36Sopenharmony_ci		dma_unmap_single(hostdata->dev, hostdata->caps_addr,
112862306a36Sopenharmony_ci				 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
112962306a36Sopenharmony_ci		return 1;
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	return 0;
113362306a36Sopenharmony_ci}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci/**
113662306a36Sopenharmony_ci * unmap_persist_bufs: - Unmap persistent data needed for adapter logins
113762306a36Sopenharmony_ci * @hostdata:   ibmvscsi_host_data of host
113862306a36Sopenharmony_ci *
113962306a36Sopenharmony_ci * Unmap the capabilities and adapter info DMA buffers
114062306a36Sopenharmony_ci */
114162306a36Sopenharmony_cistatic void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	dma_unmap_single(hostdata->dev, hostdata->caps_addr,
114462306a36Sopenharmony_ci			 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr,
114762306a36Sopenharmony_ci			 sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL);
114862306a36Sopenharmony_ci}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci/**
115162306a36Sopenharmony_ci * login_rsp: - Handle response to SRP login request
115262306a36Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
115362306a36Sopenharmony_ci *
115462306a36Sopenharmony_ci * Used as a "done" callback by when sending srp_login. Gets called
115562306a36Sopenharmony_ci * by ibmvscsi_handle_crq()
115662306a36Sopenharmony_ci*/
115762306a36Sopenharmony_cistatic void login_rsp(struct srp_event_struct *evt_struct)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
116062306a36Sopenharmony_ci	switch (evt_struct->xfer_iu->srp.login_rsp.opcode) {
116162306a36Sopenharmony_ci	case SRP_LOGIN_RSP:	/* it worked! */
116262306a36Sopenharmony_ci		break;
116362306a36Sopenharmony_ci	case SRP_LOGIN_REJ:	/* refused! */
116462306a36Sopenharmony_ci		dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
116562306a36Sopenharmony_ci			 evt_struct->xfer_iu->srp.login_rej.reason);
116662306a36Sopenharmony_ci		/* Login failed.  */
116762306a36Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, -1);
116862306a36Sopenharmony_ci		return;
116962306a36Sopenharmony_ci	default:
117062306a36Sopenharmony_ci		dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
117162306a36Sopenharmony_ci			evt_struct->xfer_iu->srp.login_rsp.opcode);
117262306a36Sopenharmony_ci		/* Login failed.  */
117362306a36Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, -1);
117462306a36Sopenharmony_ci		return;
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
117862306a36Sopenharmony_ci	hostdata->client_migrated = 0;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Now we know what the real request-limit is.
118162306a36Sopenharmony_ci	 * This value is set rather than added to request_limit because
118262306a36Sopenharmony_ci	 * request_limit could have been set to -1 by this client.
118362306a36Sopenharmony_ci	 */
118462306a36Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata,
118562306a36Sopenharmony_ci		   be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	/* If we had any pending I/Os, kick them */
118862306a36Sopenharmony_ci	hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK;
118962306a36Sopenharmony_ci	wake_up(&hostdata->work_wait_q);
119062306a36Sopenharmony_ci}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci/**
119362306a36Sopenharmony_ci * send_srp_login: - Sends the srp login
119462306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
119562306a36Sopenharmony_ci *
119662306a36Sopenharmony_ci * Returns zero if successful.
119762306a36Sopenharmony_ci*/
119862306a36Sopenharmony_cistatic int send_srp_login(struct ibmvscsi_host_data *hostdata)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	int rc;
120162306a36Sopenharmony_ci	unsigned long flags;
120262306a36Sopenharmony_ci	struct srp_login_req *login;
120362306a36Sopenharmony_ci	struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	BUG_ON(!evt_struct);
120662306a36Sopenharmony_ci	init_event_struct(evt_struct, login_rsp,
120762306a36Sopenharmony_ci			  VIOSRP_SRP_FORMAT, login_timeout);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	login = &evt_struct->iu.srp.login_req;
121062306a36Sopenharmony_ci	memset(login, 0, sizeof(*login));
121162306a36Sopenharmony_ci	login->opcode = SRP_LOGIN_REQ;
121262306a36Sopenharmony_ci	login->req_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
121362306a36Sopenharmony_ci	login->req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
121462306a36Sopenharmony_ci					 SRP_BUF_FORMAT_INDIRECT);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	/* Start out with a request limit of 0, since this is negotiated in
121762306a36Sopenharmony_ci	 * the login request we are just sending and login requests always
121862306a36Sopenharmony_ci	 * get sent by the driver regardless of request_limit.
121962306a36Sopenharmony_ci	 */
122062306a36Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata, 0);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
122362306a36Sopenharmony_ci	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
122462306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
122562306a36Sopenharmony_ci	dev_info(hostdata->dev, "sent SRP login\n");
122662306a36Sopenharmony_ci	return rc;
122762306a36Sopenharmony_ci};
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci/**
123062306a36Sopenharmony_ci * capabilities_rsp: - Handle response to MAD adapter capabilities request
123162306a36Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
123262306a36Sopenharmony_ci *
123362306a36Sopenharmony_ci * Used as a "done" callback by when sending adapter_info.
123462306a36Sopenharmony_ci */
123562306a36Sopenharmony_cistatic void capabilities_rsp(struct srp_event_struct *evt_struct)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (evt_struct->xfer_iu->mad.capabilities.common.status) {
124062306a36Sopenharmony_ci		dev_err(hostdata->dev, "error 0x%X getting capabilities info\n",
124162306a36Sopenharmony_ci			evt_struct->xfer_iu->mad.capabilities.common.status);
124262306a36Sopenharmony_ci	} else {
124362306a36Sopenharmony_ci		if (hostdata->caps.migration.common.server_support !=
124462306a36Sopenharmony_ci		    cpu_to_be16(SERVER_SUPPORTS_CAP))
124562306a36Sopenharmony_ci			dev_info(hostdata->dev, "Partition migration not supported\n");
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci		if (client_reserve) {
124862306a36Sopenharmony_ci			if (hostdata->caps.reserve.common.server_support ==
124962306a36Sopenharmony_ci			    cpu_to_be16(SERVER_SUPPORTS_CAP))
125062306a36Sopenharmony_ci				dev_info(hostdata->dev, "Client reserve enabled\n");
125162306a36Sopenharmony_ci			else
125262306a36Sopenharmony_ci				dev_info(hostdata->dev, "Client reserve not supported\n");
125362306a36Sopenharmony_ci		}
125462306a36Sopenharmony_ci	}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	send_srp_login(hostdata);
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci/**
126062306a36Sopenharmony_ci * send_mad_capabilities: - Sends the mad capabilities request
126162306a36Sopenharmony_ci *      and stores the result so it can be retrieved with
126262306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
126362306a36Sopenharmony_ci */
126462306a36Sopenharmony_cistatic void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
126562306a36Sopenharmony_ci{
126662306a36Sopenharmony_ci	struct viosrp_capabilities *req;
126762306a36Sopenharmony_ci	struct srp_event_struct *evt_struct;
126862306a36Sopenharmony_ci	unsigned long flags;
126962306a36Sopenharmony_ci	struct device_node *of_node = hostdata->dev->of_node;
127062306a36Sopenharmony_ci	const char *location;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
127362306a36Sopenharmony_ci	BUG_ON(!evt_struct);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	init_event_struct(evt_struct, capabilities_rsp,
127662306a36Sopenharmony_ci			  VIOSRP_MAD_FORMAT, info_timeout);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	req = &evt_struct->iu.mad.capabilities;
127962306a36Sopenharmony_ci	memset(req, 0, sizeof(*req));
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	hostdata->caps.flags = cpu_to_be32(CAP_LIST_SUPPORTED);
128262306a36Sopenharmony_ci	if (hostdata->client_migrated)
128362306a36Sopenharmony_ci		hostdata->caps.flags |= cpu_to_be32(CLIENT_MIGRATED);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	strscpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev),
128662306a36Sopenharmony_ci		sizeof(hostdata->caps.name));
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	location = of_get_property(of_node, "ibm,loc-code", NULL);
128962306a36Sopenharmony_ci	location = location ? location : dev_name(hostdata->dev);
129062306a36Sopenharmony_ci	strscpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc));
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	req->common.type = cpu_to_be32(VIOSRP_CAPABILITIES_TYPE);
129362306a36Sopenharmony_ci	req->buffer = cpu_to_be64(hostdata->caps_addr);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	hostdata->caps.migration.common.cap_type =
129662306a36Sopenharmony_ci				cpu_to_be32(MIGRATION_CAPABILITIES);
129762306a36Sopenharmony_ci	hostdata->caps.migration.common.length =
129862306a36Sopenharmony_ci				cpu_to_be16(sizeof(hostdata->caps.migration));
129962306a36Sopenharmony_ci	hostdata->caps.migration.common.server_support =
130062306a36Sopenharmony_ci				cpu_to_be16(SERVER_SUPPORTS_CAP);
130162306a36Sopenharmony_ci	hostdata->caps.migration.ecl = cpu_to_be32(1);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (client_reserve) {
130462306a36Sopenharmony_ci		hostdata->caps.reserve.common.cap_type =
130562306a36Sopenharmony_ci					cpu_to_be32(RESERVATION_CAPABILITIES);
130662306a36Sopenharmony_ci		hostdata->caps.reserve.common.length =
130762306a36Sopenharmony_ci				cpu_to_be16(sizeof(hostdata->caps.reserve));
130862306a36Sopenharmony_ci		hostdata->caps.reserve.common.server_support =
130962306a36Sopenharmony_ci				cpu_to_be16(SERVER_SUPPORTS_CAP);
131062306a36Sopenharmony_ci		hostdata->caps.reserve.type =
131162306a36Sopenharmony_ci				cpu_to_be32(CLIENT_RESERVE_SCSI_2);
131262306a36Sopenharmony_ci		req->common.length =
131362306a36Sopenharmony_ci				cpu_to_be16(sizeof(hostdata->caps));
131462306a36Sopenharmony_ci	} else
131562306a36Sopenharmony_ci		req->common.length = cpu_to_be16(sizeof(hostdata->caps) -
131662306a36Sopenharmony_ci						sizeof(hostdata->caps.reserve));
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
131962306a36Sopenharmony_ci	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
132062306a36Sopenharmony_ci		dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n");
132162306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
132262306a36Sopenharmony_ci};
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci/**
132562306a36Sopenharmony_ci * fast_fail_rsp: - Handle response to MAD enable fast fail
132662306a36Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
132762306a36Sopenharmony_ci *
132862306a36Sopenharmony_ci * Used as a "done" callback by when sending enable fast fail. Gets called
132962306a36Sopenharmony_ci * by ibmvscsi_handle_crq()
133062306a36Sopenharmony_ci */
133162306a36Sopenharmony_cistatic void fast_fail_rsp(struct srp_event_struct *evt_struct)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
133462306a36Sopenharmony_ci	u16 status = be16_to_cpu(evt_struct->xfer_iu->mad.fast_fail.common.status);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (status == VIOSRP_MAD_NOT_SUPPORTED)
133762306a36Sopenharmony_ci		dev_err(hostdata->dev, "fast_fail not supported in server\n");
133862306a36Sopenharmony_ci	else if (status == VIOSRP_MAD_FAILED)
133962306a36Sopenharmony_ci		dev_err(hostdata->dev, "fast_fail request failed\n");
134062306a36Sopenharmony_ci	else if (status != VIOSRP_MAD_SUCCESS)
134162306a36Sopenharmony_ci		dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	send_mad_capabilities(hostdata);
134462306a36Sopenharmony_ci}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci/**
134762306a36Sopenharmony_ci * enable_fast_fail() - Start host initialization
134862306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
134962306a36Sopenharmony_ci *
135062306a36Sopenharmony_ci * Returns zero if successful.
135162306a36Sopenharmony_ci */
135262306a36Sopenharmony_cistatic int enable_fast_fail(struct ibmvscsi_host_data *hostdata)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	int rc;
135562306a36Sopenharmony_ci	unsigned long flags;
135662306a36Sopenharmony_ci	struct viosrp_fast_fail *fast_fail_mad;
135762306a36Sopenharmony_ci	struct srp_event_struct *evt_struct;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	if (!fast_fail) {
136062306a36Sopenharmony_ci		send_mad_capabilities(hostdata);
136162306a36Sopenharmony_ci		return 0;
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
136562306a36Sopenharmony_ci	BUG_ON(!evt_struct);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	fast_fail_mad = &evt_struct->iu.mad.fast_fail;
137062306a36Sopenharmony_ci	memset(fast_fail_mad, 0, sizeof(*fast_fail_mad));
137162306a36Sopenharmony_ci	fast_fail_mad->common.type = cpu_to_be32(VIOSRP_ENABLE_FAST_FAIL);
137262306a36Sopenharmony_ci	fast_fail_mad->common.length = cpu_to_be16(sizeof(*fast_fail_mad));
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
137562306a36Sopenharmony_ci	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
137662306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
137762306a36Sopenharmony_ci	return rc;
137862306a36Sopenharmony_ci}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci/**
138162306a36Sopenharmony_ci * adapter_info_rsp: - Handle response to MAD adapter info request
138262306a36Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
138362306a36Sopenharmony_ci *
138462306a36Sopenharmony_ci * Used as a "done" callback by when sending adapter_info. Gets called
138562306a36Sopenharmony_ci * by ibmvscsi_handle_crq()
138662306a36Sopenharmony_ci*/
138762306a36Sopenharmony_cistatic void adapter_info_rsp(struct srp_event_struct *evt_struct)
138862306a36Sopenharmony_ci{
138962306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
139262306a36Sopenharmony_ci		dev_err(hostdata->dev, "error %d getting adapter info\n",
139362306a36Sopenharmony_ci			evt_struct->xfer_iu->mad.adapter_info.common.status);
139462306a36Sopenharmony_ci	} else {
139562306a36Sopenharmony_ci		dev_info(hostdata->dev, "host srp version: %s, "
139662306a36Sopenharmony_ci			 "host partition %s (%d), OS %d, max io %u\n",
139762306a36Sopenharmony_ci			 hostdata->madapter_info.srp_version,
139862306a36Sopenharmony_ci			 hostdata->madapter_info.partition_name,
139962306a36Sopenharmony_ci			 be32_to_cpu(hostdata->madapter_info.partition_number),
140062306a36Sopenharmony_ci			 be32_to_cpu(hostdata->madapter_info.os_type),
140162306a36Sopenharmony_ci			 be32_to_cpu(hostdata->madapter_info.port_max_txu[0]));
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci		if (hostdata->madapter_info.port_max_txu[0])
140462306a36Sopenharmony_ci			hostdata->host->max_sectors =
140562306a36Sopenharmony_ci				be32_to_cpu(hostdata->madapter_info.port_max_txu[0]) >> 9;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci		if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX &&
140862306a36Sopenharmony_ci		    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
140962306a36Sopenharmony_ci			dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
141062306a36Sopenharmony_ci				hostdata->madapter_info.srp_version);
141162306a36Sopenharmony_ci			dev_err(hostdata->dev, "limiting scatterlists to %d\n",
141262306a36Sopenharmony_ci				MAX_INDIRECT_BUFS);
141362306a36Sopenharmony_ci			hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
141462306a36Sopenharmony_ci		}
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci		if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX) {
141762306a36Sopenharmony_ci			enable_fast_fail(hostdata);
141862306a36Sopenharmony_ci			return;
141962306a36Sopenharmony_ci		}
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	send_srp_login(hostdata);
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci/**
142662306a36Sopenharmony_ci * send_mad_adapter_info: - Sends the mad adapter info request
142762306a36Sopenharmony_ci *      and stores the result so it can be retrieved with
142862306a36Sopenharmony_ci *      sysfs.  We COULD consider causing a failure if the
142962306a36Sopenharmony_ci *      returned SRP version doesn't match ours.
143062306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
143162306a36Sopenharmony_ci *
143262306a36Sopenharmony_ci * Returns zero if successful.
143362306a36Sopenharmony_ci*/
143462306a36Sopenharmony_cistatic void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
143562306a36Sopenharmony_ci{
143662306a36Sopenharmony_ci	struct viosrp_adapter_info *req;
143762306a36Sopenharmony_ci	struct srp_event_struct *evt_struct;
143862306a36Sopenharmony_ci	unsigned long flags;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
144162306a36Sopenharmony_ci	BUG_ON(!evt_struct);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	init_event_struct(evt_struct,
144462306a36Sopenharmony_ci			  adapter_info_rsp,
144562306a36Sopenharmony_ci			  VIOSRP_MAD_FORMAT,
144662306a36Sopenharmony_ci			  info_timeout);
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	req = &evt_struct->iu.mad.adapter_info;
144962306a36Sopenharmony_ci	memset(req, 0x00, sizeof(*req));
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	req->common.type = cpu_to_be32(VIOSRP_ADAPTER_INFO_TYPE);
145262306a36Sopenharmony_ci	req->common.length = cpu_to_be16(sizeof(hostdata->madapter_info));
145362306a36Sopenharmony_ci	req->buffer = cpu_to_be64(hostdata->adapter_info_addr);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
145662306a36Sopenharmony_ci	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
145762306a36Sopenharmony_ci		dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
145862306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
145962306a36Sopenharmony_ci};
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci/*
146262306a36Sopenharmony_ci * init_adapter() - Start virtual adapter initialization sequence
146362306a36Sopenharmony_ci */
146462306a36Sopenharmony_cistatic void init_adapter(struct ibmvscsi_host_data *hostdata)
146562306a36Sopenharmony_ci{
146662306a36Sopenharmony_ci	send_mad_adapter_info(hostdata);
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci/*
147062306a36Sopenharmony_ci * sync_completion: Signal that a synchronous command has completed
147162306a36Sopenharmony_ci * Note that after returning from this call, the evt_struct is freed.
147262306a36Sopenharmony_ci * the caller waiting on this completion shouldn't touch the evt_struct
147362306a36Sopenharmony_ci * again.
147462306a36Sopenharmony_ci */
147562306a36Sopenharmony_cistatic void sync_completion(struct srp_event_struct *evt_struct)
147662306a36Sopenharmony_ci{
147762306a36Sopenharmony_ci	/* copy the response back */
147862306a36Sopenharmony_ci	if (evt_struct->sync_srp)
147962306a36Sopenharmony_ci		*evt_struct->sync_srp = *evt_struct->xfer_iu;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	complete(&evt_struct->comp);
148262306a36Sopenharmony_ci}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci/*
148562306a36Sopenharmony_ci * ibmvscsi_eh_abort_handler: Abort a command...from scsi host template
148662306a36Sopenharmony_ci * send this over to the server and wait synchronously for the response
148762306a36Sopenharmony_ci */
148862306a36Sopenharmony_cistatic int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
149162306a36Sopenharmony_ci	struct srp_tsk_mgmt *tsk_mgmt;
149262306a36Sopenharmony_ci	struct srp_event_struct *evt;
149362306a36Sopenharmony_ci	struct srp_event_struct *tmp_evt, *found_evt;
149462306a36Sopenharmony_ci	union viosrp_iu srp_rsp;
149562306a36Sopenharmony_ci	int rsp_rc;
149662306a36Sopenharmony_ci	unsigned long flags;
149762306a36Sopenharmony_ci	u16 lun = lun_from_dev(cmd->device);
149862306a36Sopenharmony_ci	unsigned long wait_switch = 0;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	/* First, find this command in our sent list so we can figure
150162306a36Sopenharmony_ci	 * out the correct tag
150262306a36Sopenharmony_ci	 */
150362306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
150462306a36Sopenharmony_ci	wait_switch = jiffies + (init_timeout * HZ);
150562306a36Sopenharmony_ci	do {
150662306a36Sopenharmony_ci		found_evt = NULL;
150762306a36Sopenharmony_ci		list_for_each_entry(tmp_evt, &hostdata->sent, list) {
150862306a36Sopenharmony_ci			if (tmp_evt->cmnd == cmd) {
150962306a36Sopenharmony_ci				found_evt = tmp_evt;
151062306a36Sopenharmony_ci				break;
151162306a36Sopenharmony_ci			}
151262306a36Sopenharmony_ci		}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		if (!found_evt) {
151562306a36Sopenharmony_ci			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
151662306a36Sopenharmony_ci			return SUCCESS;
151762306a36Sopenharmony_ci		}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci		evt = get_event_struct(&hostdata->pool);
152062306a36Sopenharmony_ci		if (evt == NULL) {
152162306a36Sopenharmony_ci			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
152262306a36Sopenharmony_ci			sdev_printk(KERN_ERR, cmd->device,
152362306a36Sopenharmony_ci				"failed to allocate abort event\n");
152462306a36Sopenharmony_ci			return FAILED;
152562306a36Sopenharmony_ci		}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci		init_event_struct(evt,
152862306a36Sopenharmony_ci				  sync_completion,
152962306a36Sopenharmony_ci				  VIOSRP_SRP_FORMAT,
153062306a36Sopenharmony_ci				  abort_timeout);
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci		/* Set up an abort SRP command */
153562306a36Sopenharmony_ci		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
153662306a36Sopenharmony_ci		tsk_mgmt->opcode = SRP_TSK_MGMT;
153762306a36Sopenharmony_ci		int_to_scsilun(lun, &tsk_mgmt->lun);
153862306a36Sopenharmony_ci		tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
153962306a36Sopenharmony_ci		tsk_mgmt->task_tag = (u64) found_evt;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci		evt->sync_srp = &srp_rsp;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci		init_completion(&evt->comp);
154462306a36Sopenharmony_ci		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
154762306a36Sopenharmony_ci			break;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
155062306a36Sopenharmony_ci		msleep(10);
155162306a36Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
155262306a36Sopenharmony_ci	} while (time_before(jiffies, wait_switch));
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	if (rsp_rc != 0) {
155762306a36Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
155862306a36Sopenharmony_ci			    "failed to send abort() event. rc=%d\n", rsp_rc);
155962306a36Sopenharmony_ci		return FAILED;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	sdev_printk(KERN_INFO, cmd->device,
156362306a36Sopenharmony_ci                    "aborting command. lun 0x%llx, tag 0x%llx\n",
156462306a36Sopenharmony_ci		    (((u64) lun) << 48), (u64) found_evt);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	wait_for_completion(&evt->comp);
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	/* make sure we got a good response */
156962306a36Sopenharmony_ci	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
157062306a36Sopenharmony_ci		if (printk_ratelimit())
157162306a36Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n",
157262306a36Sopenharmony_ci				    srp_rsp.srp.rsp.opcode);
157362306a36Sopenharmony_ci		return FAILED;
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
157762306a36Sopenharmony_ci		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
157862306a36Sopenharmony_ci	else
157962306a36Sopenharmony_ci		rsp_rc = srp_rsp.srp.rsp.status;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	if (rsp_rc) {
158262306a36Sopenharmony_ci		if (printk_ratelimit())
158362306a36Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device,
158462306a36Sopenharmony_ci				    "abort code %d for task tag 0x%llx\n",
158562306a36Sopenharmony_ci				    rsp_rc, tsk_mgmt->task_tag);
158662306a36Sopenharmony_ci		return FAILED;
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	/* Because we dropped the spinlock above, it's possible
159062306a36Sopenharmony_ci	 * The event is no longer in our list.  Make sure it didn't
159162306a36Sopenharmony_ci	 * complete while we were aborting
159262306a36Sopenharmony_ci	 */
159362306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
159462306a36Sopenharmony_ci	found_evt = NULL;
159562306a36Sopenharmony_ci	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
159662306a36Sopenharmony_ci		if (tmp_evt->cmnd == cmd) {
159762306a36Sopenharmony_ci			found_evt = tmp_evt;
159862306a36Sopenharmony_ci			break;
159962306a36Sopenharmony_ci		}
160062306a36Sopenharmony_ci	}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	if (found_evt == NULL) {
160362306a36Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
160462306a36Sopenharmony_ci		sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%llx completed\n",
160562306a36Sopenharmony_ci			    tsk_mgmt->task_tag);
160662306a36Sopenharmony_ci		return SUCCESS;
160762306a36Sopenharmony_ci	}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%llx\n",
161062306a36Sopenharmony_ci		    tsk_mgmt->task_tag);
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	cmd->result = (DID_ABORT << 16);
161362306a36Sopenharmony_ci	list_del(&found_evt->list);
161462306a36Sopenharmony_ci	unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt,
161562306a36Sopenharmony_ci		       found_evt->hostdata->dev);
161662306a36Sopenharmony_ci	free_event_struct(&found_evt->hostdata->pool, found_evt);
161762306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
161862306a36Sopenharmony_ci	atomic_inc(&hostdata->request_limit);
161962306a36Sopenharmony_ci	return SUCCESS;
162062306a36Sopenharmony_ci}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci/*
162362306a36Sopenharmony_ci * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host
162462306a36Sopenharmony_ci * template send this over to the server and wait synchronously for the
162562306a36Sopenharmony_ci * response
162662306a36Sopenharmony_ci */
162762306a36Sopenharmony_cistatic int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
162862306a36Sopenharmony_ci{
162962306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
163062306a36Sopenharmony_ci	struct srp_tsk_mgmt *tsk_mgmt;
163162306a36Sopenharmony_ci	struct srp_event_struct *evt;
163262306a36Sopenharmony_ci	struct srp_event_struct *tmp_evt, *pos;
163362306a36Sopenharmony_ci	union viosrp_iu srp_rsp;
163462306a36Sopenharmony_ci	int rsp_rc;
163562306a36Sopenharmony_ci	unsigned long flags;
163662306a36Sopenharmony_ci	u16 lun = lun_from_dev(cmd->device);
163762306a36Sopenharmony_ci	unsigned long wait_switch = 0;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
164062306a36Sopenharmony_ci	wait_switch = jiffies + (init_timeout * HZ);
164162306a36Sopenharmony_ci	do {
164262306a36Sopenharmony_ci		evt = get_event_struct(&hostdata->pool);
164362306a36Sopenharmony_ci		if (evt == NULL) {
164462306a36Sopenharmony_ci			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
164562306a36Sopenharmony_ci			sdev_printk(KERN_ERR, cmd->device,
164662306a36Sopenharmony_ci				"failed to allocate reset event\n");
164762306a36Sopenharmony_ci			return FAILED;
164862306a36Sopenharmony_ci		}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci		init_event_struct(evt,
165162306a36Sopenharmony_ci				  sync_completion,
165262306a36Sopenharmony_ci				  VIOSRP_SRP_FORMAT,
165362306a36Sopenharmony_ci				  reset_timeout);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci		/* Set up a lun reset SRP command */
165862306a36Sopenharmony_ci		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
165962306a36Sopenharmony_ci		tsk_mgmt->opcode = SRP_TSK_MGMT;
166062306a36Sopenharmony_ci		int_to_scsilun(lun, &tsk_mgmt->lun);
166162306a36Sopenharmony_ci		tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci		evt->sync_srp = &srp_rsp;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci		init_completion(&evt->comp);
166662306a36Sopenharmony_ci		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
166962306a36Sopenharmony_ci			break;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
167262306a36Sopenharmony_ci		msleep(10);
167362306a36Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
167462306a36Sopenharmony_ci	} while (time_before(jiffies, wait_switch));
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	if (rsp_rc != 0) {
167962306a36Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
168062306a36Sopenharmony_ci			    "failed to send reset event. rc=%d\n", rsp_rc);
168162306a36Sopenharmony_ci		return FAILED;
168262306a36Sopenharmony_ci	}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%llx\n",
168562306a36Sopenharmony_ci		    (((u64) lun) << 48));
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	wait_for_completion(&evt->comp);
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	/* make sure we got a good response */
169062306a36Sopenharmony_ci	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
169162306a36Sopenharmony_ci		if (printk_ratelimit())
169262306a36Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n",
169362306a36Sopenharmony_ci				    srp_rsp.srp.rsp.opcode);
169462306a36Sopenharmony_ci		return FAILED;
169562306a36Sopenharmony_ci	}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
169862306a36Sopenharmony_ci		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
169962306a36Sopenharmony_ci	else
170062306a36Sopenharmony_ci		rsp_rc = srp_rsp.srp.rsp.status;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	if (rsp_rc) {
170362306a36Sopenharmony_ci		if (printk_ratelimit())
170462306a36Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device,
170562306a36Sopenharmony_ci				    "reset code %d for task tag 0x%llx\n",
170662306a36Sopenharmony_ci				    rsp_rc, tsk_mgmt->task_tag);
170762306a36Sopenharmony_ci		return FAILED;
170862306a36Sopenharmony_ci	}
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	/* We need to find all commands for this LUN that have not yet been
171162306a36Sopenharmony_ci	 * responded to, and fail them with DID_RESET
171262306a36Sopenharmony_ci	 */
171362306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
171462306a36Sopenharmony_ci	list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
171562306a36Sopenharmony_ci		if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) {
171662306a36Sopenharmony_ci			if (tmp_evt->cmnd)
171762306a36Sopenharmony_ci				tmp_evt->cmnd->result = (DID_RESET << 16);
171862306a36Sopenharmony_ci			list_del(&tmp_evt->list);
171962306a36Sopenharmony_ci			unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt,
172062306a36Sopenharmony_ci				       tmp_evt->hostdata->dev);
172162306a36Sopenharmony_ci			free_event_struct(&tmp_evt->hostdata->pool,
172262306a36Sopenharmony_ci						   tmp_evt);
172362306a36Sopenharmony_ci			atomic_inc(&hostdata->request_limit);
172462306a36Sopenharmony_ci			if (tmp_evt->cmnd_done)
172562306a36Sopenharmony_ci				tmp_evt->cmnd_done(tmp_evt->cmnd);
172662306a36Sopenharmony_ci			else if (tmp_evt->done)
172762306a36Sopenharmony_ci				tmp_evt->done(tmp_evt);
172862306a36Sopenharmony_ci		}
172962306a36Sopenharmony_ci	}
173062306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
173162306a36Sopenharmony_ci	return SUCCESS;
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci/**
173562306a36Sopenharmony_ci * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
173662306a36Sopenharmony_ci * @cmd:	struct scsi_cmnd having problems
173762306a36Sopenharmony_ci*/
173862306a36Sopenharmony_cistatic int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	unsigned long wait_switch = 0;
174162306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	ibmvscsi_reset_host(hostdata);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	for (wait_switch = jiffies + (init_timeout * HZ);
174862306a36Sopenharmony_ci	     time_before(jiffies, wait_switch) &&
174962306a36Sopenharmony_ci		     atomic_read(&hostdata->request_limit) < 2;) {
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci		msleep(10);
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	if (atomic_read(&hostdata->request_limit) <= 0)
175562306a36Sopenharmony_ci		return FAILED;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	return SUCCESS;
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci/**
176162306a36Sopenharmony_ci * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ
176262306a36Sopenharmony_ci * @crq:	Command/Response queue
176362306a36Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
176462306a36Sopenharmony_ci *
176562306a36Sopenharmony_ci*/
176662306a36Sopenharmony_cistatic void ibmvscsi_handle_crq(struct viosrp_crq *crq,
176762306a36Sopenharmony_ci				struct ibmvscsi_host_data *hostdata)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	long rc;
177062306a36Sopenharmony_ci	unsigned long flags;
177162306a36Sopenharmony_ci	/* The hypervisor copies our tag value here so no byteswapping */
177262306a36Sopenharmony_ci	struct srp_event_struct *evt_struct =
177362306a36Sopenharmony_ci			(__force struct srp_event_struct *)crq->IU_data_ptr;
177462306a36Sopenharmony_ci	switch (crq->valid) {
177562306a36Sopenharmony_ci	case VIOSRP_CRQ_INIT_RSP:		/* initialization */
177662306a36Sopenharmony_ci		switch (crq->format) {
177762306a36Sopenharmony_ci		case VIOSRP_CRQ_INIT:	/* Initialization message */
177862306a36Sopenharmony_ci			dev_info(hostdata->dev, "partner initialized\n");
177962306a36Sopenharmony_ci			/* Send back a response */
178062306a36Sopenharmony_ci			rc = ibmvscsi_send_crq(hostdata, 0xC002000000000000LL, 0);
178162306a36Sopenharmony_ci			if (rc == 0) {
178262306a36Sopenharmony_ci				/* Now login */
178362306a36Sopenharmony_ci				init_adapter(hostdata);
178462306a36Sopenharmony_ci			} else {
178562306a36Sopenharmony_ci				dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
178662306a36Sopenharmony_ci			}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci			break;
178962306a36Sopenharmony_ci		case VIOSRP_CRQ_INIT_COMPLETE:	/* Initialization response */
179062306a36Sopenharmony_ci			dev_info(hostdata->dev, "partner initialization complete\n");
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci			/* Now login */
179362306a36Sopenharmony_ci			init_adapter(hostdata);
179462306a36Sopenharmony_ci			break;
179562306a36Sopenharmony_ci		default:
179662306a36Sopenharmony_ci			dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
179762306a36Sopenharmony_ci		}
179862306a36Sopenharmony_ci		return;
179962306a36Sopenharmony_ci	case VIOSRP_CRQ_XPORT_EVENT:	/* Hypervisor telling us the connection is closed */
180062306a36Sopenharmony_ci		scsi_block_requests(hostdata->host);
180162306a36Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, 0);
180262306a36Sopenharmony_ci		if (crq->format == 0x06) {
180362306a36Sopenharmony_ci			/* We need to re-setup the interpartition connection */
180462306a36Sopenharmony_ci			dev_info(hostdata->dev, "Re-enabling adapter!\n");
180562306a36Sopenharmony_ci			hostdata->client_migrated = 1;
180662306a36Sopenharmony_ci			hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE;
180762306a36Sopenharmony_ci			purge_requests(hostdata, DID_REQUEUE);
180862306a36Sopenharmony_ci			wake_up(&hostdata->work_wait_q);
180962306a36Sopenharmony_ci		} else {
181062306a36Sopenharmony_ci			dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
181162306a36Sopenharmony_ci				crq->format);
181262306a36Sopenharmony_ci			ibmvscsi_reset_host(hostdata);
181362306a36Sopenharmony_ci		}
181462306a36Sopenharmony_ci		return;
181562306a36Sopenharmony_ci	case VIOSRP_CRQ_CMD_RSP:		/* real payload */
181662306a36Sopenharmony_ci		break;
181762306a36Sopenharmony_ci	default:
181862306a36Sopenharmony_ci		dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
181962306a36Sopenharmony_ci			crq->valid);
182062306a36Sopenharmony_ci		return;
182162306a36Sopenharmony_ci	}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/* The only kind of payload CRQs we should get are responses to
182462306a36Sopenharmony_ci	 * things we send. Make sure this response is to something we
182562306a36Sopenharmony_ci	 * actually sent
182662306a36Sopenharmony_ci	 */
182762306a36Sopenharmony_ci	if (!valid_event_struct(&hostdata->pool, evt_struct)) {
182862306a36Sopenharmony_ci		dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
182962306a36Sopenharmony_ci		       evt_struct);
183062306a36Sopenharmony_ci		return;
183162306a36Sopenharmony_ci	}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	if (atomic_read(&evt_struct->free)) {
183462306a36Sopenharmony_ci		dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
183562306a36Sopenharmony_ci			evt_struct);
183662306a36Sopenharmony_ci		return;
183762306a36Sopenharmony_ci	}
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	if (crq->format == VIOSRP_SRP_FORMAT)
184062306a36Sopenharmony_ci		atomic_add(be32_to_cpu(evt_struct->xfer_iu->srp.rsp.req_lim_delta),
184162306a36Sopenharmony_ci			   &hostdata->request_limit);
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	del_timer(&evt_struct->timer);
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd)
184662306a36Sopenharmony_ci		evt_struct->cmnd->result = DID_ERROR << 16;
184762306a36Sopenharmony_ci	if (evt_struct->done)
184862306a36Sopenharmony_ci		evt_struct->done(evt_struct);
184962306a36Sopenharmony_ci	else
185062306a36Sopenharmony_ci		dev_err(hostdata->dev, "returned done() is NULL; not running it!\n");
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	/*
185362306a36Sopenharmony_ci	 * Lock the host_lock before messing with these structures, since we
185462306a36Sopenharmony_ci	 * are running in a task context
185562306a36Sopenharmony_ci	 */
185662306a36Sopenharmony_ci	spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags);
185762306a36Sopenharmony_ci	list_del(&evt_struct->list);
185862306a36Sopenharmony_ci	free_event_struct(&evt_struct->hostdata->pool, evt_struct);
185962306a36Sopenharmony_ci	spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags);
186062306a36Sopenharmony_ci}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci/**
186362306a36Sopenharmony_ci * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
186462306a36Sopenharmony_ci * @sdev:	struct scsi_device device to configure
186562306a36Sopenharmony_ci *
186662306a36Sopenharmony_ci * Enable allow_restart for a device if it is a disk.  Adjust the
186762306a36Sopenharmony_ci * queue_depth here also as is required by the documentation for
186862306a36Sopenharmony_ci * struct scsi_host_template.
186962306a36Sopenharmony_ci */
187062306a36Sopenharmony_cistatic int ibmvscsi_slave_configure(struct scsi_device *sdev)
187162306a36Sopenharmony_ci{
187262306a36Sopenharmony_ci	struct Scsi_Host *shost = sdev->host;
187362306a36Sopenharmony_ci	unsigned long lock_flags = 0;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, lock_flags);
187662306a36Sopenharmony_ci	if (sdev->type == TYPE_DISK) {
187762306a36Sopenharmony_ci		sdev->allow_restart = 1;
187862306a36Sopenharmony_ci		blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, lock_flags);
188162306a36Sopenharmony_ci	return 0;
188262306a36Sopenharmony_ci}
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci/**
188562306a36Sopenharmony_ci * ibmvscsi_change_queue_depth - Change the device's queue depth
188662306a36Sopenharmony_ci * @sdev:	scsi device struct
188762306a36Sopenharmony_ci * @qdepth:	depth to set
188862306a36Sopenharmony_ci *
188962306a36Sopenharmony_ci * Return value:
189062306a36Sopenharmony_ci * 	actual depth set
189162306a36Sopenharmony_ci **/
189262306a36Sopenharmony_cistatic int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
189362306a36Sopenharmony_ci{
189462306a36Sopenharmony_ci	if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
189562306a36Sopenharmony_ci		qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
189662306a36Sopenharmony_ci	return scsi_change_queue_depth(sdev, qdepth);
189762306a36Sopenharmony_ci}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci/* ------------------------------------------------------------
190062306a36Sopenharmony_ci * sysfs attributes
190162306a36Sopenharmony_ci */
190262306a36Sopenharmony_cistatic ssize_t show_host_vhost_loc(struct device *dev,
190362306a36Sopenharmony_ci				   struct device_attribute *attr, char *buf)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
190662306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
190762306a36Sopenharmony_ci	int len;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n",
191062306a36Sopenharmony_ci		       hostdata->caps.loc);
191162306a36Sopenharmony_ci	return len;
191262306a36Sopenharmony_ci}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_vhost_loc = {
191562306a36Sopenharmony_ci	.attr = {
191662306a36Sopenharmony_ci		 .name = "vhost_loc",
191762306a36Sopenharmony_ci		 .mode = S_IRUGO,
191862306a36Sopenharmony_ci		 },
191962306a36Sopenharmony_ci	.show = show_host_vhost_loc,
192062306a36Sopenharmony_ci};
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_cistatic ssize_t show_host_vhost_name(struct device *dev,
192362306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
192462306a36Sopenharmony_ci{
192562306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
192662306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
192762306a36Sopenharmony_ci	int len;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n",
193062306a36Sopenharmony_ci		       hostdata->caps.name);
193162306a36Sopenharmony_ci	return len;
193262306a36Sopenharmony_ci}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_vhost_name = {
193562306a36Sopenharmony_ci	.attr = {
193662306a36Sopenharmony_ci		 .name = "vhost_name",
193762306a36Sopenharmony_ci		 .mode = S_IRUGO,
193862306a36Sopenharmony_ci		 },
193962306a36Sopenharmony_ci	.show = show_host_vhost_name,
194062306a36Sopenharmony_ci};
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_cistatic ssize_t show_host_srp_version(struct device *dev,
194362306a36Sopenharmony_ci				     struct device_attribute *attr, char *buf)
194462306a36Sopenharmony_ci{
194562306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
194662306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
194762306a36Sopenharmony_ci	int len;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%s\n",
195062306a36Sopenharmony_ci		       hostdata->madapter_info.srp_version);
195162306a36Sopenharmony_ci	return len;
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_srp_version = {
195562306a36Sopenharmony_ci	.attr = {
195662306a36Sopenharmony_ci		 .name = "srp_version",
195762306a36Sopenharmony_ci		 .mode = S_IRUGO,
195862306a36Sopenharmony_ci		 },
195962306a36Sopenharmony_ci	.show = show_host_srp_version,
196062306a36Sopenharmony_ci};
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_cistatic ssize_t show_host_partition_name(struct device *dev,
196362306a36Sopenharmony_ci					struct device_attribute *attr,
196462306a36Sopenharmony_ci					char *buf)
196562306a36Sopenharmony_ci{
196662306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
196762306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
196862306a36Sopenharmony_ci	int len;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%s\n",
197162306a36Sopenharmony_ci		       hostdata->madapter_info.partition_name);
197262306a36Sopenharmony_ci	return len;
197362306a36Sopenharmony_ci}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_partition_name = {
197662306a36Sopenharmony_ci	.attr = {
197762306a36Sopenharmony_ci		 .name = "partition_name",
197862306a36Sopenharmony_ci		 .mode = S_IRUGO,
197962306a36Sopenharmony_ci		 },
198062306a36Sopenharmony_ci	.show = show_host_partition_name,
198162306a36Sopenharmony_ci};
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_cistatic ssize_t show_host_partition_number(struct device *dev,
198462306a36Sopenharmony_ci					  struct device_attribute *attr,
198562306a36Sopenharmony_ci					  char *buf)
198662306a36Sopenharmony_ci{
198762306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
198862306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
198962306a36Sopenharmony_ci	int len;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%d\n",
199262306a36Sopenharmony_ci		       be32_to_cpu(hostdata->madapter_info.partition_number));
199362306a36Sopenharmony_ci	return len;
199462306a36Sopenharmony_ci}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_partition_number = {
199762306a36Sopenharmony_ci	.attr = {
199862306a36Sopenharmony_ci		 .name = "partition_number",
199962306a36Sopenharmony_ci		 .mode = S_IRUGO,
200062306a36Sopenharmony_ci		 },
200162306a36Sopenharmony_ci	.show = show_host_partition_number,
200262306a36Sopenharmony_ci};
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_cistatic ssize_t show_host_mad_version(struct device *dev,
200562306a36Sopenharmony_ci				     struct device_attribute *attr, char *buf)
200662306a36Sopenharmony_ci{
200762306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
200862306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
200962306a36Sopenharmony_ci	int len;
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%d\n",
201262306a36Sopenharmony_ci		       be32_to_cpu(hostdata->madapter_info.mad_version));
201362306a36Sopenharmony_ci	return len;
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_mad_version = {
201762306a36Sopenharmony_ci	.attr = {
201862306a36Sopenharmony_ci		 .name = "mad_version",
201962306a36Sopenharmony_ci		 .mode = S_IRUGO,
202062306a36Sopenharmony_ci		 },
202162306a36Sopenharmony_ci	.show = show_host_mad_version,
202262306a36Sopenharmony_ci};
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_cistatic ssize_t show_host_os_type(struct device *dev,
202562306a36Sopenharmony_ci				 struct device_attribute *attr, char *buf)
202662306a36Sopenharmony_ci{
202762306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
202862306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
202962306a36Sopenharmony_ci	int len;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%d\n",
203262306a36Sopenharmony_ci		       be32_to_cpu(hostdata->madapter_info.os_type));
203362306a36Sopenharmony_ci	return len;
203462306a36Sopenharmony_ci}
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_os_type = {
203762306a36Sopenharmony_ci	.attr = {
203862306a36Sopenharmony_ci		 .name = "os_type",
203962306a36Sopenharmony_ci		 .mode = S_IRUGO,
204062306a36Sopenharmony_ci		 },
204162306a36Sopenharmony_ci	.show = show_host_os_type,
204262306a36Sopenharmony_ci};
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_cistatic ssize_t show_host_config(struct device *dev,
204562306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
204662306a36Sopenharmony_ci{
204762306a36Sopenharmony_ci	return 0;
204862306a36Sopenharmony_ci}
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_cistatic struct device_attribute ibmvscsi_host_config = {
205162306a36Sopenharmony_ci	.attr = {
205262306a36Sopenharmony_ci		.name = "config",
205362306a36Sopenharmony_ci		.mode = S_IRUGO,
205462306a36Sopenharmony_ci		},
205562306a36Sopenharmony_ci	.show = show_host_config,
205662306a36Sopenharmony_ci};
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_cistatic int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type)
205962306a36Sopenharmony_ci{
206062306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	dev_info(hostdata->dev, "Initiating adapter reset!\n");
206362306a36Sopenharmony_ci	ibmvscsi_reset_host(hostdata);
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	return 0;
206662306a36Sopenharmony_ci}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_cistatic struct attribute *ibmvscsi_host_attrs[] = {
206962306a36Sopenharmony_ci	&ibmvscsi_host_vhost_loc.attr,
207062306a36Sopenharmony_ci	&ibmvscsi_host_vhost_name.attr,
207162306a36Sopenharmony_ci	&ibmvscsi_host_srp_version.attr,
207262306a36Sopenharmony_ci	&ibmvscsi_host_partition_name.attr,
207362306a36Sopenharmony_ci	&ibmvscsi_host_partition_number.attr,
207462306a36Sopenharmony_ci	&ibmvscsi_host_mad_version.attr,
207562306a36Sopenharmony_ci	&ibmvscsi_host_os_type.attr,
207662306a36Sopenharmony_ci	&ibmvscsi_host_config.attr,
207762306a36Sopenharmony_ci	NULL
207862306a36Sopenharmony_ci};
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ciATTRIBUTE_GROUPS(ibmvscsi_host);
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci/* ------------------------------------------------------------
208362306a36Sopenharmony_ci * SCSI driver registration
208462306a36Sopenharmony_ci */
208562306a36Sopenharmony_cistatic struct scsi_host_template driver_template = {
208662306a36Sopenharmony_ci	.module = THIS_MODULE,
208762306a36Sopenharmony_ci	.name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION,
208862306a36Sopenharmony_ci	.proc_name = "ibmvscsi",
208962306a36Sopenharmony_ci	.queuecommand = ibmvscsi_queuecommand,
209062306a36Sopenharmony_ci	.eh_timed_out = srp_timed_out,
209162306a36Sopenharmony_ci	.eh_abort_handler = ibmvscsi_eh_abort_handler,
209262306a36Sopenharmony_ci	.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
209362306a36Sopenharmony_ci	.eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
209462306a36Sopenharmony_ci	.slave_configure = ibmvscsi_slave_configure,
209562306a36Sopenharmony_ci	.change_queue_depth = ibmvscsi_change_queue_depth,
209662306a36Sopenharmony_ci	.host_reset = ibmvscsi_host_reset,
209762306a36Sopenharmony_ci	.cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
209862306a36Sopenharmony_ci	.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
209962306a36Sopenharmony_ci	.this_id = -1,
210062306a36Sopenharmony_ci	.sg_tablesize = SG_ALL,
210162306a36Sopenharmony_ci	.shost_groups = ibmvscsi_host_groups,
210262306a36Sopenharmony_ci};
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci/**
210562306a36Sopenharmony_ci * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver
210662306a36Sopenharmony_ci *
210762306a36Sopenharmony_ci * @vdev: struct vio_dev for the device whose desired IO mem is to be returned
210862306a36Sopenharmony_ci *
210962306a36Sopenharmony_ci * Return value:
211062306a36Sopenharmony_ci *	Number of bytes of IO data the driver will need to perform well.
211162306a36Sopenharmony_ci */
211262306a36Sopenharmony_cistatic unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
211362306a36Sopenharmony_ci{
211462306a36Sopenharmony_ci	/* iu_storage data allocated in initialize_event_pool */
211562306a36Sopenharmony_ci	unsigned long desired_io = max_events * sizeof(union viosrp_iu);
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	/* add io space for sg data */
211862306a36Sopenharmony_ci	desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 *
211962306a36Sopenharmony_ci	                     IBMVSCSI_CMDS_PER_LUN_DEFAULT);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	return desired_io;
212262306a36Sopenharmony_ci}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_cistatic void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
212562306a36Sopenharmony_ci{
212662306a36Sopenharmony_ci	unsigned long flags;
212762306a36Sopenharmony_ci	int rc;
212862306a36Sopenharmony_ci	char *action = "reset";
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
213162306a36Sopenharmony_ci	switch (hostdata->action) {
213262306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_UNBLOCK:
213362306a36Sopenharmony_ci		rc = 0;
213462306a36Sopenharmony_ci		break;
213562306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_RESET:
213662306a36Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
213762306a36Sopenharmony_ci		rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
213862306a36Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
213962306a36Sopenharmony_ci		if (!rc)
214062306a36Sopenharmony_ci			rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
214162306a36Sopenharmony_ci		vio_enable_interrupts(to_vio_dev(hostdata->dev));
214262306a36Sopenharmony_ci		break;
214362306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_REENABLE:
214462306a36Sopenharmony_ci		action = "enable";
214562306a36Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
214662306a36Sopenharmony_ci		rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata);
214762306a36Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
214862306a36Sopenharmony_ci		if (!rc)
214962306a36Sopenharmony_ci			rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
215062306a36Sopenharmony_ci		break;
215162306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_NONE:
215262306a36Sopenharmony_ci	default:
215362306a36Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
215462306a36Sopenharmony_ci		return;
215562306a36Sopenharmony_ci	}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	hostdata->action = IBMVSCSI_HOST_ACTION_NONE;
215862306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	if (rc) {
216162306a36Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, -1);
216262306a36Sopenharmony_ci		dev_err(hostdata->dev, "error after %s\n", action);
216362306a36Sopenharmony_ci	}
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	scsi_unblock_requests(hostdata->host);
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cistatic int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	if (kthread_should_stop())
217162306a36Sopenharmony_ci		return 1;
217262306a36Sopenharmony_ci	switch (hostdata->action) {
217362306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_NONE:
217462306a36Sopenharmony_ci		return 0;
217562306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_RESET:
217662306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_REENABLE:
217762306a36Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_UNBLOCK:
217862306a36Sopenharmony_ci	default:
217962306a36Sopenharmony_ci		break;
218062306a36Sopenharmony_ci	}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	return 1;
218362306a36Sopenharmony_ci}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_cistatic int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	unsigned long flags;
218862306a36Sopenharmony_ci	int rc;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
219162306a36Sopenharmony_ci	rc = __ibmvscsi_work_to_do(hostdata);
219262306a36Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	return rc;
219562306a36Sopenharmony_ci}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_cistatic int ibmvscsi_work(void *data)
219862306a36Sopenharmony_ci{
219962306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = data;
220062306a36Sopenharmony_ci	int rc;
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	set_user_nice(current, MIN_NICE);
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	while (1) {
220562306a36Sopenharmony_ci		rc = wait_event_interruptible(hostdata->work_wait_q,
220662306a36Sopenharmony_ci					      ibmvscsi_work_to_do(hostdata));
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci		BUG_ON(rc);
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci		if (kthread_should_stop())
221162306a36Sopenharmony_ci			break;
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci		ibmvscsi_do_work(hostdata);
221462306a36Sopenharmony_ci	}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	return 0;
221762306a36Sopenharmony_ci}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci/*
222062306a36Sopenharmony_ci * Called by bus code for each adapter
222162306a36Sopenharmony_ci */
222262306a36Sopenharmony_cistatic int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
222362306a36Sopenharmony_ci{
222462306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata;
222562306a36Sopenharmony_ci	struct Scsi_Host *host;
222662306a36Sopenharmony_ci	struct device *dev = &vdev->dev;
222762306a36Sopenharmony_ci	struct srp_rport_identifiers ids;
222862306a36Sopenharmony_ci	struct srp_rport *rport;
222962306a36Sopenharmony_ci	unsigned long wait_switch = 0;
223062306a36Sopenharmony_ci	int rc;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	dev_set_drvdata(&vdev->dev, NULL);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
223562306a36Sopenharmony_ci	if (!host) {
223662306a36Sopenharmony_ci		dev_err(&vdev->dev, "couldn't allocate host data\n");
223762306a36Sopenharmony_ci		goto scsi_host_alloc_failed;
223862306a36Sopenharmony_ci	}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	host->transportt = ibmvscsi_transport_template;
224162306a36Sopenharmony_ci	hostdata = shost_priv(host);
224262306a36Sopenharmony_ci	memset(hostdata, 0x00, sizeof(*hostdata));
224362306a36Sopenharmony_ci	INIT_LIST_HEAD(&hostdata->sent);
224462306a36Sopenharmony_ci	init_waitqueue_head(&hostdata->work_wait_q);
224562306a36Sopenharmony_ci	hostdata->host = host;
224662306a36Sopenharmony_ci	hostdata->dev = dev;
224762306a36Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata, -1);
224862306a36Sopenharmony_ci	hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	if (map_persist_bufs(hostdata)) {
225162306a36Sopenharmony_ci		dev_err(&vdev->dev, "couldn't map persistent buffers\n");
225262306a36Sopenharmony_ci		goto persist_bufs_failed;
225362306a36Sopenharmony_ci	}
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
225662306a36Sopenharmony_ci					    "ibmvscsi", host->host_no);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	if (IS_ERR(hostdata->work_thread)) {
225962306a36Sopenharmony_ci		dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
226062306a36Sopenharmony_ci			PTR_ERR(hostdata->work_thread));
226162306a36Sopenharmony_ci		goto init_crq_failed;
226262306a36Sopenharmony_ci	}
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci	rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_events);
226562306a36Sopenharmony_ci	if (rc != 0 && rc != H_RESOURCE) {
226662306a36Sopenharmony_ci		dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
226762306a36Sopenharmony_ci		goto kill_kthread;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci	if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
227062306a36Sopenharmony_ci		dev_err(&vdev->dev, "couldn't initialize event pool\n");
227162306a36Sopenharmony_ci		goto init_pool_failed;
227262306a36Sopenharmony_ci	}
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	host->max_lun = IBMVSCSI_MAX_LUN;
227562306a36Sopenharmony_ci	host->max_id = max_id;
227662306a36Sopenharmony_ci	host->max_channel = max_channel;
227762306a36Sopenharmony_ci	host->max_cmd_len = 16;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	dev_info(dev,
228062306a36Sopenharmony_ci		 "Maximum ID: %d Maximum LUN: %llu Maximum Channel: %d\n",
228162306a36Sopenharmony_ci		 host->max_id, host->max_lun, host->max_channel);
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	if (scsi_add_host(hostdata->host, hostdata->dev))
228462306a36Sopenharmony_ci		goto add_host_failed;
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	/* we don't have a proper target_port_id so let's use the fake one */
228762306a36Sopenharmony_ci	memcpy(ids.port_id, hostdata->madapter_info.partition_name,
228862306a36Sopenharmony_ci	       sizeof(ids.port_id));
228962306a36Sopenharmony_ci	ids.roles = SRP_RPORT_ROLE_TARGET;
229062306a36Sopenharmony_ci	rport = srp_rport_add(host, &ids);
229162306a36Sopenharmony_ci	if (IS_ERR(rport))
229262306a36Sopenharmony_ci		goto add_srp_port_failed;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	/* Try to send an initialization message.  Note that this is allowed
229562306a36Sopenharmony_ci	 * to fail if the other end is not acive.  In that case we don't
229662306a36Sopenharmony_ci	 * want to scan
229762306a36Sopenharmony_ci	 */
229862306a36Sopenharmony_ci	if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
229962306a36Sopenharmony_ci	    || rc == H_RESOURCE) {
230062306a36Sopenharmony_ci		/*
230162306a36Sopenharmony_ci		 * Wait around max init_timeout secs for the adapter to finish
230262306a36Sopenharmony_ci		 * initializing. When we are done initializing, we will have a
230362306a36Sopenharmony_ci		 * valid request_limit.  We don't want Linux scanning before
230462306a36Sopenharmony_ci		 * we are ready.
230562306a36Sopenharmony_ci		 */
230662306a36Sopenharmony_ci		for (wait_switch = jiffies + (init_timeout * HZ);
230762306a36Sopenharmony_ci		     time_before(jiffies, wait_switch) &&
230862306a36Sopenharmony_ci		     atomic_read(&hostdata->request_limit) < 2;) {
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci			msleep(10);
231162306a36Sopenharmony_ci		}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci		/* if we now have a valid request_limit, initiate a scan */
231462306a36Sopenharmony_ci		if (atomic_read(&hostdata->request_limit) > 0)
231562306a36Sopenharmony_ci			scsi_scan_host(host);
231662306a36Sopenharmony_ci	}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	dev_set_drvdata(&vdev->dev, hostdata);
231962306a36Sopenharmony_ci	spin_lock(&ibmvscsi_driver_lock);
232062306a36Sopenharmony_ci	list_add_tail(&hostdata->host_list, &ibmvscsi_head);
232162306a36Sopenharmony_ci	spin_unlock(&ibmvscsi_driver_lock);
232262306a36Sopenharmony_ci	return 0;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci      add_srp_port_failed:
232562306a36Sopenharmony_ci	scsi_remove_host(hostdata->host);
232662306a36Sopenharmony_ci      add_host_failed:
232762306a36Sopenharmony_ci	release_event_pool(&hostdata->pool, hostdata);
232862306a36Sopenharmony_ci      init_pool_failed:
232962306a36Sopenharmony_ci	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_events);
233062306a36Sopenharmony_ci      kill_kthread:
233162306a36Sopenharmony_ci      kthread_stop(hostdata->work_thread);
233262306a36Sopenharmony_ci      init_crq_failed:
233362306a36Sopenharmony_ci	unmap_persist_bufs(hostdata);
233462306a36Sopenharmony_ci      persist_bufs_failed:
233562306a36Sopenharmony_ci	scsi_host_put(host);
233662306a36Sopenharmony_ci      scsi_host_alloc_failed:
233762306a36Sopenharmony_ci	return -1;
233862306a36Sopenharmony_ci}
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_cistatic void ibmvscsi_remove(struct vio_dev *vdev)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	srp_remove_host(hostdata->host);
234562306a36Sopenharmony_ci	scsi_remove_host(hostdata->host);
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_ci	purge_requests(hostdata, DID_ERROR);
234862306a36Sopenharmony_ci	release_event_pool(&hostdata->pool, hostdata);
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
235162306a36Sopenharmony_ci					max_events);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	kthread_stop(hostdata->work_thread);
235462306a36Sopenharmony_ci	unmap_persist_bufs(hostdata);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	spin_lock(&ibmvscsi_driver_lock);
235762306a36Sopenharmony_ci	list_del(&hostdata->host_list);
235862306a36Sopenharmony_ci	spin_unlock(&ibmvscsi_driver_lock);
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	scsi_host_put(hostdata->host);
236162306a36Sopenharmony_ci}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci/**
236462306a36Sopenharmony_ci * ibmvscsi_resume: Resume from suspend
236562306a36Sopenharmony_ci * @dev:	device struct
236662306a36Sopenharmony_ci *
236762306a36Sopenharmony_ci * We may have lost an interrupt across suspend/resume, so kick the
236862306a36Sopenharmony_ci * interrupt handler
236962306a36Sopenharmony_ci */
237062306a36Sopenharmony_cistatic int ibmvscsi_resume(struct device *dev)
237162306a36Sopenharmony_ci{
237262306a36Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(dev);
237362306a36Sopenharmony_ci	vio_disable_interrupts(to_vio_dev(hostdata->dev));
237462306a36Sopenharmony_ci	tasklet_schedule(&hostdata->srp_task);
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	return 0;
237762306a36Sopenharmony_ci}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci/*
238062306a36Sopenharmony_ci * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we
238162306a36Sopenharmony_ci * support.
238262306a36Sopenharmony_ci */
238362306a36Sopenharmony_cistatic const struct vio_device_id ibmvscsi_device_table[] = {
238462306a36Sopenharmony_ci	{"vscsi", "IBM,v-scsi"},
238562306a36Sopenharmony_ci	{ "", "" }
238662306a36Sopenharmony_ci};
238762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_cistatic const struct dev_pm_ops ibmvscsi_pm_ops = {
239062306a36Sopenharmony_ci	.resume = ibmvscsi_resume
239162306a36Sopenharmony_ci};
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_cistatic struct vio_driver ibmvscsi_driver = {
239462306a36Sopenharmony_ci	.id_table = ibmvscsi_device_table,
239562306a36Sopenharmony_ci	.probe = ibmvscsi_probe,
239662306a36Sopenharmony_ci	.remove = ibmvscsi_remove,
239762306a36Sopenharmony_ci	.get_desired_dma = ibmvscsi_get_desired_dma,
239862306a36Sopenharmony_ci	.name = "ibmvscsi",
239962306a36Sopenharmony_ci	.pm = &ibmvscsi_pm_ops,
240062306a36Sopenharmony_ci};
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_cistatic struct srp_function_template ibmvscsi_transport_functions = {
240362306a36Sopenharmony_ci};
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_cistatic int __init ibmvscsi_module_init(void)
240662306a36Sopenharmony_ci{
240762306a36Sopenharmony_ci	int ret;
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	/* Ensure we have two requests to do error recovery */
241062306a36Sopenharmony_ci	driver_template.can_queue = max_requests;
241162306a36Sopenharmony_ci	max_events = max_requests + 2;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	if (!firmware_has_feature(FW_FEATURE_VIO))
241462306a36Sopenharmony_ci		return -ENODEV;
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	ibmvscsi_transport_template =
241762306a36Sopenharmony_ci		srp_attach_transport(&ibmvscsi_transport_functions);
241862306a36Sopenharmony_ci	if (!ibmvscsi_transport_template)
241962306a36Sopenharmony_ci		return -ENOMEM;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	ret = vio_register_driver(&ibmvscsi_driver);
242262306a36Sopenharmony_ci	if (ret)
242362306a36Sopenharmony_ci		srp_release_transport(ibmvscsi_transport_template);
242462306a36Sopenharmony_ci	return ret;
242562306a36Sopenharmony_ci}
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_cistatic void __exit ibmvscsi_module_exit(void)
242862306a36Sopenharmony_ci{
242962306a36Sopenharmony_ci	vio_unregister_driver(&ibmvscsi_driver);
243062306a36Sopenharmony_ci	srp_release_transport(ibmvscsi_transport_template);
243162306a36Sopenharmony_ci}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_cimodule_init(ibmvscsi_module_init);
243462306a36Sopenharmony_cimodule_exit(ibmvscsi_module_exit);
2435