18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
38c2ecf20Sopenharmony_ci * ibmvscsi.c
48c2ecf20Sopenharmony_ci * (C) Copyright IBM Corporation 1994, 2004
58c2ecf20Sopenharmony_ci * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
68c2ecf20Sopenharmony_ci *          Santiago Leon (santil@us.ibm.com)
78c2ecf20Sopenharmony_ci *          Dave Boutcher (sleddog@us.ibm.com)
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * ------------------------------------------------------------
108c2ecf20Sopenharmony_ci * Emulation of a SCSI host adapter for Virtual I/O devices
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This driver supports the SCSI adapter implemented by the IBM
138c2ecf20Sopenharmony_ci * Power5 firmware.  That SCSI adapter is not a physical adapter,
148c2ecf20Sopenharmony_ci * but allows Linux SCSI peripheral drivers to directly
158c2ecf20Sopenharmony_ci * access devices in another logical partition on the physical system.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * The virtual adapter(s) are present in the open firmware device
188c2ecf20Sopenharmony_ci * tree just like real adapters.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * One of the capabilities provided on these systems is the ability
218c2ecf20Sopenharmony_ci * to DMA between partitions.  The architecture states that for VSCSI,
228c2ecf20Sopenharmony_ci * the server side is allowed to DMA to and from the client.  The client
238c2ecf20Sopenharmony_ci * is never trusted to DMA to or from the server directly.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * Messages are sent between partitions on a "Command/Response Queue"
268c2ecf20Sopenharmony_ci * (CRQ), which is just a buffer of 16 byte entries in the receiver's
278c2ecf20Sopenharmony_ci * Senders cannot access the buffer directly, but send messages by
288c2ecf20Sopenharmony_ci * making a hypervisor call and passing in the 16 bytes.  The hypervisor
298c2ecf20Sopenharmony_ci * puts the message in the next 16 byte space in round-robin fashion,
308c2ecf20Sopenharmony_ci * turns on the high order bit of the message (the valid bit), and
318c2ecf20Sopenharmony_ci * generates an interrupt to the receiver (if interrupts are turned on.)
328c2ecf20Sopenharmony_ci * The receiver just turns off the valid bit when they have copied out
338c2ecf20Sopenharmony_ci * the message.
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit
368c2ecf20Sopenharmony_ci * (IU) (as defined in the T10 standard available at www.t10.org), gets
378c2ecf20Sopenharmony_ci * a DMA address for the message, and sends it to the server as the
388c2ecf20Sopenharmony_ci * payload of a CRQ message.  The server DMAs the SRP IU and processes it,
398c2ecf20Sopenharmony_ci * including doing any additional data transfers.  When it is done, it
408c2ecf20Sopenharmony_ci * DMAs the SRP response back to the same address as the request came from,
418c2ecf20Sopenharmony_ci * and sends a CRQ message back to inform the client that the request has
428c2ecf20Sopenharmony_ci * completed.
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * TODO: This is currently pretty tied to the IBM pSeries hypervisor
458c2ecf20Sopenharmony_ci * interfaces.  It would be really nice to abstract this above an RDMA
468c2ecf20Sopenharmony_ci * layer.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#include <linux/module.h>
508c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
518c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
528c2ecf20Sopenharmony_ci#include <linux/delay.h>
538c2ecf20Sopenharmony_ci#include <linux/slab.h>
548c2ecf20Sopenharmony_ci#include <linux/of.h>
558c2ecf20Sopenharmony_ci#include <linux/pm.h>
568c2ecf20Sopenharmony_ci#include <linux/kthread.h>
578c2ecf20Sopenharmony_ci#include <asm/firmware.h>
588c2ecf20Sopenharmony_ci#include <asm/vio.h>
598c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
608c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
618c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
628c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
638c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_srp.h>
648c2ecf20Sopenharmony_ci#include "ibmvscsi.h"
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/* The values below are somewhat arbitrary default values, but
678c2ecf20Sopenharmony_ci * OS/400 will use 3 busses (disks, CDs, tapes, I think.)
688c2ecf20Sopenharmony_ci * Note that there are 3 bits of channel value, 6 bits of id, and
698c2ecf20Sopenharmony_ci * 5 bits of LUN.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_cistatic int max_id = 64;
728c2ecf20Sopenharmony_cistatic int max_channel = 3;
738c2ecf20Sopenharmony_cistatic int init_timeout = 300;
748c2ecf20Sopenharmony_cistatic int login_timeout = 60;
758c2ecf20Sopenharmony_cistatic int info_timeout = 30;
768c2ecf20Sopenharmony_cistatic int abort_timeout = 60;
778c2ecf20Sopenharmony_cistatic int reset_timeout = 60;
788c2ecf20Sopenharmony_cistatic int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
798c2ecf20Sopenharmony_cistatic int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
808c2ecf20Sopenharmony_cistatic int fast_fail = 1;
818c2ecf20Sopenharmony_cistatic int client_reserve = 1;
828c2ecf20Sopenharmony_cistatic char partition_name[96] = "UNKNOWN";
838c2ecf20Sopenharmony_cistatic unsigned int partition_number = -1;
848c2ecf20Sopenharmony_cistatic LIST_HEAD(ibmvscsi_head);
858c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(ibmvscsi_driver_lock);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic struct scsi_transport_template *ibmvscsi_transport_template;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define IBMVSCSI_VERSION "1.5.9"
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IBM Virtual SCSI");
928c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dave Boutcher");
938c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
948c2ecf20Sopenharmony_ciMODULE_VERSION(IBMVSCSI_VERSION);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cimodule_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_id, "Largest ID value for each channel [Default=64]");
988c2ecf20Sopenharmony_cimodule_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
998c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_channel, "Largest channel value [Default=3]");
1008c2ecf20Sopenharmony_cimodule_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
1018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
1028c2ecf20Sopenharmony_cimodule_param_named(max_requests, max_requests, int, S_IRUGO);
1038c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
1048c2ecf20Sopenharmony_cimodule_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR);
1058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]");
1068c2ecf20Sopenharmony_cimodule_param_named(client_reserve, client_reserve, int, S_IRUGO );
1078c2ecf20Sopenharmony_ciMODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release");
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void ibmvscsi_handle_crq(struct viosrp_crq *crq,
1108c2ecf20Sopenharmony_ci				struct ibmvscsi_host_data *hostdata);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
1138c2ecf20Sopenharmony_ci * Routines for managing the command/response queue
1148c2ecf20Sopenharmony_ci */
1158c2ecf20Sopenharmony_ci/**
1168c2ecf20Sopenharmony_ci * ibmvscsi_handle_event: - Interrupt handler for crq events
1178c2ecf20Sopenharmony_ci * @irq:	number of irq to handle, not used
1188c2ecf20Sopenharmony_ci * @dev_instance: ibmvscsi_host_data of host that received interrupt
1198c2ecf20Sopenharmony_ci *
1208c2ecf20Sopenharmony_ci * Disables interrupts and schedules srp_task
1218c2ecf20Sopenharmony_ci * Always returns IRQ_HANDLED
1228c2ecf20Sopenharmony_ci */
1238c2ecf20Sopenharmony_cistatic irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata =
1268c2ecf20Sopenharmony_ci	    (struct ibmvscsi_host_data *)dev_instance;
1278c2ecf20Sopenharmony_ci	vio_disable_interrupts(to_vio_dev(hostdata->dev));
1288c2ecf20Sopenharmony_ci	tasklet_schedule(&hostdata->srp_task);
1298c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/**
1338c2ecf20Sopenharmony_ci * release_crq_queue: - Deallocates data and unregisters CRQ
1348c2ecf20Sopenharmony_ci * @queue:	crq_queue to initialize and register
1358c2ecf20Sopenharmony_ci * @host_data:	ibmvscsi_host_data of host
1368c2ecf20Sopenharmony_ci *
1378c2ecf20Sopenharmony_ci * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
1388c2ecf20Sopenharmony_ci * the crq with the hypervisor.
1398c2ecf20Sopenharmony_ci */
1408c2ecf20Sopenharmony_cistatic void ibmvscsi_release_crq_queue(struct crq_queue *queue,
1418c2ecf20Sopenharmony_ci				       struct ibmvscsi_host_data *hostdata,
1428c2ecf20Sopenharmony_ci				       int max_requests)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	long rc = 0;
1458c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
1468c2ecf20Sopenharmony_ci	free_irq(vdev->irq, (void *)hostdata);
1478c2ecf20Sopenharmony_ci	tasklet_kill(&hostdata->srp_task);
1488c2ecf20Sopenharmony_ci	do {
1498c2ecf20Sopenharmony_ci		if (rc)
1508c2ecf20Sopenharmony_ci			msleep(100);
1518c2ecf20Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
1528c2ecf20Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
1538c2ecf20Sopenharmony_ci	dma_unmap_single(hostdata->dev,
1548c2ecf20Sopenharmony_ci			 queue->msg_token,
1558c2ecf20Sopenharmony_ci			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
1568c2ecf20Sopenharmony_ci	free_page((unsigned long)queue->msgs);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/**
1608c2ecf20Sopenharmony_ci * crq_queue_next_crq: - Returns the next entry in message queue
1618c2ecf20Sopenharmony_ci * @queue:	crq_queue to use
1628c2ecf20Sopenharmony_ci *
1638c2ecf20Sopenharmony_ci * Returns pointer to next entry in queue, or NULL if there are no new
1648c2ecf20Sopenharmony_ci * entried in the CRQ.
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_cistatic struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
1698c2ecf20Sopenharmony_ci	unsigned long flags;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	spin_lock_irqsave(&queue->lock, flags);
1728c2ecf20Sopenharmony_ci	crq = &queue->msgs[queue->cur];
1738c2ecf20Sopenharmony_ci	if (crq->valid != VIOSRP_CRQ_FREE) {
1748c2ecf20Sopenharmony_ci		if (++queue->cur == queue->size)
1758c2ecf20Sopenharmony_ci			queue->cur = 0;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci		/* Ensure the read of the valid bit occurs before reading any
1788c2ecf20Sopenharmony_ci		 * other bits of the CRQ entry
1798c2ecf20Sopenharmony_ci		 */
1808c2ecf20Sopenharmony_ci		rmb();
1818c2ecf20Sopenharmony_ci	} else
1828c2ecf20Sopenharmony_ci		crq = NULL;
1838c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&queue->lock, flags);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return crq;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/**
1898c2ecf20Sopenharmony_ci * ibmvscsi_send_crq: - Send a CRQ
1908c2ecf20Sopenharmony_ci * @hostdata:	the adapter
1918c2ecf20Sopenharmony_ci * @word1:	the first 64 bits of the data
1928c2ecf20Sopenharmony_ci * @word2:	the second 64 bits of the data
1938c2ecf20Sopenharmony_ci */
1948c2ecf20Sopenharmony_cistatic int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
1958c2ecf20Sopenharmony_ci			     u64 word1, u64 word2)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/*
2008c2ecf20Sopenharmony_ci	 * Ensure the command buffer is flushed to memory before handing it
2018c2ecf20Sopenharmony_ci	 * over to the VIOS to prevent it from fetching any stale data.
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	mb();
2048c2ecf20Sopenharmony_ci	return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/**
2088c2ecf20Sopenharmony_ci * ibmvscsi_task: - Process srps asynchronously
2098c2ecf20Sopenharmony_ci * @data:	ibmvscsi_host_data of host
2108c2ecf20Sopenharmony_ci */
2118c2ecf20Sopenharmony_cistatic void ibmvscsi_task(void *data)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
2148c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
2158c2ecf20Sopenharmony_ci	struct viosrp_crq *crq;
2168c2ecf20Sopenharmony_ci	int done = 0;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	while (!done) {
2198c2ecf20Sopenharmony_ci		/* Pull all the valid messages off the CRQ */
2208c2ecf20Sopenharmony_ci		while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
2218c2ecf20Sopenharmony_ci			ibmvscsi_handle_crq(crq, hostdata);
2228c2ecf20Sopenharmony_ci			crq->valid = VIOSRP_CRQ_FREE;
2238c2ecf20Sopenharmony_ci			wmb();
2248c2ecf20Sopenharmony_ci		}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		vio_enable_interrupts(vdev);
2278c2ecf20Sopenharmony_ci		crq = crq_queue_next_crq(&hostdata->queue);
2288c2ecf20Sopenharmony_ci		if (crq != NULL) {
2298c2ecf20Sopenharmony_ci			vio_disable_interrupts(vdev);
2308c2ecf20Sopenharmony_ci			ibmvscsi_handle_crq(crq, hostdata);
2318c2ecf20Sopenharmony_ci			crq->valid = VIOSRP_CRQ_FREE;
2328c2ecf20Sopenharmony_ci			wmb();
2338c2ecf20Sopenharmony_ci		} else {
2348c2ecf20Sopenharmony_ci			done = 1;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic void gather_partition_info(void)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	const char *ppartition_name;
2428c2ecf20Sopenharmony_ci	const __be32 *p_number_ptr;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* Retrieve information about this partition */
2458c2ecf20Sopenharmony_ci	if (!of_root)
2468c2ecf20Sopenharmony_ci		return;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	of_node_get(of_root);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	ppartition_name = of_get_property(of_root, "ibm,partition-name", NULL);
2518c2ecf20Sopenharmony_ci	if (ppartition_name)
2528c2ecf20Sopenharmony_ci		strlcpy(partition_name, ppartition_name,
2538c2ecf20Sopenharmony_ci				sizeof(partition_name));
2548c2ecf20Sopenharmony_ci	p_number_ptr = of_get_property(of_root, "ibm,partition-no", NULL);
2558c2ecf20Sopenharmony_ci	if (p_number_ptr)
2568c2ecf20Sopenharmony_ci		partition_number = of_read_number(p_number_ptr, 1);
2578c2ecf20Sopenharmony_ci	of_node_put(of_root);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic void set_adapter_info(struct ibmvscsi_host_data *hostdata)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	memset(&hostdata->madapter_info, 0x00,
2638c2ecf20Sopenharmony_ci			sizeof(hostdata->madapter_info));
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	dev_info(hostdata->dev, "SRP_VERSION: %s\n", SRP_VERSION);
2668c2ecf20Sopenharmony_ci	strcpy(hostdata->madapter_info.srp_version, SRP_VERSION);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	strncpy(hostdata->madapter_info.partition_name, partition_name,
2698c2ecf20Sopenharmony_ci			sizeof(hostdata->madapter_info.partition_name));
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	hostdata->madapter_info.partition_number =
2728c2ecf20Sopenharmony_ci					cpu_to_be32(partition_number);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	hostdata->madapter_info.mad_version = cpu_to_be32(SRP_MAD_VERSION_1);
2758c2ecf20Sopenharmony_ci	hostdata->madapter_info.os_type = cpu_to_be32(SRP_MAD_OS_LINUX);
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/**
2798c2ecf20Sopenharmony_ci * reset_crq_queue: - resets a crq after a failure
2808c2ecf20Sopenharmony_ci * @queue:	crq_queue to initialize and register
2818c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
2828c2ecf20Sopenharmony_ci *
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_cistatic int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
2858c2ecf20Sopenharmony_ci				    struct ibmvscsi_host_data *hostdata)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	int rc = 0;
2888c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/* Close the CRQ */
2918c2ecf20Sopenharmony_ci	do {
2928c2ecf20Sopenharmony_ci		if (rc)
2938c2ecf20Sopenharmony_ci			msleep(100);
2948c2ecf20Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
2958c2ecf20Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/* Clean out the queue */
2988c2ecf20Sopenharmony_ci	memset(queue->msgs, 0x00, PAGE_SIZE);
2998c2ecf20Sopenharmony_ci	queue->cur = 0;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	set_adapter_info(hostdata);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* And re-open it again */
3048c2ecf20Sopenharmony_ci	rc = plpar_hcall_norets(H_REG_CRQ,
3058c2ecf20Sopenharmony_ci				vdev->unit_address,
3068c2ecf20Sopenharmony_ci				queue->msg_token, PAGE_SIZE);
3078c2ecf20Sopenharmony_ci	if (rc == H_CLOSED) {
3088c2ecf20Sopenharmony_ci		/* Adapter is good, but other end is not ready */
3098c2ecf20Sopenharmony_ci		dev_warn(hostdata->dev, "Partner adapter not ready\n");
3108c2ecf20Sopenharmony_ci	} else if (rc != 0) {
3118c2ecf20Sopenharmony_ci		dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	return rc;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci/**
3178c2ecf20Sopenharmony_ci * initialize_crq_queue: - Initializes and registers CRQ with hypervisor
3188c2ecf20Sopenharmony_ci * @queue:	crq_queue to initialize and register
3198c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
3208c2ecf20Sopenharmony_ci *
3218c2ecf20Sopenharmony_ci * Allocates a page for messages, maps it for dma, and registers
3228c2ecf20Sopenharmony_ci * the crq with the hypervisor.
3238c2ecf20Sopenharmony_ci * Returns zero on success.
3248c2ecf20Sopenharmony_ci */
3258c2ecf20Sopenharmony_cistatic int ibmvscsi_init_crq_queue(struct crq_queue *queue,
3268c2ecf20Sopenharmony_ci				   struct ibmvscsi_host_data *hostdata,
3278c2ecf20Sopenharmony_ci				   int max_requests)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	int rc;
3308c2ecf20Sopenharmony_ci	int retrc;
3318c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (!queue->msgs)
3368c2ecf20Sopenharmony_ci		goto malloc_failed;
3378c2ecf20Sopenharmony_ci	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	queue->msg_token = dma_map_single(hostdata->dev, queue->msgs,
3408c2ecf20Sopenharmony_ci					  queue->size * sizeof(*queue->msgs),
3418c2ecf20Sopenharmony_ci					  DMA_BIDIRECTIONAL);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (dma_mapping_error(hostdata->dev, queue->msg_token))
3448c2ecf20Sopenharmony_ci		goto map_failed;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	gather_partition_info();
3478c2ecf20Sopenharmony_ci	set_adapter_info(hostdata);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	retrc = rc = plpar_hcall_norets(H_REG_CRQ,
3508c2ecf20Sopenharmony_ci				vdev->unit_address,
3518c2ecf20Sopenharmony_ci				queue->msg_token, PAGE_SIZE);
3528c2ecf20Sopenharmony_ci	if (rc == H_RESOURCE)
3538c2ecf20Sopenharmony_ci		/* maybe kexecing and resource is busy. try a reset */
3548c2ecf20Sopenharmony_ci		rc = ibmvscsi_reset_crq_queue(queue,
3558c2ecf20Sopenharmony_ci					      hostdata);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (rc == H_CLOSED) {
3588c2ecf20Sopenharmony_ci		/* Adapter is good, but other end is not ready */
3598c2ecf20Sopenharmony_ci		dev_warn(hostdata->dev, "Partner adapter not ready\n");
3608c2ecf20Sopenharmony_ci		retrc = 0;
3618c2ecf20Sopenharmony_ci	} else if (rc != 0) {
3628c2ecf20Sopenharmony_ci		dev_warn(hostdata->dev, "Error %d opening adapter\n", rc);
3638c2ecf20Sopenharmony_ci		goto reg_crq_failed;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	queue->cur = 0;
3678c2ecf20Sopenharmony_ci	spin_lock_init(&queue->lock);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
3708c2ecf20Sopenharmony_ci		     (unsigned long)hostdata);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (request_irq(vdev->irq,
3738c2ecf20Sopenharmony_ci			ibmvscsi_handle_event,
3748c2ecf20Sopenharmony_ci			0, "ibmvscsi", (void *)hostdata) != 0) {
3758c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
3768c2ecf20Sopenharmony_ci			vdev->irq);
3778c2ecf20Sopenharmony_ci		goto req_irq_failed;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	rc = vio_enable_interrupts(vdev);
3818c2ecf20Sopenharmony_ci	if (rc != 0) {
3828c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "Error %d enabling interrupts!!!\n", rc);
3838c2ecf20Sopenharmony_ci		goto req_irq_failed;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return retrc;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci      req_irq_failed:
3898c2ecf20Sopenharmony_ci	tasklet_kill(&hostdata->srp_task);
3908c2ecf20Sopenharmony_ci	rc = 0;
3918c2ecf20Sopenharmony_ci	do {
3928c2ecf20Sopenharmony_ci		if (rc)
3938c2ecf20Sopenharmony_ci			msleep(100);
3948c2ecf20Sopenharmony_ci		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
3958c2ecf20Sopenharmony_ci	} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
3968c2ecf20Sopenharmony_ci      reg_crq_failed:
3978c2ecf20Sopenharmony_ci	dma_unmap_single(hostdata->dev,
3988c2ecf20Sopenharmony_ci			 queue->msg_token,
3998c2ecf20Sopenharmony_ci			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
4008c2ecf20Sopenharmony_ci      map_failed:
4018c2ecf20Sopenharmony_ci	free_page((unsigned long)queue->msgs);
4028c2ecf20Sopenharmony_ci      malloc_failed:
4038c2ecf20Sopenharmony_ci	return -1;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/**
4078c2ecf20Sopenharmony_ci * reenable_crq_queue: - reenables a crq after
4088c2ecf20Sopenharmony_ci * @queue:	crq_queue to initialize and register
4098c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
4108c2ecf20Sopenharmony_ci *
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_cistatic int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
4138c2ecf20Sopenharmony_ci				       struct ibmvscsi_host_data *hostdata)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	int rc = 0;
4168c2ecf20Sopenharmony_ci	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	set_adapter_info(hostdata);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/* Re-enable the CRQ */
4218c2ecf20Sopenharmony_ci	do {
4228c2ecf20Sopenharmony_ci		if (rc)
4238c2ecf20Sopenharmony_ci			msleep(100);
4248c2ecf20Sopenharmony_ci		rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
4258c2ecf20Sopenharmony_ci	} while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (rc)
4288c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "Error %d enabling adapter\n", rc);
4298c2ecf20Sopenharmony_ci	return rc;
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
4338c2ecf20Sopenharmony_ci * Routines for the event pool and event structs
4348c2ecf20Sopenharmony_ci */
4358c2ecf20Sopenharmony_ci/**
4368c2ecf20Sopenharmony_ci * initialize_event_pool: - Allocates and initializes the event pool for a host
4378c2ecf20Sopenharmony_ci * @pool:	event_pool to be initialized
4388c2ecf20Sopenharmony_ci * @size:	Number of events in pool
4398c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data who owns the event pool
4408c2ecf20Sopenharmony_ci *
4418c2ecf20Sopenharmony_ci * Returns zero on success.
4428c2ecf20Sopenharmony_ci*/
4438c2ecf20Sopenharmony_cistatic int initialize_event_pool(struct event_pool *pool,
4448c2ecf20Sopenharmony_ci				 int size, struct ibmvscsi_host_data *hostdata)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	int i;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	pool->size = size;
4498c2ecf20Sopenharmony_ci	pool->next = 0;
4508c2ecf20Sopenharmony_ci	pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL);
4518c2ecf20Sopenharmony_ci	if (!pool->events)
4528c2ecf20Sopenharmony_ci		return -ENOMEM;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	pool->iu_storage =
4558c2ecf20Sopenharmony_ci	    dma_alloc_coherent(hostdata->dev,
4568c2ecf20Sopenharmony_ci			       pool->size * sizeof(*pool->iu_storage),
4578c2ecf20Sopenharmony_ci			       &pool->iu_token, 0);
4588c2ecf20Sopenharmony_ci	if (!pool->iu_storage) {
4598c2ecf20Sopenharmony_ci		kfree(pool->events);
4608c2ecf20Sopenharmony_ci		return -ENOMEM;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	for (i = 0; i < pool->size; ++i) {
4648c2ecf20Sopenharmony_ci		struct srp_event_struct *evt = &pool->events[i];
4658c2ecf20Sopenharmony_ci		memset(&evt->crq, 0x00, sizeof(evt->crq));
4668c2ecf20Sopenharmony_ci		atomic_set(&evt->free, 1);
4678c2ecf20Sopenharmony_ci		evt->crq.valid = VIOSRP_CRQ_CMD_RSP;
4688c2ecf20Sopenharmony_ci		evt->crq.IU_length = cpu_to_be16(sizeof(*evt->xfer_iu));
4698c2ecf20Sopenharmony_ci		evt->crq.IU_data_ptr = cpu_to_be64(pool->iu_token +
4708c2ecf20Sopenharmony_ci			sizeof(*evt->xfer_iu) * i);
4718c2ecf20Sopenharmony_ci		evt->xfer_iu = pool->iu_storage + i;
4728c2ecf20Sopenharmony_ci		evt->hostdata = hostdata;
4738c2ecf20Sopenharmony_ci		evt->ext_list = NULL;
4748c2ecf20Sopenharmony_ci		evt->ext_list_token = 0;
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	return 0;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci/**
4818c2ecf20Sopenharmony_ci * release_event_pool: - Frees memory of an event pool of a host
4828c2ecf20Sopenharmony_ci * @pool:	event_pool to be released
4838c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data who owns the even pool
4848c2ecf20Sopenharmony_ci *
4858c2ecf20Sopenharmony_ci * Returns zero on success.
4868c2ecf20Sopenharmony_ci*/
4878c2ecf20Sopenharmony_cistatic void release_event_pool(struct event_pool *pool,
4888c2ecf20Sopenharmony_ci			       struct ibmvscsi_host_data *hostdata)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	int i, in_use = 0;
4918c2ecf20Sopenharmony_ci	for (i = 0; i < pool->size; ++i) {
4928c2ecf20Sopenharmony_ci		if (atomic_read(&pool->events[i].free) != 1)
4938c2ecf20Sopenharmony_ci			++in_use;
4948c2ecf20Sopenharmony_ci		if (pool->events[i].ext_list) {
4958c2ecf20Sopenharmony_ci			dma_free_coherent(hostdata->dev,
4968c2ecf20Sopenharmony_ci				  SG_ALL * sizeof(struct srp_direct_buf),
4978c2ecf20Sopenharmony_ci				  pool->events[i].ext_list,
4988c2ecf20Sopenharmony_ci				  pool->events[i].ext_list_token);
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci	if (in_use)
5028c2ecf20Sopenharmony_ci		dev_warn(hostdata->dev, "releasing event pool with %d "
5038c2ecf20Sopenharmony_ci			 "events still in use?\n", in_use);
5048c2ecf20Sopenharmony_ci	kfree(pool->events);
5058c2ecf20Sopenharmony_ci	dma_free_coherent(hostdata->dev,
5068c2ecf20Sopenharmony_ci			  pool->size * sizeof(*pool->iu_storage),
5078c2ecf20Sopenharmony_ci			  pool->iu_storage, pool->iu_token);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/**
5118c2ecf20Sopenharmony_ci * valid_event_struct: - Determines if event is valid.
5128c2ecf20Sopenharmony_ci * @pool:	event_pool that contains the event
5138c2ecf20Sopenharmony_ci * @evt:	srp_event_struct to be checked for validity
5148c2ecf20Sopenharmony_ci *
5158c2ecf20Sopenharmony_ci * Returns zero if event is invalid, one otherwise.
5168c2ecf20Sopenharmony_ci*/
5178c2ecf20Sopenharmony_cistatic int valid_event_struct(struct event_pool *pool,
5188c2ecf20Sopenharmony_ci				struct srp_event_struct *evt)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	int index = evt - pool->events;
5218c2ecf20Sopenharmony_ci	if (index < 0 || index >= pool->size)	/* outside of bounds */
5228c2ecf20Sopenharmony_ci		return 0;
5238c2ecf20Sopenharmony_ci	if (evt != pool->events + index)	/* unaligned */
5248c2ecf20Sopenharmony_ci		return 0;
5258c2ecf20Sopenharmony_ci	return 1;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/**
5298c2ecf20Sopenharmony_ci * ibmvscsi_free-event_struct: - Changes status of event to "free"
5308c2ecf20Sopenharmony_ci * @pool:	event_pool that contains the event
5318c2ecf20Sopenharmony_ci * @evt:	srp_event_struct to be modified
5328c2ecf20Sopenharmony_ci *
5338c2ecf20Sopenharmony_ci*/
5348c2ecf20Sopenharmony_cistatic void free_event_struct(struct event_pool *pool,
5358c2ecf20Sopenharmony_ci				       struct srp_event_struct *evt)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	if (!valid_event_struct(pool, evt)) {
5388c2ecf20Sopenharmony_ci		dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p "
5398c2ecf20Sopenharmony_ci			"(not in pool %p)\n", evt, pool->events);
5408c2ecf20Sopenharmony_ci		return;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci	if (atomic_inc_return(&evt->free) != 1) {
5438c2ecf20Sopenharmony_ci		dev_err(evt->hostdata->dev, "Freeing event_struct %p "
5448c2ecf20Sopenharmony_ci			"which is not in use!\n", evt);
5458c2ecf20Sopenharmony_ci		return;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci/**
5508c2ecf20Sopenharmony_ci * get_evt_struct: - Gets the next free event in pool
5518c2ecf20Sopenharmony_ci * @pool:	event_pool that contains the events to be searched
5528c2ecf20Sopenharmony_ci *
5538c2ecf20Sopenharmony_ci * Returns the next event in "free" state, and NULL if none are free.
5548c2ecf20Sopenharmony_ci * Note that no synchronization is done here, we assume the host_lock
5558c2ecf20Sopenharmony_ci * will syncrhonze things.
5568c2ecf20Sopenharmony_ci*/
5578c2ecf20Sopenharmony_cistatic struct srp_event_struct *get_event_struct(struct event_pool *pool)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	int i;
5608c2ecf20Sopenharmony_ci	int poolsize = pool->size;
5618c2ecf20Sopenharmony_ci	int offset = pool->next;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	for (i = 0; i < poolsize; i++) {
5648c2ecf20Sopenharmony_ci		offset = (offset + 1) % poolsize;
5658c2ecf20Sopenharmony_ci		if (!atomic_dec_if_positive(&pool->events[offset].free)) {
5668c2ecf20Sopenharmony_ci			pool->next = offset;
5678c2ecf20Sopenharmony_ci			return &pool->events[offset];
5688c2ecf20Sopenharmony_ci		}
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n");
5728c2ecf20Sopenharmony_ci	return NULL;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci/**
5768c2ecf20Sopenharmony_ci * init_event_struct: Initialize fields in an event struct that are always
5778c2ecf20Sopenharmony_ci *                    required.
5788c2ecf20Sopenharmony_ci * @evt:        The event
5798c2ecf20Sopenharmony_ci * @done:       Routine to call when the event is responded to
5808c2ecf20Sopenharmony_ci * @format:     SRP or MAD format
5818c2ecf20Sopenharmony_ci * @timeout:    timeout value set in the CRQ
5828c2ecf20Sopenharmony_ci */
5838c2ecf20Sopenharmony_cistatic void init_event_struct(struct srp_event_struct *evt_struct,
5848c2ecf20Sopenharmony_ci			      void (*done) (struct srp_event_struct *),
5858c2ecf20Sopenharmony_ci			      u8 format,
5868c2ecf20Sopenharmony_ci			      int timeout)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	evt_struct->cmnd = NULL;
5898c2ecf20Sopenharmony_ci	evt_struct->cmnd_done = NULL;
5908c2ecf20Sopenharmony_ci	evt_struct->sync_srp = NULL;
5918c2ecf20Sopenharmony_ci	evt_struct->crq.format = format;
5928c2ecf20Sopenharmony_ci	evt_struct->crq.timeout = cpu_to_be16(timeout);
5938c2ecf20Sopenharmony_ci	evt_struct->done = done;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
5978c2ecf20Sopenharmony_ci * Routines for receiving SCSI responses from the hosting partition
5988c2ecf20Sopenharmony_ci */
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci/**
6018c2ecf20Sopenharmony_ci * set_srp_direction: Set the fields in the srp related to data
6028c2ecf20Sopenharmony_ci *     direction and number of buffers based on the direction in
6038c2ecf20Sopenharmony_ci *     the scsi_cmnd and the number of buffers
6048c2ecf20Sopenharmony_ci */
6058c2ecf20Sopenharmony_cistatic void set_srp_direction(struct scsi_cmnd *cmd,
6068c2ecf20Sopenharmony_ci			      struct srp_cmd *srp_cmd,
6078c2ecf20Sopenharmony_ci			      int numbuf)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	u8 fmt;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (numbuf == 0)
6128c2ecf20Sopenharmony_ci		return;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (numbuf == 1)
6158c2ecf20Sopenharmony_ci		fmt = SRP_DATA_DESC_DIRECT;
6168c2ecf20Sopenharmony_ci	else {
6178c2ecf20Sopenharmony_ci		fmt = SRP_DATA_DESC_INDIRECT;
6188c2ecf20Sopenharmony_ci		numbuf = min(numbuf, MAX_INDIRECT_BUFS);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci		if (cmd->sc_data_direction == DMA_TO_DEVICE)
6218c2ecf20Sopenharmony_ci			srp_cmd->data_out_desc_cnt = numbuf;
6228c2ecf20Sopenharmony_ci		else
6238c2ecf20Sopenharmony_ci			srp_cmd->data_in_desc_cnt = numbuf;
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (cmd->sc_data_direction == DMA_TO_DEVICE)
6278c2ecf20Sopenharmony_ci		srp_cmd->buf_fmt = fmt << 4;
6288c2ecf20Sopenharmony_ci	else
6298c2ecf20Sopenharmony_ci		srp_cmd->buf_fmt = fmt;
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci/**
6338c2ecf20Sopenharmony_ci * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
6348c2ecf20Sopenharmony_ci * @cmd:	srp_cmd whose additional_data member will be unmapped
6358c2ecf20Sopenharmony_ci * @dev:	device for which the memory is mapped
6368c2ecf20Sopenharmony_ci *
6378c2ecf20Sopenharmony_ci*/
6388c2ecf20Sopenharmony_cistatic void unmap_cmd_data(struct srp_cmd *cmd,
6398c2ecf20Sopenharmony_ci			   struct srp_event_struct *evt_struct,
6408c2ecf20Sopenharmony_ci			   struct device *dev)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	u8 out_fmt, in_fmt;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	out_fmt = cmd->buf_fmt >> 4;
6458c2ecf20Sopenharmony_ci	in_fmt = cmd->buf_fmt & ((1U << 4) - 1);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC)
6488c2ecf20Sopenharmony_ci		return;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (evt_struct->cmnd)
6518c2ecf20Sopenharmony_ci		scsi_dma_unmap(evt_struct->cmnd);
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic int map_sg_list(struct scsi_cmnd *cmd, int nseg,
6558c2ecf20Sopenharmony_ci		       struct srp_direct_buf *md)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	int i;
6588c2ecf20Sopenharmony_ci	struct scatterlist *sg;
6598c2ecf20Sopenharmony_ci	u64 total_length = 0;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	scsi_for_each_sg(cmd, sg, nseg, i) {
6628c2ecf20Sopenharmony_ci		struct srp_direct_buf *descr = md + i;
6638c2ecf20Sopenharmony_ci		descr->va = cpu_to_be64(sg_dma_address(sg));
6648c2ecf20Sopenharmony_ci		descr->len = cpu_to_be32(sg_dma_len(sg));
6658c2ecf20Sopenharmony_ci		descr->key = 0;
6668c2ecf20Sopenharmony_ci		total_length += sg_dma_len(sg);
6678c2ecf20Sopenharmony_ci 	}
6688c2ecf20Sopenharmony_ci	return total_length;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci/**
6728c2ecf20Sopenharmony_ci * map_sg_data: - Maps dma for a scatterlist and initializes descriptor fields
6738c2ecf20Sopenharmony_ci * @cmd:	struct scsi_cmnd with the scatterlist
6748c2ecf20Sopenharmony_ci * @srp_cmd:	srp_cmd that contains the memory descriptor
6758c2ecf20Sopenharmony_ci * @dev:	device for which to map dma memory
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
6788c2ecf20Sopenharmony_ci * Returns 1 on success.
6798c2ecf20Sopenharmony_ci*/
6808c2ecf20Sopenharmony_cistatic int map_sg_data(struct scsi_cmnd *cmd,
6818c2ecf20Sopenharmony_ci		       struct srp_event_struct *evt_struct,
6828c2ecf20Sopenharmony_ci		       struct srp_cmd *srp_cmd, struct device *dev)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	int sg_mapped;
6868c2ecf20Sopenharmony_ci	u64 total_length = 0;
6878c2ecf20Sopenharmony_ci	struct srp_direct_buf *data =
6888c2ecf20Sopenharmony_ci		(struct srp_direct_buf *) srp_cmd->add_data;
6898c2ecf20Sopenharmony_ci	struct srp_indirect_buf *indirect =
6908c2ecf20Sopenharmony_ci		(struct srp_indirect_buf *) data;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	sg_mapped = scsi_dma_map(cmd);
6938c2ecf20Sopenharmony_ci	if (!sg_mapped)
6948c2ecf20Sopenharmony_ci		return 1;
6958c2ecf20Sopenharmony_ci	else if (sg_mapped < 0)
6968c2ecf20Sopenharmony_ci		return 0;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	set_srp_direction(cmd, srp_cmd, sg_mapped);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* special case; we can use a single direct descriptor */
7018c2ecf20Sopenharmony_ci	if (sg_mapped == 1) {
7028c2ecf20Sopenharmony_ci		map_sg_list(cmd, sg_mapped, data);
7038c2ecf20Sopenharmony_ci		return 1;
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	indirect->table_desc.va = 0;
7078c2ecf20Sopenharmony_ci	indirect->table_desc.len = cpu_to_be32(sg_mapped *
7088c2ecf20Sopenharmony_ci					       sizeof(struct srp_direct_buf));
7098c2ecf20Sopenharmony_ci	indirect->table_desc.key = 0;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (sg_mapped <= MAX_INDIRECT_BUFS) {
7128c2ecf20Sopenharmony_ci		total_length = map_sg_list(cmd, sg_mapped,
7138c2ecf20Sopenharmony_ci					   &indirect->desc_list[0]);
7148c2ecf20Sopenharmony_ci		indirect->len = cpu_to_be32(total_length);
7158c2ecf20Sopenharmony_ci		return 1;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	/* get indirect table */
7198c2ecf20Sopenharmony_ci	if (!evt_struct->ext_list) {
7208c2ecf20Sopenharmony_ci		evt_struct->ext_list = (struct srp_direct_buf *)
7218c2ecf20Sopenharmony_ci			dma_alloc_coherent(dev,
7228c2ecf20Sopenharmony_ci					   SG_ALL * sizeof(struct srp_direct_buf),
7238c2ecf20Sopenharmony_ci					   &evt_struct->ext_list_token, 0);
7248c2ecf20Sopenharmony_ci		if (!evt_struct->ext_list) {
7258c2ecf20Sopenharmony_ci			if (!firmware_has_feature(FW_FEATURE_CMO))
7268c2ecf20Sopenharmony_ci				sdev_printk(KERN_ERR, cmd->device,
7278c2ecf20Sopenharmony_ci				            "Can't allocate memory "
7288c2ecf20Sopenharmony_ci				            "for indirect table\n");
7298c2ecf20Sopenharmony_ci			scsi_dma_unmap(cmd);
7308c2ecf20Sopenharmony_ci			return 0;
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	indirect->len = cpu_to_be32(total_length);
7378c2ecf20Sopenharmony_ci	indirect->table_desc.va = cpu_to_be64(evt_struct->ext_list_token);
7388c2ecf20Sopenharmony_ci	indirect->table_desc.len = cpu_to_be32(sg_mapped *
7398c2ecf20Sopenharmony_ci					       sizeof(indirect->desc_list[0]));
7408c2ecf20Sopenharmony_ci	memcpy(indirect->desc_list, evt_struct->ext_list,
7418c2ecf20Sopenharmony_ci	       MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
7428c2ecf20Sopenharmony_ci 	return 1;
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci/**
7468c2ecf20Sopenharmony_ci * map_data_for_srp_cmd: - Calls functions to map data for srp cmds
7478c2ecf20Sopenharmony_ci * @cmd:	struct scsi_cmnd with the memory to be mapped
7488c2ecf20Sopenharmony_ci * @srp_cmd:	srp_cmd that contains the memory descriptor
7498c2ecf20Sopenharmony_ci * @dev:	dma device for which to map dma memory
7508c2ecf20Sopenharmony_ci *
7518c2ecf20Sopenharmony_ci * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds
7528c2ecf20Sopenharmony_ci * Returns 1 on success.
7538c2ecf20Sopenharmony_ci*/
7548c2ecf20Sopenharmony_cistatic int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
7558c2ecf20Sopenharmony_ci				struct srp_event_struct *evt_struct,
7568c2ecf20Sopenharmony_ci				struct srp_cmd *srp_cmd, struct device *dev)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	switch (cmd->sc_data_direction) {
7598c2ecf20Sopenharmony_ci	case DMA_FROM_DEVICE:
7608c2ecf20Sopenharmony_ci	case DMA_TO_DEVICE:
7618c2ecf20Sopenharmony_ci		break;
7628c2ecf20Sopenharmony_ci	case DMA_NONE:
7638c2ecf20Sopenharmony_ci		return 1;
7648c2ecf20Sopenharmony_ci	case DMA_BIDIRECTIONAL:
7658c2ecf20Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
7668c2ecf20Sopenharmony_ci			    "Can't map DMA_BIDIRECTIONAL to read/write\n");
7678c2ecf20Sopenharmony_ci		return 0;
7688c2ecf20Sopenharmony_ci	default:
7698c2ecf20Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
7708c2ecf20Sopenharmony_ci			    "Unknown data direction 0x%02x; can't map!\n",
7718c2ecf20Sopenharmony_ci			    cmd->sc_data_direction);
7728c2ecf20Sopenharmony_ci		return 0;
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	return map_sg_data(cmd, evt_struct, srp_cmd, dev);
7768c2ecf20Sopenharmony_ci}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci/**
7798c2ecf20Sopenharmony_ci * purge_requests: Our virtual adapter just shut down.  purge any sent requests
7808c2ecf20Sopenharmony_ci * @hostdata:    the adapter
7818c2ecf20Sopenharmony_ci */
7828c2ecf20Sopenharmony_cistatic void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	struct srp_event_struct *evt;
7858c2ecf20Sopenharmony_ci	unsigned long flags;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
7888c2ecf20Sopenharmony_ci	while (!list_empty(&hostdata->sent)) {
7898c2ecf20Sopenharmony_ci		evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
7908c2ecf20Sopenharmony_ci		list_del(&evt->list);
7918c2ecf20Sopenharmony_ci		del_timer(&evt->timer);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
7948c2ecf20Sopenharmony_ci		if (evt->cmnd) {
7958c2ecf20Sopenharmony_ci			evt->cmnd->result = (error_code << 16);
7968c2ecf20Sopenharmony_ci			unmap_cmd_data(&evt->iu.srp.cmd, evt,
7978c2ecf20Sopenharmony_ci				       evt->hostdata->dev);
7988c2ecf20Sopenharmony_ci			if (evt->cmnd_done)
7998c2ecf20Sopenharmony_ci				evt->cmnd_done(evt->cmnd);
8008c2ecf20Sopenharmony_ci		} else if (evt->done && evt->crq.format != VIOSRP_MAD_FORMAT &&
8018c2ecf20Sopenharmony_ci			   evt->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
8028c2ecf20Sopenharmony_ci			evt->done(evt);
8038c2ecf20Sopenharmony_ci		free_event_struct(&evt->hostdata->pool, evt);
8048c2ecf20Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci/**
8108c2ecf20Sopenharmony_ci * ibmvscsi_set_request_limit - Set the adapter request_limit in response to
8118c2ecf20Sopenharmony_ci * an adapter failure, reset, or SRP Login. Done under host lock to prevent
8128c2ecf20Sopenharmony_ci * race with SCSI command submission.
8138c2ecf20Sopenharmony_ci * @hostdata:	adapter to adjust
8148c2ecf20Sopenharmony_ci * @limit:	new request limit
8158c2ecf20Sopenharmony_ci */
8168c2ecf20Sopenharmony_cistatic void ibmvscsi_set_request_limit(struct ibmvscsi_host_data *hostdata, int limit)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	unsigned long flags;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
8218c2ecf20Sopenharmony_ci	atomic_set(&hostdata->request_limit, limit);
8228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci/**
8268c2ecf20Sopenharmony_ci * ibmvscsi_reset_host - Reset the connection to the server
8278c2ecf20Sopenharmony_ci * @hostdata:	struct ibmvscsi_host_data to reset
8288c2ecf20Sopenharmony_ci*/
8298c2ecf20Sopenharmony_cistatic void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	scsi_block_requests(hostdata->host);
8328c2ecf20Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata, 0);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	purge_requests(hostdata, DID_ERROR);
8358c2ecf20Sopenharmony_ci	hostdata->action = IBMVSCSI_HOST_ACTION_RESET;
8368c2ecf20Sopenharmony_ci	wake_up(&hostdata->work_wait_q);
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci/**
8408c2ecf20Sopenharmony_ci * ibmvscsi_timeout - Internal command timeout handler
8418c2ecf20Sopenharmony_ci * @evt_struct:	struct srp_event_struct that timed out
8428c2ecf20Sopenharmony_ci *
8438c2ecf20Sopenharmony_ci * Called when an internally generated command times out
8448c2ecf20Sopenharmony_ci*/
8458c2ecf20Sopenharmony_cistatic void ibmvscsi_timeout(struct timer_list *t)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct srp_event_struct *evt_struct = from_timer(evt_struct, t, timer);
8488c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
8518c2ecf20Sopenharmony_ci		evt_struct->iu.srp.cmd.opcode);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	ibmvscsi_reset_host(hostdata);
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
8588c2ecf20Sopenharmony_ci * Routines for sending and receiving SRPs
8598c2ecf20Sopenharmony_ci */
8608c2ecf20Sopenharmony_ci/**
8618c2ecf20Sopenharmony_ci * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
8628c2ecf20Sopenharmony_ci * @evt_struct:	evt_struct to be sent
8638c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
8648c2ecf20Sopenharmony_ci * @timeout:	timeout in seconds - 0 means do not time command
8658c2ecf20Sopenharmony_ci *
8668c2ecf20Sopenharmony_ci * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
8678c2ecf20Sopenharmony_ci * Note that this routine assumes that host_lock is held for synchronization
8688c2ecf20Sopenharmony_ci*/
8698c2ecf20Sopenharmony_cistatic int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
8708c2ecf20Sopenharmony_ci				   struct ibmvscsi_host_data *hostdata,
8718c2ecf20Sopenharmony_ci				   unsigned long timeout)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	__be64 *crq_as_u64 = (__be64 *)&evt_struct->crq;
8748c2ecf20Sopenharmony_ci	int request_status = 0;
8758c2ecf20Sopenharmony_ci	int rc;
8768c2ecf20Sopenharmony_ci	int srp_req = 0;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	/* If we have exhausted our request limit, just fail this request,
8798c2ecf20Sopenharmony_ci	 * unless it is for a reset or abort.
8808c2ecf20Sopenharmony_ci	 * Note that there are rare cases involving driver generated requests
8818c2ecf20Sopenharmony_ci	 * (such as task management requests) that the mid layer may think we
8828c2ecf20Sopenharmony_ci	 * can handle more requests (can_queue) when we actually can't
8838c2ecf20Sopenharmony_ci	 */
8848c2ecf20Sopenharmony_ci	if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
8858c2ecf20Sopenharmony_ci		srp_req = 1;
8868c2ecf20Sopenharmony_ci		request_status =
8878c2ecf20Sopenharmony_ci			atomic_dec_if_positive(&hostdata->request_limit);
8888c2ecf20Sopenharmony_ci		/* If request limit was -1 when we started, it is now even
8898c2ecf20Sopenharmony_ci		 * less than that
8908c2ecf20Sopenharmony_ci		 */
8918c2ecf20Sopenharmony_ci		if (request_status < -1)
8928c2ecf20Sopenharmony_ci			goto send_error;
8938c2ecf20Sopenharmony_ci		/* Otherwise, we may have run out of requests. */
8948c2ecf20Sopenharmony_ci		/* If request limit was 0 when we started the adapter is in the
8958c2ecf20Sopenharmony_ci		 * process of performing a login with the server adapter, or
8968c2ecf20Sopenharmony_ci		 * we may have run out of requests.
8978c2ecf20Sopenharmony_ci		 */
8988c2ecf20Sopenharmony_ci		else if (request_status == -1 &&
8998c2ecf20Sopenharmony_ci		         evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
9008c2ecf20Sopenharmony_ci			goto send_busy;
9018c2ecf20Sopenharmony_ci		/* Abort and reset calls should make it through.
9028c2ecf20Sopenharmony_ci		 * Nothing except abort and reset should use the last two
9038c2ecf20Sopenharmony_ci		 * slots unless we had two or less to begin with.
9048c2ecf20Sopenharmony_ci		 */
9058c2ecf20Sopenharmony_ci		else if (request_status < 2 &&
9068c2ecf20Sopenharmony_ci		         evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
9078c2ecf20Sopenharmony_ci			/* In the case that we have less than two requests
9088c2ecf20Sopenharmony_ci			 * available, check the server limit as a combination
9098c2ecf20Sopenharmony_ci			 * of the request limit and the number of requests
9108c2ecf20Sopenharmony_ci			 * in-flight (the size of the send list).  If the
9118c2ecf20Sopenharmony_ci			 * server limit is greater than 2, return busy so
9128c2ecf20Sopenharmony_ci			 * that the last two are reserved for reset and abort.
9138c2ecf20Sopenharmony_ci			 */
9148c2ecf20Sopenharmony_ci			int server_limit = request_status;
9158c2ecf20Sopenharmony_ci			struct srp_event_struct *tmp_evt;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci			list_for_each_entry(tmp_evt, &hostdata->sent, list) {
9188c2ecf20Sopenharmony_ci				server_limit++;
9198c2ecf20Sopenharmony_ci			}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci			if (server_limit > 2)
9228c2ecf20Sopenharmony_ci				goto send_busy;
9238c2ecf20Sopenharmony_ci		}
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	/* Copy the IU into the transfer area */
9278c2ecf20Sopenharmony_ci	*evt_struct->xfer_iu = evt_struct->iu;
9288c2ecf20Sopenharmony_ci	evt_struct->xfer_iu->srp.rsp.tag = (u64)evt_struct;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	/* Add this to the sent list.  We need to do this
9318c2ecf20Sopenharmony_ci	 * before we actually send
9328c2ecf20Sopenharmony_ci	 * in case it comes back REALLY fast
9338c2ecf20Sopenharmony_ci	 */
9348c2ecf20Sopenharmony_ci	list_add_tail(&evt_struct->list, &hostdata->sent);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	timer_setup(&evt_struct->timer, ibmvscsi_timeout, 0);
9378c2ecf20Sopenharmony_ci	if (timeout) {
9388c2ecf20Sopenharmony_ci		evt_struct->timer.expires = jiffies + (timeout * HZ);
9398c2ecf20Sopenharmony_ci		add_timer(&evt_struct->timer);
9408c2ecf20Sopenharmony_ci	}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	rc = ibmvscsi_send_crq(hostdata, be64_to_cpu(crq_as_u64[0]),
9438c2ecf20Sopenharmony_ci			       be64_to_cpu(crq_as_u64[1]));
9448c2ecf20Sopenharmony_ci	if (rc != 0) {
9458c2ecf20Sopenharmony_ci		list_del(&evt_struct->list);
9468c2ecf20Sopenharmony_ci		del_timer(&evt_struct->timer);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
9498c2ecf20Sopenharmony_ci		 * Firmware will send a CRQ with a transport event (0xFF) to
9508c2ecf20Sopenharmony_ci		 * tell this client what has happened to the transport.  This
9518c2ecf20Sopenharmony_ci		 * will be handled in ibmvscsi_handle_crq()
9528c2ecf20Sopenharmony_ci		 */
9538c2ecf20Sopenharmony_ci		if (rc == H_CLOSED) {
9548c2ecf20Sopenharmony_ci			dev_warn(hostdata->dev, "send warning. "
9558c2ecf20Sopenharmony_ci			         "Receive queue closed, will retry.\n");
9568c2ecf20Sopenharmony_ci			goto send_busy;
9578c2ecf20Sopenharmony_ci		}
9588c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "send error %d\n", rc);
9598c2ecf20Sopenharmony_ci		if (srp_req)
9608c2ecf20Sopenharmony_ci			atomic_inc(&hostdata->request_limit);
9618c2ecf20Sopenharmony_ci		goto send_error;
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	return 0;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci send_busy:
9678c2ecf20Sopenharmony_ci	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	free_event_struct(&hostdata->pool, evt_struct);
9708c2ecf20Sopenharmony_ci	if (srp_req && request_status != -1)
9718c2ecf20Sopenharmony_ci		atomic_inc(&hostdata->request_limit);
9728c2ecf20Sopenharmony_ci	return SCSI_MLQUEUE_HOST_BUSY;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci send_error:
9758c2ecf20Sopenharmony_ci	unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	if (evt_struct->cmnd != NULL) {
9788c2ecf20Sopenharmony_ci		evt_struct->cmnd->result = DID_ERROR << 16;
9798c2ecf20Sopenharmony_ci		evt_struct->cmnd_done(evt_struct->cmnd);
9808c2ecf20Sopenharmony_ci	} else if (evt_struct->done)
9818c2ecf20Sopenharmony_ci		evt_struct->done(evt_struct);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	free_event_struct(&hostdata->pool, evt_struct);
9848c2ecf20Sopenharmony_ci	return 0;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci/**
9888c2ecf20Sopenharmony_ci * handle_cmd_rsp: -  Handle responses from commands
9898c2ecf20Sopenharmony_ci * @evt_struct:	srp_event_struct to be handled
9908c2ecf20Sopenharmony_ci *
9918c2ecf20Sopenharmony_ci * Used as a callback by when sending scsi cmds.
9928c2ecf20Sopenharmony_ci * Gets called by ibmvscsi_handle_crq()
9938c2ecf20Sopenharmony_ci*/
9948c2ecf20Sopenharmony_cistatic void handle_cmd_rsp(struct srp_event_struct *evt_struct)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
9978c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmnd = evt_struct->cmnd;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	if (unlikely(rsp->opcode != SRP_RSP)) {
10008c2ecf20Sopenharmony_ci		if (printk_ratelimit())
10018c2ecf20Sopenharmony_ci			dev_warn(evt_struct->hostdata->dev,
10028c2ecf20Sopenharmony_ci				 "bad SRP RSP type %#02x\n", rsp->opcode);
10038c2ecf20Sopenharmony_ci	}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (cmnd) {
10068c2ecf20Sopenharmony_ci		cmnd->result |= rsp->status;
10078c2ecf20Sopenharmony_ci		if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
10088c2ecf20Sopenharmony_ci			memcpy(cmnd->sense_buffer,
10098c2ecf20Sopenharmony_ci			       rsp->data,
10108c2ecf20Sopenharmony_ci			       be32_to_cpu(rsp->sense_data_len));
10118c2ecf20Sopenharmony_ci		unmap_cmd_data(&evt_struct->iu.srp.cmd,
10128c2ecf20Sopenharmony_ci			       evt_struct,
10138c2ecf20Sopenharmony_ci			       evt_struct->hostdata->dev);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci		if (rsp->flags & SRP_RSP_FLAG_DOOVER)
10168c2ecf20Sopenharmony_ci			scsi_set_resid(cmnd,
10178c2ecf20Sopenharmony_ci				       be32_to_cpu(rsp->data_out_res_cnt));
10188c2ecf20Sopenharmony_ci		else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
10198c2ecf20Sopenharmony_ci			scsi_set_resid(cmnd, be32_to_cpu(rsp->data_in_res_cnt));
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	if (evt_struct->cmnd_done)
10238c2ecf20Sopenharmony_ci		evt_struct->cmnd_done(cmnd);
10248c2ecf20Sopenharmony_ci}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci/**
10278c2ecf20Sopenharmony_ci * lun_from_dev: - Returns the lun of the scsi device
10288c2ecf20Sopenharmony_ci * @dev:	struct scsi_device
10298c2ecf20Sopenharmony_ci *
10308c2ecf20Sopenharmony_ci*/
10318c2ecf20Sopenharmony_cistatic inline u16 lun_from_dev(struct scsi_device *dev)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun;
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci/**
10378c2ecf20Sopenharmony_ci * ibmvscsi_queue: - The queuecommand function of the scsi template
10388c2ecf20Sopenharmony_ci * @cmd:	struct scsi_cmnd to be executed
10398c2ecf20Sopenharmony_ci * @done:	Callback function to be called when cmd is completed
10408c2ecf20Sopenharmony_ci*/
10418c2ecf20Sopenharmony_cistatic int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
10428c2ecf20Sopenharmony_ci				 void (*done) (struct scsi_cmnd *))
10438c2ecf20Sopenharmony_ci{
10448c2ecf20Sopenharmony_ci	struct srp_cmd *srp_cmd;
10458c2ecf20Sopenharmony_ci	struct srp_event_struct *evt_struct;
10468c2ecf20Sopenharmony_ci	struct srp_indirect_buf *indirect;
10478c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host);
10488c2ecf20Sopenharmony_ci	u16 lun = lun_from_dev(cmnd->device);
10498c2ecf20Sopenharmony_ci	u8 out_fmt, in_fmt;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	cmnd->result = (DID_OK << 16);
10528c2ecf20Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
10538c2ecf20Sopenharmony_ci	if (!evt_struct)
10548c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	/* Set up the actual SRP IU */
10578c2ecf20Sopenharmony_ci	srp_cmd = &evt_struct->iu.srp.cmd;
10588c2ecf20Sopenharmony_ci	memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
10598c2ecf20Sopenharmony_ci	srp_cmd->opcode = SRP_CMD;
10608c2ecf20Sopenharmony_ci	memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
10618c2ecf20Sopenharmony_ci	int_to_scsilun(lun, &srp_cmd->lun);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
10648c2ecf20Sopenharmony_ci		if (!firmware_has_feature(FW_FEATURE_CMO))
10658c2ecf20Sopenharmony_ci			sdev_printk(KERN_ERR, cmnd->device,
10668c2ecf20Sopenharmony_ci			            "couldn't convert cmd to srp_cmd\n");
10678c2ecf20Sopenharmony_ci		free_event_struct(&hostdata->pool, evt_struct);
10688c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	init_event_struct(evt_struct,
10728c2ecf20Sopenharmony_ci			  handle_cmd_rsp,
10738c2ecf20Sopenharmony_ci			  VIOSRP_SRP_FORMAT,
10748c2ecf20Sopenharmony_ci			  cmnd->request->timeout/HZ);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	evt_struct->cmnd = cmnd;
10778c2ecf20Sopenharmony_ci	evt_struct->cmnd_done = done;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	/* Fix up dma address of the buffer itself */
10808c2ecf20Sopenharmony_ci	indirect = (struct srp_indirect_buf *) srp_cmd->add_data;
10818c2ecf20Sopenharmony_ci	out_fmt = srp_cmd->buf_fmt >> 4;
10828c2ecf20Sopenharmony_ci	in_fmt = srp_cmd->buf_fmt & ((1U << 4) - 1);
10838c2ecf20Sopenharmony_ci	if ((in_fmt == SRP_DATA_DESC_INDIRECT ||
10848c2ecf20Sopenharmony_ci	     out_fmt == SRP_DATA_DESC_INDIRECT) &&
10858c2ecf20Sopenharmony_ci	    indirect->table_desc.va == 0) {
10868c2ecf20Sopenharmony_ci		indirect->table_desc.va =
10878c2ecf20Sopenharmony_ci			cpu_to_be64(be64_to_cpu(evt_struct->crq.IU_data_ptr) +
10888c2ecf20Sopenharmony_ci			offsetof(struct srp_cmd, add_data) +
10898c2ecf20Sopenharmony_ci			offsetof(struct srp_indirect_buf, desc_list));
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(ibmvscsi_queuecommand)
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
10988c2ecf20Sopenharmony_ci * Routines for driver initialization
10998c2ecf20Sopenharmony_ci */
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci/**
11028c2ecf20Sopenharmony_ci * map_persist_bufs: - Pre-map persistent data for adapter logins
11038c2ecf20Sopenharmony_ci * @hostdata:   ibmvscsi_host_data of host
11048c2ecf20Sopenharmony_ci *
11058c2ecf20Sopenharmony_ci * Map the capabilities and adapter info DMA buffers to avoid runtime failures.
11068c2ecf20Sopenharmony_ci * Return 1 on error, 0 on success.
11078c2ecf20Sopenharmony_ci */
11088c2ecf20Sopenharmony_cistatic int map_persist_bufs(struct ibmvscsi_host_data *hostdata)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps,
11128c2ecf20Sopenharmony_ci					     sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) {
11158c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "Unable to map capabilities buffer!\n");
11168c2ecf20Sopenharmony_ci		return 1;
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	hostdata->adapter_info_addr = dma_map_single(hostdata->dev,
11208c2ecf20Sopenharmony_ci						     &hostdata->madapter_info,
11218c2ecf20Sopenharmony_ci						     sizeof(hostdata->madapter_info),
11228c2ecf20Sopenharmony_ci						     DMA_BIDIRECTIONAL);
11238c2ecf20Sopenharmony_ci	if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) {
11248c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "Unable to map adapter info buffer!\n");
11258c2ecf20Sopenharmony_ci		dma_unmap_single(hostdata->dev, hostdata->caps_addr,
11268c2ecf20Sopenharmony_ci				 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
11278c2ecf20Sopenharmony_ci		return 1;
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	return 0;
11318c2ecf20Sopenharmony_ci}
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci/**
11348c2ecf20Sopenharmony_ci * unmap_persist_bufs: - Unmap persistent data needed for adapter logins
11358c2ecf20Sopenharmony_ci * @hostdata:   ibmvscsi_host_data of host
11368c2ecf20Sopenharmony_ci *
11378c2ecf20Sopenharmony_ci * Unmap the capabilities and adapter info DMA buffers
11388c2ecf20Sopenharmony_ci */
11398c2ecf20Sopenharmony_cistatic void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	dma_unmap_single(hostdata->dev, hostdata->caps_addr,
11428c2ecf20Sopenharmony_ci			 sizeof(hostdata->caps), DMA_BIDIRECTIONAL);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr,
11458c2ecf20Sopenharmony_ci			 sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL);
11468c2ecf20Sopenharmony_ci}
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci/**
11498c2ecf20Sopenharmony_ci * login_rsp: - Handle response to SRP login request
11508c2ecf20Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
11518c2ecf20Sopenharmony_ci *
11528c2ecf20Sopenharmony_ci * Used as a "done" callback by when sending srp_login. Gets called
11538c2ecf20Sopenharmony_ci * by ibmvscsi_handle_crq()
11548c2ecf20Sopenharmony_ci*/
11558c2ecf20Sopenharmony_cistatic void login_rsp(struct srp_event_struct *evt_struct)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
11588c2ecf20Sopenharmony_ci	switch (evt_struct->xfer_iu->srp.login_rsp.opcode) {
11598c2ecf20Sopenharmony_ci	case SRP_LOGIN_RSP:	/* it worked! */
11608c2ecf20Sopenharmony_ci		break;
11618c2ecf20Sopenharmony_ci	case SRP_LOGIN_REJ:	/* refused! */
11628c2ecf20Sopenharmony_ci		dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
11638c2ecf20Sopenharmony_ci			 evt_struct->xfer_iu->srp.login_rej.reason);
11648c2ecf20Sopenharmony_ci		/* Login failed.  */
11658c2ecf20Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, -1);
11668c2ecf20Sopenharmony_ci		return;
11678c2ecf20Sopenharmony_ci	default:
11688c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
11698c2ecf20Sopenharmony_ci			evt_struct->xfer_iu->srp.login_rsp.opcode);
11708c2ecf20Sopenharmony_ci		/* Login failed.  */
11718c2ecf20Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, -1);
11728c2ecf20Sopenharmony_ci		return;
11738c2ecf20Sopenharmony_ci	}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
11768c2ecf20Sopenharmony_ci	hostdata->client_migrated = 0;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	/* Now we know what the real request-limit is.
11798c2ecf20Sopenharmony_ci	 * This value is set rather than added to request_limit because
11808c2ecf20Sopenharmony_ci	 * request_limit could have been set to -1 by this client.
11818c2ecf20Sopenharmony_ci	 */
11828c2ecf20Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata,
11838c2ecf20Sopenharmony_ci		   be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	/* If we had any pending I/Os, kick them */
11868c2ecf20Sopenharmony_ci	hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK;
11878c2ecf20Sopenharmony_ci	wake_up(&hostdata->work_wait_q);
11888c2ecf20Sopenharmony_ci}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci/**
11918c2ecf20Sopenharmony_ci * send_srp_login: - Sends the srp login
11928c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
11938c2ecf20Sopenharmony_ci *
11948c2ecf20Sopenharmony_ci * Returns zero if successful.
11958c2ecf20Sopenharmony_ci*/
11968c2ecf20Sopenharmony_cistatic int send_srp_login(struct ibmvscsi_host_data *hostdata)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	int rc;
11998c2ecf20Sopenharmony_ci	unsigned long flags;
12008c2ecf20Sopenharmony_ci	struct srp_login_req *login;
12018c2ecf20Sopenharmony_ci	struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	BUG_ON(!evt_struct);
12048c2ecf20Sopenharmony_ci	init_event_struct(evt_struct, login_rsp,
12058c2ecf20Sopenharmony_ci			  VIOSRP_SRP_FORMAT, login_timeout);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	login = &evt_struct->iu.srp.login_req;
12088c2ecf20Sopenharmony_ci	memset(login, 0, sizeof(*login));
12098c2ecf20Sopenharmony_ci	login->opcode = SRP_LOGIN_REQ;
12108c2ecf20Sopenharmony_ci	login->req_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
12118c2ecf20Sopenharmony_ci	login->req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
12128c2ecf20Sopenharmony_ci					 SRP_BUF_FORMAT_INDIRECT);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	/* Start out with a request limit of 0, since this is negotiated in
12158c2ecf20Sopenharmony_ci	 * the login request we are just sending and login requests always
12168c2ecf20Sopenharmony_ci	 * get sent by the driver regardless of request_limit.
12178c2ecf20Sopenharmony_ci	 */
12188c2ecf20Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata, 0);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
12218c2ecf20Sopenharmony_ci	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2);
12228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
12238c2ecf20Sopenharmony_ci	dev_info(hostdata->dev, "sent SRP login\n");
12248c2ecf20Sopenharmony_ci	return rc;
12258c2ecf20Sopenharmony_ci};
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci/**
12288c2ecf20Sopenharmony_ci * capabilities_rsp: - Handle response to MAD adapter capabilities request
12298c2ecf20Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
12308c2ecf20Sopenharmony_ci *
12318c2ecf20Sopenharmony_ci * Used as a "done" callback by when sending adapter_info.
12328c2ecf20Sopenharmony_ci */
12338c2ecf20Sopenharmony_cistatic void capabilities_rsp(struct srp_event_struct *evt_struct)
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (evt_struct->xfer_iu->mad.capabilities.common.status) {
12388c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "error 0x%X getting capabilities info\n",
12398c2ecf20Sopenharmony_ci			evt_struct->xfer_iu->mad.capabilities.common.status);
12408c2ecf20Sopenharmony_ci	} else {
12418c2ecf20Sopenharmony_ci		if (hostdata->caps.migration.common.server_support !=
12428c2ecf20Sopenharmony_ci		    cpu_to_be16(SERVER_SUPPORTS_CAP))
12438c2ecf20Sopenharmony_ci			dev_info(hostdata->dev, "Partition migration not supported\n");
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci		if (client_reserve) {
12468c2ecf20Sopenharmony_ci			if (hostdata->caps.reserve.common.server_support ==
12478c2ecf20Sopenharmony_ci			    cpu_to_be16(SERVER_SUPPORTS_CAP))
12488c2ecf20Sopenharmony_ci				dev_info(hostdata->dev, "Client reserve enabled\n");
12498c2ecf20Sopenharmony_ci			else
12508c2ecf20Sopenharmony_ci				dev_info(hostdata->dev, "Client reserve not supported\n");
12518c2ecf20Sopenharmony_ci		}
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	send_srp_login(hostdata);
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci/**
12588c2ecf20Sopenharmony_ci * send_mad_capabilities: - Sends the mad capabilities request
12598c2ecf20Sopenharmony_ci *      and stores the result so it can be retrieved with
12608c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
12618c2ecf20Sopenharmony_ci */
12628c2ecf20Sopenharmony_cistatic void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
12638c2ecf20Sopenharmony_ci{
12648c2ecf20Sopenharmony_ci	struct viosrp_capabilities *req;
12658c2ecf20Sopenharmony_ci	struct srp_event_struct *evt_struct;
12668c2ecf20Sopenharmony_ci	unsigned long flags;
12678c2ecf20Sopenharmony_ci	struct device_node *of_node = hostdata->dev->of_node;
12688c2ecf20Sopenharmony_ci	const char *location;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
12718c2ecf20Sopenharmony_ci	BUG_ON(!evt_struct);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	init_event_struct(evt_struct, capabilities_rsp,
12748c2ecf20Sopenharmony_ci			  VIOSRP_MAD_FORMAT, info_timeout);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	req = &evt_struct->iu.mad.capabilities;
12778c2ecf20Sopenharmony_ci	memset(req, 0, sizeof(*req));
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	hostdata->caps.flags = cpu_to_be32(CAP_LIST_SUPPORTED);
12808c2ecf20Sopenharmony_ci	if (hostdata->client_migrated)
12818c2ecf20Sopenharmony_ci		hostdata->caps.flags |= cpu_to_be32(CLIENT_MIGRATED);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	strlcpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev),
12848c2ecf20Sopenharmony_ci		sizeof(hostdata->caps.name));
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	location = of_get_property(of_node, "ibm,loc-code", NULL);
12878c2ecf20Sopenharmony_ci	location = location ? location : dev_name(hostdata->dev);
12888c2ecf20Sopenharmony_ci	strlcpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc));
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	req->common.type = cpu_to_be32(VIOSRP_CAPABILITIES_TYPE);
12918c2ecf20Sopenharmony_ci	req->buffer = cpu_to_be64(hostdata->caps_addr);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	hostdata->caps.migration.common.cap_type =
12948c2ecf20Sopenharmony_ci				cpu_to_be32(MIGRATION_CAPABILITIES);
12958c2ecf20Sopenharmony_ci	hostdata->caps.migration.common.length =
12968c2ecf20Sopenharmony_ci				cpu_to_be16(sizeof(hostdata->caps.migration));
12978c2ecf20Sopenharmony_ci	hostdata->caps.migration.common.server_support =
12988c2ecf20Sopenharmony_ci				cpu_to_be16(SERVER_SUPPORTS_CAP);
12998c2ecf20Sopenharmony_ci	hostdata->caps.migration.ecl = cpu_to_be32(1);
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	if (client_reserve) {
13028c2ecf20Sopenharmony_ci		hostdata->caps.reserve.common.cap_type =
13038c2ecf20Sopenharmony_ci					cpu_to_be32(RESERVATION_CAPABILITIES);
13048c2ecf20Sopenharmony_ci		hostdata->caps.reserve.common.length =
13058c2ecf20Sopenharmony_ci				cpu_to_be16(sizeof(hostdata->caps.reserve));
13068c2ecf20Sopenharmony_ci		hostdata->caps.reserve.common.server_support =
13078c2ecf20Sopenharmony_ci				cpu_to_be16(SERVER_SUPPORTS_CAP);
13088c2ecf20Sopenharmony_ci		hostdata->caps.reserve.type =
13098c2ecf20Sopenharmony_ci				cpu_to_be32(CLIENT_RESERVE_SCSI_2);
13108c2ecf20Sopenharmony_ci		req->common.length =
13118c2ecf20Sopenharmony_ci				cpu_to_be16(sizeof(hostdata->caps));
13128c2ecf20Sopenharmony_ci	} else
13138c2ecf20Sopenharmony_ci		req->common.length = cpu_to_be16(sizeof(hostdata->caps) -
13148c2ecf20Sopenharmony_ci						sizeof(hostdata->caps.reserve));
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
13178c2ecf20Sopenharmony_ci	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
13188c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n");
13198c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
13208c2ecf20Sopenharmony_ci};
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci/**
13238c2ecf20Sopenharmony_ci * fast_fail_rsp: - Handle response to MAD enable fast fail
13248c2ecf20Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
13258c2ecf20Sopenharmony_ci *
13268c2ecf20Sopenharmony_ci * Used as a "done" callback by when sending enable fast fail. Gets called
13278c2ecf20Sopenharmony_ci * by ibmvscsi_handle_crq()
13288c2ecf20Sopenharmony_ci */
13298c2ecf20Sopenharmony_cistatic void fast_fail_rsp(struct srp_event_struct *evt_struct)
13308c2ecf20Sopenharmony_ci{
13318c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
13328c2ecf20Sopenharmony_ci	u16 status = be16_to_cpu(evt_struct->xfer_iu->mad.fast_fail.common.status);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	if (status == VIOSRP_MAD_NOT_SUPPORTED)
13358c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "fast_fail not supported in server\n");
13368c2ecf20Sopenharmony_ci	else if (status == VIOSRP_MAD_FAILED)
13378c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "fast_fail request failed\n");
13388c2ecf20Sopenharmony_ci	else if (status != VIOSRP_MAD_SUCCESS)
13398c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status);
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	send_mad_capabilities(hostdata);
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci/**
13458c2ecf20Sopenharmony_ci * init_host - Start host initialization
13468c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
13478c2ecf20Sopenharmony_ci *
13488c2ecf20Sopenharmony_ci * Returns zero if successful.
13498c2ecf20Sopenharmony_ci */
13508c2ecf20Sopenharmony_cistatic int enable_fast_fail(struct ibmvscsi_host_data *hostdata)
13518c2ecf20Sopenharmony_ci{
13528c2ecf20Sopenharmony_ci	int rc;
13538c2ecf20Sopenharmony_ci	unsigned long flags;
13548c2ecf20Sopenharmony_ci	struct viosrp_fast_fail *fast_fail_mad;
13558c2ecf20Sopenharmony_ci	struct srp_event_struct *evt_struct;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	if (!fast_fail) {
13588c2ecf20Sopenharmony_ci		send_mad_capabilities(hostdata);
13598c2ecf20Sopenharmony_ci		return 0;
13608c2ecf20Sopenharmony_ci	}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
13638c2ecf20Sopenharmony_ci	BUG_ON(!evt_struct);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	fast_fail_mad = &evt_struct->iu.mad.fast_fail;
13688c2ecf20Sopenharmony_ci	memset(fast_fail_mad, 0, sizeof(*fast_fail_mad));
13698c2ecf20Sopenharmony_ci	fast_fail_mad->common.type = cpu_to_be32(VIOSRP_ENABLE_FAST_FAIL);
13708c2ecf20Sopenharmony_ci	fast_fail_mad->common.length = cpu_to_be16(sizeof(*fast_fail_mad));
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
13738c2ecf20Sopenharmony_ci	rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
13748c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
13758c2ecf20Sopenharmony_ci	return rc;
13768c2ecf20Sopenharmony_ci}
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci/**
13798c2ecf20Sopenharmony_ci * adapter_info_rsp: - Handle response to MAD adapter info request
13808c2ecf20Sopenharmony_ci * @evt_struct:	srp_event_struct with the response
13818c2ecf20Sopenharmony_ci *
13828c2ecf20Sopenharmony_ci * Used as a "done" callback by when sending adapter_info. Gets called
13838c2ecf20Sopenharmony_ci * by ibmvscsi_handle_crq()
13848c2ecf20Sopenharmony_ci*/
13858c2ecf20Sopenharmony_cistatic void adapter_info_rsp(struct srp_event_struct *evt_struct)
13868c2ecf20Sopenharmony_ci{
13878c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
13908c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "error %d getting adapter info\n",
13918c2ecf20Sopenharmony_ci			evt_struct->xfer_iu->mad.adapter_info.common.status);
13928c2ecf20Sopenharmony_ci	} else {
13938c2ecf20Sopenharmony_ci		dev_info(hostdata->dev, "host srp version: %s, "
13948c2ecf20Sopenharmony_ci			 "host partition %s (%d), OS %d, max io %u\n",
13958c2ecf20Sopenharmony_ci			 hostdata->madapter_info.srp_version,
13968c2ecf20Sopenharmony_ci			 hostdata->madapter_info.partition_name,
13978c2ecf20Sopenharmony_ci			 be32_to_cpu(hostdata->madapter_info.partition_number),
13988c2ecf20Sopenharmony_ci			 be32_to_cpu(hostdata->madapter_info.os_type),
13998c2ecf20Sopenharmony_ci			 be32_to_cpu(hostdata->madapter_info.port_max_txu[0]));
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		if (hostdata->madapter_info.port_max_txu[0])
14028c2ecf20Sopenharmony_ci			hostdata->host->max_sectors =
14038c2ecf20Sopenharmony_ci				be32_to_cpu(hostdata->madapter_info.port_max_txu[0]) >> 9;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci		if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX &&
14068c2ecf20Sopenharmony_ci		    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
14078c2ecf20Sopenharmony_ci			dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
14088c2ecf20Sopenharmony_ci				hostdata->madapter_info.srp_version);
14098c2ecf20Sopenharmony_ci			dev_err(hostdata->dev, "limiting scatterlists to %d\n",
14108c2ecf20Sopenharmony_ci				MAX_INDIRECT_BUFS);
14118c2ecf20Sopenharmony_ci			hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
14128c2ecf20Sopenharmony_ci		}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci		if (be32_to_cpu(hostdata->madapter_info.os_type) == SRP_MAD_OS_AIX) {
14158c2ecf20Sopenharmony_ci			enable_fast_fail(hostdata);
14168c2ecf20Sopenharmony_ci			return;
14178c2ecf20Sopenharmony_ci		}
14188c2ecf20Sopenharmony_ci	}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci	send_srp_login(hostdata);
14218c2ecf20Sopenharmony_ci}
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci/**
14248c2ecf20Sopenharmony_ci * send_mad_adapter_info: - Sends the mad adapter info request
14258c2ecf20Sopenharmony_ci *      and stores the result so it can be retrieved with
14268c2ecf20Sopenharmony_ci *      sysfs.  We COULD consider causing a failure if the
14278c2ecf20Sopenharmony_ci *      returned SRP version doesn't match ours.
14288c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
14298c2ecf20Sopenharmony_ci *
14308c2ecf20Sopenharmony_ci * Returns zero if successful.
14318c2ecf20Sopenharmony_ci*/
14328c2ecf20Sopenharmony_cistatic void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
14338c2ecf20Sopenharmony_ci{
14348c2ecf20Sopenharmony_ci	struct viosrp_adapter_info *req;
14358c2ecf20Sopenharmony_ci	struct srp_event_struct *evt_struct;
14368c2ecf20Sopenharmony_ci	unsigned long flags;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	evt_struct = get_event_struct(&hostdata->pool);
14398c2ecf20Sopenharmony_ci	BUG_ON(!evt_struct);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	init_event_struct(evt_struct,
14428c2ecf20Sopenharmony_ci			  adapter_info_rsp,
14438c2ecf20Sopenharmony_ci			  VIOSRP_MAD_FORMAT,
14448c2ecf20Sopenharmony_ci			  info_timeout);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	req = &evt_struct->iu.mad.adapter_info;
14478c2ecf20Sopenharmony_ci	memset(req, 0x00, sizeof(*req));
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	req->common.type = cpu_to_be32(VIOSRP_ADAPTER_INFO_TYPE);
14508c2ecf20Sopenharmony_ci	req->common.length = cpu_to_be16(sizeof(hostdata->madapter_info));
14518c2ecf20Sopenharmony_ci	req->buffer = cpu_to_be64(hostdata->adapter_info_addr);
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
14548c2ecf20Sopenharmony_ci	if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
14558c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
14568c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
14578c2ecf20Sopenharmony_ci};
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci/**
14608c2ecf20Sopenharmony_ci * init_adapter: Start virtual adapter initialization sequence
14618c2ecf20Sopenharmony_ci *
14628c2ecf20Sopenharmony_ci */
14638c2ecf20Sopenharmony_cistatic void init_adapter(struct ibmvscsi_host_data *hostdata)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	send_mad_adapter_info(hostdata);
14668c2ecf20Sopenharmony_ci}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci/**
14698c2ecf20Sopenharmony_ci * sync_completion: Signal that a synchronous command has completed
14708c2ecf20Sopenharmony_ci * Note that after returning from this call, the evt_struct is freed.
14718c2ecf20Sopenharmony_ci * the caller waiting on this completion shouldn't touch the evt_struct
14728c2ecf20Sopenharmony_ci * again.
14738c2ecf20Sopenharmony_ci */
14748c2ecf20Sopenharmony_cistatic void sync_completion(struct srp_event_struct *evt_struct)
14758c2ecf20Sopenharmony_ci{
14768c2ecf20Sopenharmony_ci	/* copy the response back */
14778c2ecf20Sopenharmony_ci	if (evt_struct->sync_srp)
14788c2ecf20Sopenharmony_ci		*evt_struct->sync_srp = *evt_struct->xfer_iu;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	complete(&evt_struct->comp);
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci/**
14848c2ecf20Sopenharmony_ci * ibmvscsi_abort: Abort a command...from scsi host template
14858c2ecf20Sopenharmony_ci * send this over to the server and wait synchronously for the response
14868c2ecf20Sopenharmony_ci */
14878c2ecf20Sopenharmony_cistatic int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
14888c2ecf20Sopenharmony_ci{
14898c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
14908c2ecf20Sopenharmony_ci	struct srp_tsk_mgmt *tsk_mgmt;
14918c2ecf20Sopenharmony_ci	struct srp_event_struct *evt;
14928c2ecf20Sopenharmony_ci	struct srp_event_struct *tmp_evt, *found_evt;
14938c2ecf20Sopenharmony_ci	union viosrp_iu srp_rsp;
14948c2ecf20Sopenharmony_ci	int rsp_rc;
14958c2ecf20Sopenharmony_ci	unsigned long flags;
14968c2ecf20Sopenharmony_ci	u16 lun = lun_from_dev(cmd->device);
14978c2ecf20Sopenharmony_ci	unsigned long wait_switch = 0;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	/* First, find this command in our sent list so we can figure
15008c2ecf20Sopenharmony_ci	 * out the correct tag
15018c2ecf20Sopenharmony_ci	 */
15028c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
15038c2ecf20Sopenharmony_ci	wait_switch = jiffies + (init_timeout * HZ);
15048c2ecf20Sopenharmony_ci	do {
15058c2ecf20Sopenharmony_ci		found_evt = NULL;
15068c2ecf20Sopenharmony_ci		list_for_each_entry(tmp_evt, &hostdata->sent, list) {
15078c2ecf20Sopenharmony_ci			if (tmp_evt->cmnd == cmd) {
15088c2ecf20Sopenharmony_ci				found_evt = tmp_evt;
15098c2ecf20Sopenharmony_ci				break;
15108c2ecf20Sopenharmony_ci			}
15118c2ecf20Sopenharmony_ci		}
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci		if (!found_evt) {
15148c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
15158c2ecf20Sopenharmony_ci			return SUCCESS;
15168c2ecf20Sopenharmony_ci		}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		evt = get_event_struct(&hostdata->pool);
15198c2ecf20Sopenharmony_ci		if (evt == NULL) {
15208c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
15218c2ecf20Sopenharmony_ci			sdev_printk(KERN_ERR, cmd->device,
15228c2ecf20Sopenharmony_ci				"failed to allocate abort event\n");
15238c2ecf20Sopenharmony_ci			return FAILED;
15248c2ecf20Sopenharmony_ci		}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci		init_event_struct(evt,
15278c2ecf20Sopenharmony_ci				  sync_completion,
15288c2ecf20Sopenharmony_ci				  VIOSRP_SRP_FORMAT,
15298c2ecf20Sopenharmony_ci				  abort_timeout);
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci		/* Set up an abort SRP command */
15348c2ecf20Sopenharmony_ci		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
15358c2ecf20Sopenharmony_ci		tsk_mgmt->opcode = SRP_TSK_MGMT;
15368c2ecf20Sopenharmony_ci		int_to_scsilun(lun, &tsk_mgmt->lun);
15378c2ecf20Sopenharmony_ci		tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
15388c2ecf20Sopenharmony_ci		tsk_mgmt->task_tag = (u64) found_evt;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci		evt->sync_srp = &srp_rsp;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci		init_completion(&evt->comp);
15438c2ecf20Sopenharmony_ci		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2);
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
15468c2ecf20Sopenharmony_ci			break;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
15498c2ecf20Sopenharmony_ci		msleep(10);
15508c2ecf20Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
15518c2ecf20Sopenharmony_ci	} while (time_before(jiffies, wait_switch));
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	if (rsp_rc != 0) {
15568c2ecf20Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
15578c2ecf20Sopenharmony_ci			    "failed to send abort() event. rc=%d\n", rsp_rc);
15588c2ecf20Sopenharmony_ci		return FAILED;
15598c2ecf20Sopenharmony_ci	}
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	sdev_printk(KERN_INFO, cmd->device,
15628c2ecf20Sopenharmony_ci                    "aborting command. lun 0x%llx, tag 0x%llx\n",
15638c2ecf20Sopenharmony_ci		    (((u64) lun) << 48), (u64) found_evt);
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	wait_for_completion(&evt->comp);
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	/* make sure we got a good response */
15688c2ecf20Sopenharmony_ci	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
15698c2ecf20Sopenharmony_ci		if (printk_ratelimit())
15708c2ecf20Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n",
15718c2ecf20Sopenharmony_ci				    srp_rsp.srp.rsp.opcode);
15728c2ecf20Sopenharmony_ci		return FAILED;
15738c2ecf20Sopenharmony_ci	}
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
15768c2ecf20Sopenharmony_ci		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
15778c2ecf20Sopenharmony_ci	else
15788c2ecf20Sopenharmony_ci		rsp_rc = srp_rsp.srp.rsp.status;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	if (rsp_rc) {
15818c2ecf20Sopenharmony_ci		if (printk_ratelimit())
15828c2ecf20Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device,
15838c2ecf20Sopenharmony_ci				    "abort code %d for task tag 0x%llx\n",
15848c2ecf20Sopenharmony_ci				    rsp_rc, tsk_mgmt->task_tag);
15858c2ecf20Sopenharmony_ci		return FAILED;
15868c2ecf20Sopenharmony_ci	}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	/* Because we dropped the spinlock above, it's possible
15898c2ecf20Sopenharmony_ci	 * The event is no longer in our list.  Make sure it didn't
15908c2ecf20Sopenharmony_ci	 * complete while we were aborting
15918c2ecf20Sopenharmony_ci	 */
15928c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
15938c2ecf20Sopenharmony_ci	found_evt = NULL;
15948c2ecf20Sopenharmony_ci	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
15958c2ecf20Sopenharmony_ci		if (tmp_evt->cmnd == cmd) {
15968c2ecf20Sopenharmony_ci			found_evt = tmp_evt;
15978c2ecf20Sopenharmony_ci			break;
15988c2ecf20Sopenharmony_ci		}
15998c2ecf20Sopenharmony_ci	}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	if (found_evt == NULL) {
16028c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
16038c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%llx completed\n",
16048c2ecf20Sopenharmony_ci			    tsk_mgmt->task_tag);
16058c2ecf20Sopenharmony_ci		return SUCCESS;
16068c2ecf20Sopenharmony_ci	}
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%llx\n",
16098c2ecf20Sopenharmony_ci		    tsk_mgmt->task_tag);
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	cmd->result = (DID_ABORT << 16);
16128c2ecf20Sopenharmony_ci	list_del(&found_evt->list);
16138c2ecf20Sopenharmony_ci	unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt,
16148c2ecf20Sopenharmony_ci		       found_evt->hostdata->dev);
16158c2ecf20Sopenharmony_ci	free_event_struct(&found_evt->hostdata->pool, found_evt);
16168c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
16178c2ecf20Sopenharmony_ci	atomic_inc(&hostdata->request_limit);
16188c2ecf20Sopenharmony_ci	return SUCCESS;
16198c2ecf20Sopenharmony_ci}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci/**
16228c2ecf20Sopenharmony_ci * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host
16238c2ecf20Sopenharmony_ci * template send this over to the server and wait synchronously for the
16248c2ecf20Sopenharmony_ci * response
16258c2ecf20Sopenharmony_ci */
16268c2ecf20Sopenharmony_cistatic int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
16278c2ecf20Sopenharmony_ci{
16288c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
16298c2ecf20Sopenharmony_ci	struct srp_tsk_mgmt *tsk_mgmt;
16308c2ecf20Sopenharmony_ci	struct srp_event_struct *evt;
16318c2ecf20Sopenharmony_ci	struct srp_event_struct *tmp_evt, *pos;
16328c2ecf20Sopenharmony_ci	union viosrp_iu srp_rsp;
16338c2ecf20Sopenharmony_ci	int rsp_rc;
16348c2ecf20Sopenharmony_ci	unsigned long flags;
16358c2ecf20Sopenharmony_ci	u16 lun = lun_from_dev(cmd->device);
16368c2ecf20Sopenharmony_ci	unsigned long wait_switch = 0;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
16398c2ecf20Sopenharmony_ci	wait_switch = jiffies + (init_timeout * HZ);
16408c2ecf20Sopenharmony_ci	do {
16418c2ecf20Sopenharmony_ci		evt = get_event_struct(&hostdata->pool);
16428c2ecf20Sopenharmony_ci		if (evt == NULL) {
16438c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
16448c2ecf20Sopenharmony_ci			sdev_printk(KERN_ERR, cmd->device,
16458c2ecf20Sopenharmony_ci				"failed to allocate reset event\n");
16468c2ecf20Sopenharmony_ci			return FAILED;
16478c2ecf20Sopenharmony_ci		}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		init_event_struct(evt,
16508c2ecf20Sopenharmony_ci				  sync_completion,
16518c2ecf20Sopenharmony_ci				  VIOSRP_SRP_FORMAT,
16528c2ecf20Sopenharmony_ci				  reset_timeout);
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci		/* Set up a lun reset SRP command */
16578c2ecf20Sopenharmony_ci		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
16588c2ecf20Sopenharmony_ci		tsk_mgmt->opcode = SRP_TSK_MGMT;
16598c2ecf20Sopenharmony_ci		int_to_scsilun(lun, &tsk_mgmt->lun);
16608c2ecf20Sopenharmony_ci		tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci		evt->sync_srp = &srp_rsp;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci		init_completion(&evt->comp);
16658c2ecf20Sopenharmony_ci		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2);
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
16688c2ecf20Sopenharmony_ci			break;
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
16718c2ecf20Sopenharmony_ci		msleep(10);
16728c2ecf20Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
16738c2ecf20Sopenharmony_ci	} while (time_before(jiffies, wait_switch));
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	if (rsp_rc != 0) {
16788c2ecf20Sopenharmony_ci		sdev_printk(KERN_ERR, cmd->device,
16798c2ecf20Sopenharmony_ci			    "failed to send reset event. rc=%d\n", rsp_rc);
16808c2ecf20Sopenharmony_ci		return FAILED;
16818c2ecf20Sopenharmony_ci	}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%llx\n",
16848c2ecf20Sopenharmony_ci		    (((u64) lun) << 48));
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	wait_for_completion(&evt->comp);
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	/* make sure we got a good response */
16898c2ecf20Sopenharmony_ci	if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
16908c2ecf20Sopenharmony_ci		if (printk_ratelimit())
16918c2ecf20Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n",
16928c2ecf20Sopenharmony_ci				    srp_rsp.srp.rsp.opcode);
16938c2ecf20Sopenharmony_ci		return FAILED;
16948c2ecf20Sopenharmony_ci	}
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID)
16978c2ecf20Sopenharmony_ci		rsp_rc = *((int *)srp_rsp.srp.rsp.data);
16988c2ecf20Sopenharmony_ci	else
16998c2ecf20Sopenharmony_ci		rsp_rc = srp_rsp.srp.rsp.status;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	if (rsp_rc) {
17028c2ecf20Sopenharmony_ci		if (printk_ratelimit())
17038c2ecf20Sopenharmony_ci			sdev_printk(KERN_WARNING, cmd->device,
17048c2ecf20Sopenharmony_ci				    "reset code %d for task tag 0x%llx\n",
17058c2ecf20Sopenharmony_ci				    rsp_rc, tsk_mgmt->task_tag);
17068c2ecf20Sopenharmony_ci		return FAILED;
17078c2ecf20Sopenharmony_ci	}
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	/* We need to find all commands for this LUN that have not yet been
17108c2ecf20Sopenharmony_ci	 * responded to, and fail them with DID_RESET
17118c2ecf20Sopenharmony_ci	 */
17128c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
17138c2ecf20Sopenharmony_ci	list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
17148c2ecf20Sopenharmony_ci		if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) {
17158c2ecf20Sopenharmony_ci			if (tmp_evt->cmnd)
17168c2ecf20Sopenharmony_ci				tmp_evt->cmnd->result = (DID_RESET << 16);
17178c2ecf20Sopenharmony_ci			list_del(&tmp_evt->list);
17188c2ecf20Sopenharmony_ci			unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt,
17198c2ecf20Sopenharmony_ci				       tmp_evt->hostdata->dev);
17208c2ecf20Sopenharmony_ci			free_event_struct(&tmp_evt->hostdata->pool,
17218c2ecf20Sopenharmony_ci						   tmp_evt);
17228c2ecf20Sopenharmony_ci			atomic_inc(&hostdata->request_limit);
17238c2ecf20Sopenharmony_ci			if (tmp_evt->cmnd_done)
17248c2ecf20Sopenharmony_ci				tmp_evt->cmnd_done(tmp_evt->cmnd);
17258c2ecf20Sopenharmony_ci			else if (tmp_evt->done)
17268c2ecf20Sopenharmony_ci				tmp_evt->done(tmp_evt);
17278c2ecf20Sopenharmony_ci		}
17288c2ecf20Sopenharmony_ci	}
17298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
17308c2ecf20Sopenharmony_ci	return SUCCESS;
17318c2ecf20Sopenharmony_ci}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci/**
17348c2ecf20Sopenharmony_ci * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
17358c2ecf20Sopenharmony_ci * @cmd:	struct scsi_cmnd having problems
17368c2ecf20Sopenharmony_ci*/
17378c2ecf20Sopenharmony_cistatic int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
17388c2ecf20Sopenharmony_ci{
17398c2ecf20Sopenharmony_ci	unsigned long wait_switch = 0;
17408c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	ibmvscsi_reset_host(hostdata);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	for (wait_switch = jiffies + (init_timeout * HZ);
17478c2ecf20Sopenharmony_ci	     time_before(jiffies, wait_switch) &&
17488c2ecf20Sopenharmony_ci		     atomic_read(&hostdata->request_limit) < 2;) {
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci		msleep(10);
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	if (atomic_read(&hostdata->request_limit) <= 0)
17548c2ecf20Sopenharmony_ci		return FAILED;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	return SUCCESS;
17578c2ecf20Sopenharmony_ci}
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci/**
17608c2ecf20Sopenharmony_ci * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ
17618c2ecf20Sopenharmony_ci * @crq:	Command/Response queue
17628c2ecf20Sopenharmony_ci * @hostdata:	ibmvscsi_host_data of host
17638c2ecf20Sopenharmony_ci *
17648c2ecf20Sopenharmony_ci*/
17658c2ecf20Sopenharmony_cistatic void ibmvscsi_handle_crq(struct viosrp_crq *crq,
17668c2ecf20Sopenharmony_ci				struct ibmvscsi_host_data *hostdata)
17678c2ecf20Sopenharmony_ci{
17688c2ecf20Sopenharmony_ci	long rc;
17698c2ecf20Sopenharmony_ci	unsigned long flags;
17708c2ecf20Sopenharmony_ci	/* The hypervisor copies our tag value here so no byteswapping */
17718c2ecf20Sopenharmony_ci	struct srp_event_struct *evt_struct =
17728c2ecf20Sopenharmony_ci			(__force struct srp_event_struct *)crq->IU_data_ptr;
17738c2ecf20Sopenharmony_ci	switch (crq->valid) {
17748c2ecf20Sopenharmony_ci	case VIOSRP_CRQ_INIT_RSP:		/* initialization */
17758c2ecf20Sopenharmony_ci		switch (crq->format) {
17768c2ecf20Sopenharmony_ci		case VIOSRP_CRQ_INIT:	/* Initialization message */
17778c2ecf20Sopenharmony_ci			dev_info(hostdata->dev, "partner initialized\n");
17788c2ecf20Sopenharmony_ci			/* Send back a response */
17798c2ecf20Sopenharmony_ci			rc = ibmvscsi_send_crq(hostdata, 0xC002000000000000LL, 0);
17808c2ecf20Sopenharmony_ci			if (rc == 0) {
17818c2ecf20Sopenharmony_ci				/* Now login */
17828c2ecf20Sopenharmony_ci				init_adapter(hostdata);
17838c2ecf20Sopenharmony_ci			} else {
17848c2ecf20Sopenharmony_ci				dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
17858c2ecf20Sopenharmony_ci			}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci			break;
17888c2ecf20Sopenharmony_ci		case VIOSRP_CRQ_INIT_COMPLETE:	/* Initialization response */
17898c2ecf20Sopenharmony_ci			dev_info(hostdata->dev, "partner initialization complete\n");
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci			/* Now login */
17928c2ecf20Sopenharmony_ci			init_adapter(hostdata);
17938c2ecf20Sopenharmony_ci			break;
17948c2ecf20Sopenharmony_ci		default:
17958c2ecf20Sopenharmony_ci			dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
17968c2ecf20Sopenharmony_ci		}
17978c2ecf20Sopenharmony_ci		return;
17988c2ecf20Sopenharmony_ci	case VIOSRP_CRQ_XPORT_EVENT:	/* Hypervisor telling us the connection is closed */
17998c2ecf20Sopenharmony_ci		scsi_block_requests(hostdata->host);
18008c2ecf20Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, 0);
18018c2ecf20Sopenharmony_ci		if (crq->format == 0x06) {
18028c2ecf20Sopenharmony_ci			/* We need to re-setup the interpartition connection */
18038c2ecf20Sopenharmony_ci			dev_info(hostdata->dev, "Re-enabling adapter!\n");
18048c2ecf20Sopenharmony_ci			hostdata->client_migrated = 1;
18058c2ecf20Sopenharmony_ci			hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE;
18068c2ecf20Sopenharmony_ci			purge_requests(hostdata, DID_REQUEUE);
18078c2ecf20Sopenharmony_ci			wake_up(&hostdata->work_wait_q);
18088c2ecf20Sopenharmony_ci		} else {
18098c2ecf20Sopenharmony_ci			dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
18108c2ecf20Sopenharmony_ci				crq->format);
18118c2ecf20Sopenharmony_ci			ibmvscsi_reset_host(hostdata);
18128c2ecf20Sopenharmony_ci		}
18138c2ecf20Sopenharmony_ci		return;
18148c2ecf20Sopenharmony_ci	case VIOSRP_CRQ_CMD_RSP:		/* real payload */
18158c2ecf20Sopenharmony_ci		break;
18168c2ecf20Sopenharmony_ci	default:
18178c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
18188c2ecf20Sopenharmony_ci			crq->valid);
18198c2ecf20Sopenharmony_ci		return;
18208c2ecf20Sopenharmony_ci	}
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	/* The only kind of payload CRQs we should get are responses to
18238c2ecf20Sopenharmony_ci	 * things we send. Make sure this response is to something we
18248c2ecf20Sopenharmony_ci	 * actually sent
18258c2ecf20Sopenharmony_ci	 */
18268c2ecf20Sopenharmony_ci	if (!valid_event_struct(&hostdata->pool, evt_struct)) {
18278c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
18288c2ecf20Sopenharmony_ci		       evt_struct);
18298c2ecf20Sopenharmony_ci		return;
18308c2ecf20Sopenharmony_ci	}
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	if (atomic_read(&evt_struct->free)) {
18338c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
18348c2ecf20Sopenharmony_ci			evt_struct);
18358c2ecf20Sopenharmony_ci		return;
18368c2ecf20Sopenharmony_ci	}
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	if (crq->format == VIOSRP_SRP_FORMAT)
18398c2ecf20Sopenharmony_ci		atomic_add(be32_to_cpu(evt_struct->xfer_iu->srp.rsp.req_lim_delta),
18408c2ecf20Sopenharmony_ci			   &hostdata->request_limit);
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	del_timer(&evt_struct->timer);
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd)
18458c2ecf20Sopenharmony_ci		evt_struct->cmnd->result = DID_ERROR << 16;
18468c2ecf20Sopenharmony_ci	if (evt_struct->done)
18478c2ecf20Sopenharmony_ci		evt_struct->done(evt_struct);
18488c2ecf20Sopenharmony_ci	else
18498c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "returned done() is NULL; not running it!\n");
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	/*
18528c2ecf20Sopenharmony_ci	 * Lock the host_lock before messing with these structures, since we
18538c2ecf20Sopenharmony_ci	 * are running in a task context
18548c2ecf20Sopenharmony_ci	 */
18558c2ecf20Sopenharmony_ci	spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags);
18568c2ecf20Sopenharmony_ci	list_del(&evt_struct->list);
18578c2ecf20Sopenharmony_ci	free_event_struct(&evt_struct->hostdata->pool, evt_struct);
18588c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags);
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci/**
18628c2ecf20Sopenharmony_ci * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
18638c2ecf20Sopenharmony_ci * @sdev:	struct scsi_device device to configure
18648c2ecf20Sopenharmony_ci *
18658c2ecf20Sopenharmony_ci * Enable allow_restart for a device if it is a disk.  Adjust the
18668c2ecf20Sopenharmony_ci * queue_depth here also as is required by the documentation for
18678c2ecf20Sopenharmony_ci * struct scsi_host_template.
18688c2ecf20Sopenharmony_ci */
18698c2ecf20Sopenharmony_cistatic int ibmvscsi_slave_configure(struct scsi_device *sdev)
18708c2ecf20Sopenharmony_ci{
18718c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = sdev->host;
18728c2ecf20Sopenharmony_ci	unsigned long lock_flags = 0;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, lock_flags);
18758c2ecf20Sopenharmony_ci	if (sdev->type == TYPE_DISK) {
18768c2ecf20Sopenharmony_ci		sdev->allow_restart = 1;
18778c2ecf20Sopenharmony_ci		blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
18788c2ecf20Sopenharmony_ci	}
18798c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, lock_flags);
18808c2ecf20Sopenharmony_ci	return 0;
18818c2ecf20Sopenharmony_ci}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci/**
18848c2ecf20Sopenharmony_ci * ibmvscsi_change_queue_depth - Change the device's queue depth
18858c2ecf20Sopenharmony_ci * @sdev:	scsi device struct
18868c2ecf20Sopenharmony_ci * @qdepth:	depth to set
18878c2ecf20Sopenharmony_ci * @reason:	calling context
18888c2ecf20Sopenharmony_ci *
18898c2ecf20Sopenharmony_ci * Return value:
18908c2ecf20Sopenharmony_ci * 	actual depth set
18918c2ecf20Sopenharmony_ci **/
18928c2ecf20Sopenharmony_cistatic int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
18938c2ecf20Sopenharmony_ci{
18948c2ecf20Sopenharmony_ci	if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
18958c2ecf20Sopenharmony_ci		qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
18968c2ecf20Sopenharmony_ci	return scsi_change_queue_depth(sdev, qdepth);
18978c2ecf20Sopenharmony_ci}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
19008c2ecf20Sopenharmony_ci * sysfs attributes
19018c2ecf20Sopenharmony_ci */
19028c2ecf20Sopenharmony_cistatic ssize_t show_host_vhost_loc(struct device *dev,
19038c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
19048c2ecf20Sopenharmony_ci{
19058c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
19068c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
19078c2ecf20Sopenharmony_ci	int len;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n",
19108c2ecf20Sopenharmony_ci		       hostdata->caps.loc);
19118c2ecf20Sopenharmony_ci	return len;
19128c2ecf20Sopenharmony_ci}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_vhost_loc = {
19158c2ecf20Sopenharmony_ci	.attr = {
19168c2ecf20Sopenharmony_ci		 .name = "vhost_loc",
19178c2ecf20Sopenharmony_ci		 .mode = S_IRUGO,
19188c2ecf20Sopenharmony_ci		 },
19198c2ecf20Sopenharmony_ci	.show = show_host_vhost_loc,
19208c2ecf20Sopenharmony_ci};
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_cistatic ssize_t show_host_vhost_name(struct device *dev,
19238c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
19248c2ecf20Sopenharmony_ci{
19258c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
19268c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
19278c2ecf20Sopenharmony_ci	int len;
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n",
19308c2ecf20Sopenharmony_ci		       hostdata->caps.name);
19318c2ecf20Sopenharmony_ci	return len;
19328c2ecf20Sopenharmony_ci}
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_vhost_name = {
19358c2ecf20Sopenharmony_ci	.attr = {
19368c2ecf20Sopenharmony_ci		 .name = "vhost_name",
19378c2ecf20Sopenharmony_ci		 .mode = S_IRUGO,
19388c2ecf20Sopenharmony_ci		 },
19398c2ecf20Sopenharmony_ci	.show = show_host_vhost_name,
19408c2ecf20Sopenharmony_ci};
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_cistatic ssize_t show_host_srp_version(struct device *dev,
19438c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
19448c2ecf20Sopenharmony_ci{
19458c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
19468c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
19478c2ecf20Sopenharmony_ci	int len;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%s\n",
19508c2ecf20Sopenharmony_ci		       hostdata->madapter_info.srp_version);
19518c2ecf20Sopenharmony_ci	return len;
19528c2ecf20Sopenharmony_ci}
19538c2ecf20Sopenharmony_ci
19548c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_srp_version = {
19558c2ecf20Sopenharmony_ci	.attr = {
19568c2ecf20Sopenharmony_ci		 .name = "srp_version",
19578c2ecf20Sopenharmony_ci		 .mode = S_IRUGO,
19588c2ecf20Sopenharmony_ci		 },
19598c2ecf20Sopenharmony_ci	.show = show_host_srp_version,
19608c2ecf20Sopenharmony_ci};
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_cistatic ssize_t show_host_partition_name(struct device *dev,
19638c2ecf20Sopenharmony_ci					struct device_attribute *attr,
19648c2ecf20Sopenharmony_ci					char *buf)
19658c2ecf20Sopenharmony_ci{
19668c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
19678c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
19688c2ecf20Sopenharmony_ci	int len;
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%s\n",
19718c2ecf20Sopenharmony_ci		       hostdata->madapter_info.partition_name);
19728c2ecf20Sopenharmony_ci	return len;
19738c2ecf20Sopenharmony_ci}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_partition_name = {
19768c2ecf20Sopenharmony_ci	.attr = {
19778c2ecf20Sopenharmony_ci		 .name = "partition_name",
19788c2ecf20Sopenharmony_ci		 .mode = S_IRUGO,
19798c2ecf20Sopenharmony_ci		 },
19808c2ecf20Sopenharmony_ci	.show = show_host_partition_name,
19818c2ecf20Sopenharmony_ci};
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_cistatic ssize_t show_host_partition_number(struct device *dev,
19848c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
19858c2ecf20Sopenharmony_ci					  char *buf)
19868c2ecf20Sopenharmony_ci{
19878c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
19888c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
19898c2ecf20Sopenharmony_ci	int len;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%d\n",
19928c2ecf20Sopenharmony_ci		       be32_to_cpu(hostdata->madapter_info.partition_number));
19938c2ecf20Sopenharmony_ci	return len;
19948c2ecf20Sopenharmony_ci}
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_partition_number = {
19978c2ecf20Sopenharmony_ci	.attr = {
19988c2ecf20Sopenharmony_ci		 .name = "partition_number",
19998c2ecf20Sopenharmony_ci		 .mode = S_IRUGO,
20008c2ecf20Sopenharmony_ci		 },
20018c2ecf20Sopenharmony_ci	.show = show_host_partition_number,
20028c2ecf20Sopenharmony_ci};
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_cistatic ssize_t show_host_mad_version(struct device *dev,
20058c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
20088c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
20098c2ecf20Sopenharmony_ci	int len;
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%d\n",
20128c2ecf20Sopenharmony_ci		       be32_to_cpu(hostdata->madapter_info.mad_version));
20138c2ecf20Sopenharmony_ci	return len;
20148c2ecf20Sopenharmony_ci}
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_mad_version = {
20178c2ecf20Sopenharmony_ci	.attr = {
20188c2ecf20Sopenharmony_ci		 .name = "mad_version",
20198c2ecf20Sopenharmony_ci		 .mode = S_IRUGO,
20208c2ecf20Sopenharmony_ci		 },
20218c2ecf20Sopenharmony_ci	.show = show_host_mad_version,
20228c2ecf20Sopenharmony_ci};
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_cistatic ssize_t show_host_os_type(struct device *dev,
20258c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
20268c2ecf20Sopenharmony_ci{
20278c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(dev);
20288c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
20298c2ecf20Sopenharmony_ci	int len;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	len = snprintf(buf, PAGE_SIZE, "%d\n",
20328c2ecf20Sopenharmony_ci		       be32_to_cpu(hostdata->madapter_info.os_type));
20338c2ecf20Sopenharmony_ci	return len;
20348c2ecf20Sopenharmony_ci}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_os_type = {
20378c2ecf20Sopenharmony_ci	.attr = {
20388c2ecf20Sopenharmony_ci		 .name = "os_type",
20398c2ecf20Sopenharmony_ci		 .mode = S_IRUGO,
20408c2ecf20Sopenharmony_ci		 },
20418c2ecf20Sopenharmony_ci	.show = show_host_os_type,
20428c2ecf20Sopenharmony_ci};
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_cistatic ssize_t show_host_config(struct device *dev,
20458c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
20468c2ecf20Sopenharmony_ci{
20478c2ecf20Sopenharmony_ci	return 0;
20488c2ecf20Sopenharmony_ci}
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_cistatic struct device_attribute ibmvscsi_host_config = {
20518c2ecf20Sopenharmony_ci	.attr = {
20528c2ecf20Sopenharmony_ci		.name = "config",
20538c2ecf20Sopenharmony_ci		.mode = S_IRUGO,
20548c2ecf20Sopenharmony_ci		},
20558c2ecf20Sopenharmony_ci	.show = show_host_config,
20568c2ecf20Sopenharmony_ci};
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_cistatic int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type)
20598c2ecf20Sopenharmony_ci{
20608c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	dev_info(hostdata->dev, "Initiating adapter reset!\n");
20638c2ecf20Sopenharmony_ci	ibmvscsi_reset_host(hostdata);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	return 0;
20668c2ecf20Sopenharmony_ci}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_cistatic struct device_attribute *ibmvscsi_attrs[] = {
20698c2ecf20Sopenharmony_ci	&ibmvscsi_host_vhost_loc,
20708c2ecf20Sopenharmony_ci	&ibmvscsi_host_vhost_name,
20718c2ecf20Sopenharmony_ci	&ibmvscsi_host_srp_version,
20728c2ecf20Sopenharmony_ci	&ibmvscsi_host_partition_name,
20738c2ecf20Sopenharmony_ci	&ibmvscsi_host_partition_number,
20748c2ecf20Sopenharmony_ci	&ibmvscsi_host_mad_version,
20758c2ecf20Sopenharmony_ci	&ibmvscsi_host_os_type,
20768c2ecf20Sopenharmony_ci	&ibmvscsi_host_config,
20778c2ecf20Sopenharmony_ci	NULL
20788c2ecf20Sopenharmony_ci};
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_ci/* ------------------------------------------------------------
20818c2ecf20Sopenharmony_ci * SCSI driver registration
20828c2ecf20Sopenharmony_ci */
20838c2ecf20Sopenharmony_cistatic struct scsi_host_template driver_template = {
20848c2ecf20Sopenharmony_ci	.module = THIS_MODULE,
20858c2ecf20Sopenharmony_ci	.name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION,
20868c2ecf20Sopenharmony_ci	.proc_name = "ibmvscsi",
20878c2ecf20Sopenharmony_ci	.queuecommand = ibmvscsi_queuecommand,
20888c2ecf20Sopenharmony_ci	.eh_timed_out = srp_timed_out,
20898c2ecf20Sopenharmony_ci	.eh_abort_handler = ibmvscsi_eh_abort_handler,
20908c2ecf20Sopenharmony_ci	.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
20918c2ecf20Sopenharmony_ci	.eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
20928c2ecf20Sopenharmony_ci	.slave_configure = ibmvscsi_slave_configure,
20938c2ecf20Sopenharmony_ci	.change_queue_depth = ibmvscsi_change_queue_depth,
20948c2ecf20Sopenharmony_ci	.host_reset = ibmvscsi_host_reset,
20958c2ecf20Sopenharmony_ci	.cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT,
20968c2ecf20Sopenharmony_ci	.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
20978c2ecf20Sopenharmony_ci	.this_id = -1,
20988c2ecf20Sopenharmony_ci	.sg_tablesize = SG_ALL,
20998c2ecf20Sopenharmony_ci	.shost_attrs = ibmvscsi_attrs,
21008c2ecf20Sopenharmony_ci};
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci/**
21038c2ecf20Sopenharmony_ci * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver
21048c2ecf20Sopenharmony_ci *
21058c2ecf20Sopenharmony_ci * @vdev: struct vio_dev for the device whose desired IO mem is to be returned
21068c2ecf20Sopenharmony_ci *
21078c2ecf20Sopenharmony_ci * Return value:
21088c2ecf20Sopenharmony_ci *	Number of bytes of IO data the driver will need to perform well.
21098c2ecf20Sopenharmony_ci */
21108c2ecf20Sopenharmony_cistatic unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
21118c2ecf20Sopenharmony_ci{
21128c2ecf20Sopenharmony_ci	/* iu_storage data allocated in initialize_event_pool */
21138c2ecf20Sopenharmony_ci	unsigned long desired_io = max_events * sizeof(union viosrp_iu);
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	/* add io space for sg data */
21168c2ecf20Sopenharmony_ci	desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 *
21178c2ecf20Sopenharmony_ci	                     IBMVSCSI_CMDS_PER_LUN_DEFAULT);
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	return desired_io;
21208c2ecf20Sopenharmony_ci}
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_cistatic void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
21238c2ecf20Sopenharmony_ci{
21248c2ecf20Sopenharmony_ci	unsigned long flags;
21258c2ecf20Sopenharmony_ci	int rc;
21268c2ecf20Sopenharmony_ci	char *action = "reset";
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
21298c2ecf20Sopenharmony_ci	switch (hostdata->action) {
21308c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_UNBLOCK:
21318c2ecf20Sopenharmony_ci		rc = 0;
21328c2ecf20Sopenharmony_ci		break;
21338c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_RESET:
21348c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
21358c2ecf20Sopenharmony_ci		rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
21368c2ecf20Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
21378c2ecf20Sopenharmony_ci		if (!rc)
21388c2ecf20Sopenharmony_ci			rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
21398c2ecf20Sopenharmony_ci		vio_enable_interrupts(to_vio_dev(hostdata->dev));
21408c2ecf20Sopenharmony_ci		break;
21418c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_REENABLE:
21428c2ecf20Sopenharmony_ci		action = "enable";
21438c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
21448c2ecf20Sopenharmony_ci		rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata);
21458c2ecf20Sopenharmony_ci		spin_lock_irqsave(hostdata->host->host_lock, flags);
21468c2ecf20Sopenharmony_ci		if (!rc)
21478c2ecf20Sopenharmony_ci			rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0);
21488c2ecf20Sopenharmony_ci		break;
21498c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_NONE:
21508c2ecf20Sopenharmony_ci	default:
21518c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
21528c2ecf20Sopenharmony_ci		return;
21538c2ecf20Sopenharmony_ci	}
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	hostdata->action = IBMVSCSI_HOST_ACTION_NONE;
21568c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	if (rc) {
21598c2ecf20Sopenharmony_ci		ibmvscsi_set_request_limit(hostdata, -1);
21608c2ecf20Sopenharmony_ci		dev_err(hostdata->dev, "error after %s\n", action);
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	scsi_unblock_requests(hostdata->host);
21648c2ecf20Sopenharmony_ci}
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_cistatic int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
21678c2ecf20Sopenharmony_ci{
21688c2ecf20Sopenharmony_ci	if (kthread_should_stop())
21698c2ecf20Sopenharmony_ci		return 1;
21708c2ecf20Sopenharmony_ci	switch (hostdata->action) {
21718c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_NONE:
21728c2ecf20Sopenharmony_ci		return 0;
21738c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_RESET:
21748c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_REENABLE:
21758c2ecf20Sopenharmony_ci	case IBMVSCSI_HOST_ACTION_UNBLOCK:
21768c2ecf20Sopenharmony_ci	default:
21778c2ecf20Sopenharmony_ci		break;
21788c2ecf20Sopenharmony_ci	}
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	return 1;
21818c2ecf20Sopenharmony_ci}
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_cistatic int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	unsigned long flags;
21868c2ecf20Sopenharmony_ci	int rc;
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	spin_lock_irqsave(hostdata->host->host_lock, flags);
21898c2ecf20Sopenharmony_ci	rc = __ibmvscsi_work_to_do(hostdata);
21908c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	return rc;
21938c2ecf20Sopenharmony_ci}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_cistatic int ibmvscsi_work(void *data)
21968c2ecf20Sopenharmony_ci{
21978c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = data;
21988c2ecf20Sopenharmony_ci	int rc;
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	set_user_nice(current, MIN_NICE);
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	while (1) {
22038c2ecf20Sopenharmony_ci		rc = wait_event_interruptible(hostdata->work_wait_q,
22048c2ecf20Sopenharmony_ci					      ibmvscsi_work_to_do(hostdata));
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci		BUG_ON(rc);
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci		if (kthread_should_stop())
22098c2ecf20Sopenharmony_ci			break;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci		ibmvscsi_do_work(hostdata);
22128c2ecf20Sopenharmony_ci	}
22138c2ecf20Sopenharmony_ci
22148c2ecf20Sopenharmony_ci	return 0;
22158c2ecf20Sopenharmony_ci}
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci/**
22188c2ecf20Sopenharmony_ci * Called by bus code for each adapter
22198c2ecf20Sopenharmony_ci */
22208c2ecf20Sopenharmony_cistatic int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
22218c2ecf20Sopenharmony_ci{
22228c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata;
22238c2ecf20Sopenharmony_ci	struct Scsi_Host *host;
22248c2ecf20Sopenharmony_ci	struct device *dev = &vdev->dev;
22258c2ecf20Sopenharmony_ci	struct srp_rport_identifiers ids;
22268c2ecf20Sopenharmony_ci	struct srp_rport *rport;
22278c2ecf20Sopenharmony_ci	unsigned long wait_switch = 0;
22288c2ecf20Sopenharmony_ci	int rc;
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	dev_set_drvdata(&vdev->dev, NULL);
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
22338c2ecf20Sopenharmony_ci	if (!host) {
22348c2ecf20Sopenharmony_ci		dev_err(&vdev->dev, "couldn't allocate host data\n");
22358c2ecf20Sopenharmony_ci		goto scsi_host_alloc_failed;
22368c2ecf20Sopenharmony_ci	}
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	host->transportt = ibmvscsi_transport_template;
22398c2ecf20Sopenharmony_ci	hostdata = shost_priv(host);
22408c2ecf20Sopenharmony_ci	memset(hostdata, 0x00, sizeof(*hostdata));
22418c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&hostdata->sent);
22428c2ecf20Sopenharmony_ci	init_waitqueue_head(&hostdata->work_wait_q);
22438c2ecf20Sopenharmony_ci	hostdata->host = host;
22448c2ecf20Sopenharmony_ci	hostdata->dev = dev;
22458c2ecf20Sopenharmony_ci	ibmvscsi_set_request_limit(hostdata, -1);
22468c2ecf20Sopenharmony_ci	hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	if (map_persist_bufs(hostdata)) {
22498c2ecf20Sopenharmony_ci		dev_err(&vdev->dev, "couldn't map persistent buffers\n");
22508c2ecf20Sopenharmony_ci		goto persist_bufs_failed;
22518c2ecf20Sopenharmony_ci	}
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
22548c2ecf20Sopenharmony_ci					    "ibmvscsi", host->host_no);
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	if (IS_ERR(hostdata->work_thread)) {
22578c2ecf20Sopenharmony_ci		dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
22588c2ecf20Sopenharmony_ci			PTR_ERR(hostdata->work_thread));
22598c2ecf20Sopenharmony_ci		goto init_crq_failed;
22608c2ecf20Sopenharmony_ci	}
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci	rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_events);
22638c2ecf20Sopenharmony_ci	if (rc != 0 && rc != H_RESOURCE) {
22648c2ecf20Sopenharmony_ci		dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
22658c2ecf20Sopenharmony_ci		goto kill_kthread;
22668c2ecf20Sopenharmony_ci	}
22678c2ecf20Sopenharmony_ci	if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
22688c2ecf20Sopenharmony_ci		dev_err(&vdev->dev, "couldn't initialize event pool\n");
22698c2ecf20Sopenharmony_ci		goto init_pool_failed;
22708c2ecf20Sopenharmony_ci	}
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci	host->max_lun = IBMVSCSI_MAX_LUN;
22738c2ecf20Sopenharmony_ci	host->max_id = max_id;
22748c2ecf20Sopenharmony_ci	host->max_channel = max_channel;
22758c2ecf20Sopenharmony_ci	host->max_cmd_len = 16;
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci	dev_info(dev,
22788c2ecf20Sopenharmony_ci		 "Maximum ID: %d Maximum LUN: %llu Maximum Channel: %d\n",
22798c2ecf20Sopenharmony_ci		 host->max_id, host->max_lun, host->max_channel);
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	if (scsi_add_host(hostdata->host, hostdata->dev))
22828c2ecf20Sopenharmony_ci		goto add_host_failed;
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	/* we don't have a proper target_port_id so let's use the fake one */
22858c2ecf20Sopenharmony_ci	memcpy(ids.port_id, hostdata->madapter_info.partition_name,
22868c2ecf20Sopenharmony_ci	       sizeof(ids.port_id));
22878c2ecf20Sopenharmony_ci	ids.roles = SRP_RPORT_ROLE_TARGET;
22888c2ecf20Sopenharmony_ci	rport = srp_rport_add(host, &ids);
22898c2ecf20Sopenharmony_ci	if (IS_ERR(rport))
22908c2ecf20Sopenharmony_ci		goto add_srp_port_failed;
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci	/* Try to send an initialization message.  Note that this is allowed
22938c2ecf20Sopenharmony_ci	 * to fail if the other end is not acive.  In that case we don't
22948c2ecf20Sopenharmony_ci	 * want to scan
22958c2ecf20Sopenharmony_ci	 */
22968c2ecf20Sopenharmony_ci	if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
22978c2ecf20Sopenharmony_ci	    || rc == H_RESOURCE) {
22988c2ecf20Sopenharmony_ci		/*
22998c2ecf20Sopenharmony_ci		 * Wait around max init_timeout secs for the adapter to finish
23008c2ecf20Sopenharmony_ci		 * initializing. When we are done initializing, we will have a
23018c2ecf20Sopenharmony_ci		 * valid request_limit.  We don't want Linux scanning before
23028c2ecf20Sopenharmony_ci		 * we are ready.
23038c2ecf20Sopenharmony_ci		 */
23048c2ecf20Sopenharmony_ci		for (wait_switch = jiffies + (init_timeout * HZ);
23058c2ecf20Sopenharmony_ci		     time_before(jiffies, wait_switch) &&
23068c2ecf20Sopenharmony_ci		     atomic_read(&hostdata->request_limit) < 2;) {
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci			msleep(10);
23098c2ecf20Sopenharmony_ci		}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci		/* if we now have a valid request_limit, initiate a scan */
23128c2ecf20Sopenharmony_ci		if (atomic_read(&hostdata->request_limit) > 0)
23138c2ecf20Sopenharmony_ci			scsi_scan_host(host);
23148c2ecf20Sopenharmony_ci	}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci	dev_set_drvdata(&vdev->dev, hostdata);
23178c2ecf20Sopenharmony_ci	spin_lock(&ibmvscsi_driver_lock);
23188c2ecf20Sopenharmony_ci	list_add_tail(&hostdata->host_list, &ibmvscsi_head);
23198c2ecf20Sopenharmony_ci	spin_unlock(&ibmvscsi_driver_lock);
23208c2ecf20Sopenharmony_ci	return 0;
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci      add_srp_port_failed:
23238c2ecf20Sopenharmony_ci	scsi_remove_host(hostdata->host);
23248c2ecf20Sopenharmony_ci      add_host_failed:
23258c2ecf20Sopenharmony_ci	release_event_pool(&hostdata->pool, hostdata);
23268c2ecf20Sopenharmony_ci      init_pool_failed:
23278c2ecf20Sopenharmony_ci	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_events);
23288c2ecf20Sopenharmony_ci      kill_kthread:
23298c2ecf20Sopenharmony_ci      kthread_stop(hostdata->work_thread);
23308c2ecf20Sopenharmony_ci      init_crq_failed:
23318c2ecf20Sopenharmony_ci	unmap_persist_bufs(hostdata);
23328c2ecf20Sopenharmony_ci      persist_bufs_failed:
23338c2ecf20Sopenharmony_ci	scsi_host_put(host);
23348c2ecf20Sopenharmony_ci      scsi_host_alloc_failed:
23358c2ecf20Sopenharmony_ci	return -1;
23368c2ecf20Sopenharmony_ci}
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_cistatic int ibmvscsi_remove(struct vio_dev *vdev)
23398c2ecf20Sopenharmony_ci{
23408c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev);
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	srp_remove_host(hostdata->host);
23438c2ecf20Sopenharmony_ci	scsi_remove_host(hostdata->host);
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci	purge_requests(hostdata, DID_ERROR);
23468c2ecf20Sopenharmony_ci	release_event_pool(&hostdata->pool, hostdata);
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
23498c2ecf20Sopenharmony_ci					max_events);
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci	kthread_stop(hostdata->work_thread);
23528c2ecf20Sopenharmony_ci	unmap_persist_bufs(hostdata);
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	spin_lock(&ibmvscsi_driver_lock);
23558c2ecf20Sopenharmony_ci	list_del(&hostdata->host_list);
23568c2ecf20Sopenharmony_ci	spin_unlock(&ibmvscsi_driver_lock);
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	scsi_host_put(hostdata->host);
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	return 0;
23618c2ecf20Sopenharmony_ci}
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci/**
23648c2ecf20Sopenharmony_ci * ibmvscsi_resume: Resume from suspend
23658c2ecf20Sopenharmony_ci * @dev:	device struct
23668c2ecf20Sopenharmony_ci *
23678c2ecf20Sopenharmony_ci * We may have lost an interrupt across suspend/resume, so kick the
23688c2ecf20Sopenharmony_ci * interrupt handler
23698c2ecf20Sopenharmony_ci */
23708c2ecf20Sopenharmony_cistatic int ibmvscsi_resume(struct device *dev)
23718c2ecf20Sopenharmony_ci{
23728c2ecf20Sopenharmony_ci	struct ibmvscsi_host_data *hostdata = dev_get_drvdata(dev);
23738c2ecf20Sopenharmony_ci	vio_disable_interrupts(to_vio_dev(hostdata->dev));
23748c2ecf20Sopenharmony_ci	tasklet_schedule(&hostdata->srp_task);
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	return 0;
23778c2ecf20Sopenharmony_ci}
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci/**
23808c2ecf20Sopenharmony_ci * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we
23818c2ecf20Sopenharmony_ci * support.
23828c2ecf20Sopenharmony_ci */
23838c2ecf20Sopenharmony_cistatic const struct vio_device_id ibmvscsi_device_table[] = {
23848c2ecf20Sopenharmony_ci	{"vscsi", "IBM,v-scsi"},
23858c2ecf20Sopenharmony_ci	{ "", "" }
23868c2ecf20Sopenharmony_ci};
23878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_cistatic const struct dev_pm_ops ibmvscsi_pm_ops = {
23908c2ecf20Sopenharmony_ci	.resume = ibmvscsi_resume
23918c2ecf20Sopenharmony_ci};
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_cistatic struct vio_driver ibmvscsi_driver = {
23948c2ecf20Sopenharmony_ci	.id_table = ibmvscsi_device_table,
23958c2ecf20Sopenharmony_ci	.probe = ibmvscsi_probe,
23968c2ecf20Sopenharmony_ci	.remove = ibmvscsi_remove,
23978c2ecf20Sopenharmony_ci	.get_desired_dma = ibmvscsi_get_desired_dma,
23988c2ecf20Sopenharmony_ci	.name = "ibmvscsi",
23998c2ecf20Sopenharmony_ci	.pm = &ibmvscsi_pm_ops,
24008c2ecf20Sopenharmony_ci};
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_cistatic struct srp_function_template ibmvscsi_transport_functions = {
24038c2ecf20Sopenharmony_ci};
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_cistatic int __init ibmvscsi_module_init(void)
24068c2ecf20Sopenharmony_ci{
24078c2ecf20Sopenharmony_ci	int ret;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	/* Ensure we have two requests to do error recovery */
24108c2ecf20Sopenharmony_ci	driver_template.can_queue = max_requests;
24118c2ecf20Sopenharmony_ci	max_events = max_requests + 2;
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	if (!firmware_has_feature(FW_FEATURE_VIO))
24148c2ecf20Sopenharmony_ci		return -ENODEV;
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	ibmvscsi_transport_template =
24178c2ecf20Sopenharmony_ci		srp_attach_transport(&ibmvscsi_transport_functions);
24188c2ecf20Sopenharmony_ci	if (!ibmvscsi_transport_template)
24198c2ecf20Sopenharmony_ci		return -ENOMEM;
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	ret = vio_register_driver(&ibmvscsi_driver);
24228c2ecf20Sopenharmony_ci	if (ret)
24238c2ecf20Sopenharmony_ci		srp_release_transport(ibmvscsi_transport_template);
24248c2ecf20Sopenharmony_ci	return ret;
24258c2ecf20Sopenharmony_ci}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_cistatic void __exit ibmvscsi_module_exit(void)
24288c2ecf20Sopenharmony_ci{
24298c2ecf20Sopenharmony_ci	vio_unregister_driver(&ibmvscsi_driver);
24308c2ecf20Sopenharmony_ci	srp_release_transport(ibmvscsi_transport_template);
24318c2ecf20Sopenharmony_ci}
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_cimodule_init(ibmvscsi_module_init);
24348c2ecf20Sopenharmony_cimodule_exit(ibmvscsi_module_exit);
2435