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