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