18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Linux driver for VMware's para-virtualized SCSI HBA. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2008-2014, VMware, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License as published by the 88c2ecf20Sopenharmony_ci * Free Software Foundation; version 2 of the License and no later version. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 118c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 128c2ecf20Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 138c2ecf20Sopenharmony_ci * NON INFRINGEMENT. See the GNU General Public License for more 148c2ecf20Sopenharmony_ci * details. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 178c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 188c2ecf20Sopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Maintained by: Jim Gill <jgill@vmware.com> 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/kernel.h> 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 298c2ecf20Sopenharmony_ci#include <linux/pci.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 328c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 338c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 348c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 358c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "vmw_pvscsi.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC); 428c2ecf20Sopenharmony_ciMODULE_AUTHOR("VMware, Inc."); 438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 448c2ecf20Sopenharmony_ciMODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8 478c2ecf20Sopenharmony_ci#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1 488c2ecf20Sopenharmony_ci#define PVSCSI_DEFAULT_QUEUE_DEPTH 254 498c2ecf20Sopenharmony_ci#define SGL_SIZE PAGE_SIZE 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct pvscsi_sg_list { 528c2ecf20Sopenharmony_ci struct PVSCSISGElement sge[PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT]; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct pvscsi_ctx { 568c2ecf20Sopenharmony_ci /* 578c2ecf20Sopenharmony_ci * The index of the context in cmd_map serves as the context ID for a 588c2ecf20Sopenharmony_ci * 1-to-1 mapping completions back to requests. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 618c2ecf20Sopenharmony_ci struct pvscsi_sg_list *sgl; 628c2ecf20Sopenharmony_ci struct list_head list; 638c2ecf20Sopenharmony_ci dma_addr_t dataPA; 648c2ecf20Sopenharmony_ci dma_addr_t sensePA; 658c2ecf20Sopenharmony_ci dma_addr_t sglPA; 668c2ecf20Sopenharmony_ci struct completion *abort_cmp; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct pvscsi_adapter { 708c2ecf20Sopenharmony_ci char *mmioBase; 718c2ecf20Sopenharmony_ci u8 rev; 728c2ecf20Sopenharmony_ci bool use_msg; 738c2ecf20Sopenharmony_ci bool use_req_threshold; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci spinlock_t hw_lock; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci struct workqueue_struct *workqueue; 788c2ecf20Sopenharmony_ci struct work_struct work; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci struct PVSCSIRingReqDesc *req_ring; 818c2ecf20Sopenharmony_ci unsigned req_pages; 828c2ecf20Sopenharmony_ci unsigned req_depth; 838c2ecf20Sopenharmony_ci dma_addr_t reqRingPA; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci struct PVSCSIRingCmpDesc *cmp_ring; 868c2ecf20Sopenharmony_ci unsigned cmp_pages; 878c2ecf20Sopenharmony_ci dma_addr_t cmpRingPA; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci struct PVSCSIRingMsgDesc *msg_ring; 908c2ecf20Sopenharmony_ci unsigned msg_pages; 918c2ecf20Sopenharmony_ci dma_addr_t msgRingPA; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci struct PVSCSIRingsState *rings_state; 948c2ecf20Sopenharmony_ci dma_addr_t ringStatePA; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci struct pci_dev *dev; 978c2ecf20Sopenharmony_ci struct Scsi_Host *host; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci struct list_head cmd_pool; 1008c2ecf20Sopenharmony_ci struct pvscsi_ctx *cmd_map; 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Command line parameters */ 1058c2ecf20Sopenharmony_cistatic int pvscsi_ring_pages; 1068c2ecf20Sopenharmony_cistatic int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING; 1078c2ecf20Sopenharmony_cistatic int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH; 1088c2ecf20Sopenharmony_cistatic bool pvscsi_disable_msi; 1098c2ecf20Sopenharmony_cistatic bool pvscsi_disable_msix; 1108c2ecf20Sopenharmony_cistatic bool pvscsi_use_msg = true; 1118c2ecf20Sopenharmony_cistatic bool pvscsi_use_req_threshold = true; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define PVSCSI_RW (S_IRUSR | S_IWUSR) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cimodule_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW); 1168c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default=" 1178c2ecf20Sopenharmony_ci __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) 1188c2ecf20Sopenharmony_ci "[up to 16 targets]," 1198c2ecf20Sopenharmony_ci __stringify(PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) 1208c2ecf20Sopenharmony_ci "[for 16+ targets])"); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cimodule_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW); 1238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default=" 1248c2ecf20Sopenharmony_ci __stringify(PVSCSI_DEFAULT_NUM_PAGES_MSG_RING) ")"); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cimodule_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW); 1278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default=" 1288c2ecf20Sopenharmony_ci __stringify(PVSCSI_DEFAULT_QUEUE_DEPTH) ")"); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cimodule_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW); 1318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)"); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cimodule_param_named(disable_msix, pvscsi_disable_msix, bool, PVSCSI_RW); 1348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)"); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cimodule_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW); 1378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)"); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cimodule_param_named(use_req_threshold, pvscsi_use_req_threshold, 1408c2ecf20Sopenharmony_ci bool, PVSCSI_RW); 1418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_req_threshold, "Use driver-based request coalescing if configured - (default=1)"); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic const struct pci_device_id pvscsi_pci_tbl[] = { 1448c2ecf20Sopenharmony_ci { PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) }, 1458c2ecf20Sopenharmony_ci { 0 } 1468c2ecf20Sopenharmony_ci}; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pvscsi_pci_tbl); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic struct device * 1518c2ecf20Sopenharmony_cipvscsi_dev(const struct pvscsi_adapter *adapter) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci return &(adapter->dev->dev); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct pvscsi_ctx * 1578c2ecf20Sopenharmony_cipvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx, *end; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci end = &adapter->cmd_map[adapter->req_depth]; 1628c2ecf20Sopenharmony_ci for (ctx = adapter->cmd_map; ctx < end; ctx++) 1638c2ecf20Sopenharmony_ci if (ctx->cmd == cmd) 1648c2ecf20Sopenharmony_ci return ctx; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return NULL; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic struct pvscsi_ctx * 1708c2ecf20Sopenharmony_cipvscsi_acquire_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (list_empty(&adapter->cmd_pool)) 1758c2ecf20Sopenharmony_ci return NULL; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ctx = list_first_entry(&adapter->cmd_pool, struct pvscsi_ctx, list); 1788c2ecf20Sopenharmony_ci ctx->cmd = cmd; 1798c2ecf20Sopenharmony_ci list_del(&ctx->list); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return ctx; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void pvscsi_release_context(struct pvscsi_adapter *adapter, 1858c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci ctx->cmd = NULL; 1888c2ecf20Sopenharmony_ci ctx->abort_cmp = NULL; 1898c2ecf20Sopenharmony_ci list_add(&ctx->list, &adapter->cmd_pool); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * Map a pvscsi_ctx struct to a context ID field value; we map to a simple 1948c2ecf20Sopenharmony_ci * non-zero integer. ctx always points to an entry in cmd_map array, hence 1958c2ecf20Sopenharmony_ci * the return value is always >=1. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic u64 pvscsi_map_context(const struct pvscsi_adapter *adapter, 1988c2ecf20Sopenharmony_ci const struct pvscsi_ctx *ctx) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci return ctx - adapter->cmd_map + 1; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic struct pvscsi_ctx * 2048c2ecf20Sopenharmony_cipvscsi_get_context(const struct pvscsi_adapter *adapter, u64 context) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci return &adapter->cmd_map[context - 1]; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void pvscsi_reg_write(const struct pvscsi_adapter *adapter, 2108c2ecf20Sopenharmony_ci u32 offset, u32 val) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci writel(val, adapter->mmioBase + offset); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic u32 pvscsi_reg_read(const struct pvscsi_adapter *adapter, u32 offset) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return readl(adapter->mmioBase + offset); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci return pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_INTR_STATUS); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter, 2268c2ecf20Sopenharmony_ci u32 val) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_STATUS, val); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic void pvscsi_unmask_intr(const struct pvscsi_adapter *adapter) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci u32 intr_bits; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci intr_bits = PVSCSI_INTR_CMPL_MASK; 2368c2ecf20Sopenharmony_ci if (adapter->use_msg) 2378c2ecf20Sopenharmony_ci intr_bits |= PVSCSI_INTR_MSG_MASK; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, intr_bits); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void pvscsi_mask_intr(const struct pvscsi_adapter *adapter) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, 0); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void pvscsi_write_cmd_desc(const struct pvscsi_adapter *adapter, 2488c2ecf20Sopenharmony_ci u32 cmd, const void *desc, size_t len) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci const u32 *ptr = desc; 2518c2ecf20Sopenharmony_ci size_t i; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci len /= sizeof(*ptr); 2548c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, cmd); 2558c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 2568c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, 2578c2ecf20Sopenharmony_ci PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter, 2618c2ecf20Sopenharmony_ci const struct pvscsi_ctx *ctx) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct PVSCSICmdDescAbortCmd cmd = { 0 }; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci cmd.target = ctx->cmd->device->id; 2668c2ecf20Sopenharmony_ci cmd.context = pvscsi_map_context(adapter, ctx); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd)); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void pvscsi_kick_rw_io(const struct pvscsi_adapter *adapter) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_RW_IO, 0); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int scsi_is_rw(unsigned char op) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci return op == READ_6 || op == WRITE_6 || 2848c2ecf20Sopenharmony_ci op == READ_10 || op == WRITE_10 || 2858c2ecf20Sopenharmony_ci op == READ_12 || op == WRITE_12 || 2868c2ecf20Sopenharmony_ci op == READ_16 || op == WRITE_16; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void pvscsi_kick_io(const struct pvscsi_adapter *adapter, 2908c2ecf20Sopenharmony_ci unsigned char op) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci if (scsi_is_rw(op)) { 2938c2ecf20Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (!adapter->use_req_threshold || 2968c2ecf20Sopenharmony_ci s->reqProdIdx - s->reqConsIdx >= s->reqCallThreshold) 2978c2ecf20Sopenharmony_ci pvscsi_kick_rw_io(adapter); 2988c2ecf20Sopenharmony_ci } else { 2998c2ecf20Sopenharmony_ci pvscsi_process_request_ring(adapter); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic void ll_adapter_reset(const struct pvscsi_adapter *adapter) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci dev_dbg(pvscsi_dev(adapter), "Adapter Reset on %p\n", adapter); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic void ll_bus_reset(const struct pvscsi_adapter *adapter) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci dev_dbg(pvscsi_dev(adapter), "Resetting bus on %p\n", adapter); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct PVSCSICmdDescResetDevice cmd = { 0 }; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci dev_dbg(pvscsi_dev(adapter), "Resetting device: target=%u\n", target); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci cmd.target = target; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE, 3268c2ecf20Sopenharmony_ci &cmd, sizeof(cmd)); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void pvscsi_create_sg(struct pvscsi_ctx *ctx, 3308c2ecf20Sopenharmony_ci struct scatterlist *sg, unsigned count) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci unsigned i; 3338c2ecf20Sopenharmony_ci struct PVSCSISGElement *sge; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci sge = &ctx->sgl->sge[0]; 3388c2ecf20Sopenharmony_ci for (i = 0; i < count; i++, sg = sg_next(sg)) { 3398c2ecf20Sopenharmony_ci sge[i].addr = sg_dma_address(sg); 3408c2ecf20Sopenharmony_ci sge[i].length = sg_dma_len(sg); 3418c2ecf20Sopenharmony_ci sge[i].flags = 0; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* 3468c2ecf20Sopenharmony_ci * Map all data buffers for a command into PCI space and 3478c2ecf20Sopenharmony_ci * setup the scatter/gather list if needed. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_cistatic int pvscsi_map_buffers(struct pvscsi_adapter *adapter, 3508c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd, 3518c2ecf20Sopenharmony_ci struct PVSCSIRingReqDesc *e) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci unsigned count; 3548c2ecf20Sopenharmony_ci unsigned bufflen = scsi_bufflen(cmd); 3558c2ecf20Sopenharmony_ci struct scatterlist *sg; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci e->dataLen = bufflen; 3588c2ecf20Sopenharmony_ci e->dataAddr = 0; 3598c2ecf20Sopenharmony_ci if (bufflen == 0) 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci sg = scsi_sglist(cmd); 3638c2ecf20Sopenharmony_ci count = scsi_sg_count(cmd); 3648c2ecf20Sopenharmony_ci if (count != 0) { 3658c2ecf20Sopenharmony_ci int segs = scsi_dma_map(cmd); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (segs == -ENOMEM) { 3688c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 3698c2ecf20Sopenharmony_ci "vmw_pvscsi: Failed to map cmd sglist for DMA.\n"); 3708c2ecf20Sopenharmony_ci return -ENOMEM; 3718c2ecf20Sopenharmony_ci } else if (segs > 1) { 3728c2ecf20Sopenharmony_ci pvscsi_create_sg(ctx, sg, segs); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; 3758c2ecf20Sopenharmony_ci ctx->sglPA = dma_map_single(&adapter->dev->dev, 3768c2ecf20Sopenharmony_ci ctx->sgl, SGL_SIZE, DMA_TO_DEVICE); 3778c2ecf20Sopenharmony_ci if (dma_mapping_error(&adapter->dev->dev, ctx->sglPA)) { 3788c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, cmd, 3798c2ecf20Sopenharmony_ci "vmw_pvscsi: Failed to map ctx sglist for DMA.\n"); 3808c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 3818c2ecf20Sopenharmony_ci ctx->sglPA = 0; 3828c2ecf20Sopenharmony_ci return -ENOMEM; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci e->dataAddr = ctx->sglPA; 3858c2ecf20Sopenharmony_ci } else 3868c2ecf20Sopenharmony_ci e->dataAddr = sg_dma_address(sg); 3878c2ecf20Sopenharmony_ci } else { 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * In case there is no S/G list, scsi_sglist points 3908c2ecf20Sopenharmony_ci * directly to the buffer. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci ctx->dataPA = dma_map_single(&adapter->dev->dev, sg, bufflen, 3938c2ecf20Sopenharmony_ci cmd->sc_data_direction); 3948c2ecf20Sopenharmony_ci if (dma_mapping_error(&adapter->dev->dev, ctx->dataPA)) { 3958c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 3968c2ecf20Sopenharmony_ci "vmw_pvscsi: Failed to map direct data buffer for DMA.\n"); 3978c2ecf20Sopenharmony_ci return -ENOMEM; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci e->dataAddr = ctx->dataPA; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * The device incorrectly doesn't clear the first byte of the sense 4078c2ecf20Sopenharmony_ci * buffer in some cases. We have to do it ourselves. 4088c2ecf20Sopenharmony_ci * Otherwise we run into trouble when SWIOTLB is forced. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_cistatic void pvscsi_patch_sense(struct scsi_cmnd *cmd) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci if (cmd->sense_buffer) 4138c2ecf20Sopenharmony_ci cmd->sense_buffer[0] = 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, 4178c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 4208c2ecf20Sopenharmony_ci unsigned bufflen; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci cmd = ctx->cmd; 4238c2ecf20Sopenharmony_ci bufflen = scsi_bufflen(cmd); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (bufflen != 0) { 4268c2ecf20Sopenharmony_ci unsigned count = scsi_sg_count(cmd); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (count != 0) { 4298c2ecf20Sopenharmony_ci scsi_dma_unmap(cmd); 4308c2ecf20Sopenharmony_ci if (ctx->sglPA) { 4318c2ecf20Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->sglPA, 4328c2ecf20Sopenharmony_ci SGL_SIZE, DMA_TO_DEVICE); 4338c2ecf20Sopenharmony_ci ctx->sglPA = 0; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci } else 4368c2ecf20Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->dataPA, 4378c2ecf20Sopenharmony_ci bufflen, cmd->sc_data_direction); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci if (cmd->sense_buffer) 4408c2ecf20Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->sensePA, 4418c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci adapter->rings_state = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, 4478c2ecf20Sopenharmony_ci &adapter->ringStatePA, GFP_KERNEL); 4488c2ecf20Sopenharmony_ci if (!adapter->rings_state) 4498c2ecf20Sopenharmony_ci return -ENOMEM; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci adapter->req_pages = min(PVSCSI_MAX_NUM_PAGES_REQ_RING, 4528c2ecf20Sopenharmony_ci pvscsi_ring_pages); 4538c2ecf20Sopenharmony_ci adapter->req_depth = adapter->req_pages 4548c2ecf20Sopenharmony_ci * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; 4558c2ecf20Sopenharmony_ci adapter->req_ring = dma_alloc_coherent(&adapter->dev->dev, 4568c2ecf20Sopenharmony_ci adapter->req_pages * PAGE_SIZE, &adapter->reqRingPA, 4578c2ecf20Sopenharmony_ci GFP_KERNEL); 4588c2ecf20Sopenharmony_ci if (!adapter->req_ring) 4598c2ecf20Sopenharmony_ci return -ENOMEM; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING, 4628c2ecf20Sopenharmony_ci pvscsi_ring_pages); 4638c2ecf20Sopenharmony_ci adapter->cmp_ring = dma_alloc_coherent(&adapter->dev->dev, 4648c2ecf20Sopenharmony_ci adapter->cmp_pages * PAGE_SIZE, &adapter->cmpRingPA, 4658c2ecf20Sopenharmony_ci GFP_KERNEL); 4668c2ecf20Sopenharmony_ci if (!adapter->cmp_ring) 4678c2ecf20Sopenharmony_ci return -ENOMEM; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->ringStatePA, PAGE_SIZE)); 4708c2ecf20Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->reqRingPA, PAGE_SIZE)); 4718c2ecf20Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->cmpRingPA, PAGE_SIZE)); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (!adapter->use_msg) 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING, 4778c2ecf20Sopenharmony_ci pvscsi_msg_ring_pages); 4788c2ecf20Sopenharmony_ci adapter->msg_ring = dma_alloc_coherent(&adapter->dev->dev, 4798c2ecf20Sopenharmony_ci adapter->msg_pages * PAGE_SIZE, &adapter->msgRingPA, 4808c2ecf20Sopenharmony_ci GFP_KERNEL); 4818c2ecf20Sopenharmony_ci if (!adapter->msg_ring) 4828c2ecf20Sopenharmony_ci return -ENOMEM; 4838c2ecf20Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE)); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct PVSCSICmdDescSetupRings cmd = { 0 }; 4918c2ecf20Sopenharmony_ci dma_addr_t base; 4928c2ecf20Sopenharmony_ci unsigned i; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci cmd.ringsStatePPN = adapter->ringStatePA >> PAGE_SHIFT; 4958c2ecf20Sopenharmony_ci cmd.reqRingNumPages = adapter->req_pages; 4968c2ecf20Sopenharmony_ci cmd.cmpRingNumPages = adapter->cmp_pages; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci base = adapter->reqRingPA; 4998c2ecf20Sopenharmony_ci for (i = 0; i < adapter->req_pages; i++) { 5008c2ecf20Sopenharmony_ci cmd.reqRingPPNs[i] = base >> PAGE_SHIFT; 5018c2ecf20Sopenharmony_ci base += PAGE_SIZE; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci base = adapter->cmpRingPA; 5058c2ecf20Sopenharmony_ci for (i = 0; i < adapter->cmp_pages; i++) { 5068c2ecf20Sopenharmony_ci cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT; 5078c2ecf20Sopenharmony_ci base += PAGE_SIZE; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci memset(adapter->rings_state, 0, PAGE_SIZE); 5118c2ecf20Sopenharmony_ci memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE); 5128c2ecf20Sopenharmony_ci memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS, 5158c2ecf20Sopenharmony_ci &cmd, sizeof(cmd)); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (adapter->use_msg) { 5188c2ecf20Sopenharmony_ci struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 }; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci cmd_msg.numPages = adapter->msg_pages; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci base = adapter->msgRingPA; 5238c2ecf20Sopenharmony_ci for (i = 0; i < adapter->msg_pages; i++) { 5248c2ecf20Sopenharmony_ci cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT; 5258c2ecf20Sopenharmony_ci base += PAGE_SIZE; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci memset(adapter->msg_ring, 0, adapter->msg_pages * PAGE_SIZE); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_MSG_RING, 5308c2ecf20Sopenharmony_ci &cmd_msg, sizeof(cmd_msg)); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic int pvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci if (!sdev->tagged_supported) 5378c2ecf20Sopenharmony_ci qdepth = 1; 5388c2ecf20Sopenharmony_ci return scsi_change_queue_depth(sdev, qdepth); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci/* 5428c2ecf20Sopenharmony_ci * Pull a completion descriptor off and pass the completion back 5438c2ecf20Sopenharmony_ci * to the SCSI mid layer. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic void pvscsi_complete_request(struct pvscsi_adapter *adapter, 5468c2ecf20Sopenharmony_ci const struct PVSCSIRingCmpDesc *e) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx; 5498c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 5508c2ecf20Sopenharmony_ci struct completion *abort_cmp; 5518c2ecf20Sopenharmony_ci u32 btstat = e->hostStatus; 5528c2ecf20Sopenharmony_ci u32 sdstat = e->scsiStatus; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci ctx = pvscsi_get_context(adapter, e->context); 5558c2ecf20Sopenharmony_ci cmd = ctx->cmd; 5568c2ecf20Sopenharmony_ci abort_cmp = ctx->abort_cmp; 5578c2ecf20Sopenharmony_ci pvscsi_unmap_buffers(adapter, ctx); 5588c2ecf20Sopenharmony_ci if (sdstat != SAM_STAT_CHECK_CONDITION) 5598c2ecf20Sopenharmony_ci pvscsi_patch_sense(cmd); 5608c2ecf20Sopenharmony_ci pvscsi_release_context(adapter, ctx); 5618c2ecf20Sopenharmony_ci if (abort_cmp) { 5628c2ecf20Sopenharmony_ci /* 5638c2ecf20Sopenharmony_ci * The command was requested to be aborted. Just signal that 5648c2ecf20Sopenharmony_ci * the request completed and swallow the actual cmd completion 5658c2ecf20Sopenharmony_ci * here. The abort handler will post a completion for this 5668c2ecf20Sopenharmony_ci * command indicating that it got successfully aborted. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci complete(abort_cmp); 5698c2ecf20Sopenharmony_ci return; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci cmd->result = 0; 5738c2ecf20Sopenharmony_ci if (sdstat != SAM_STAT_GOOD && 5748c2ecf20Sopenharmony_ci (btstat == BTSTAT_SUCCESS || 5758c2ecf20Sopenharmony_ci btstat == BTSTAT_LINKED_COMMAND_COMPLETED || 5768c2ecf20Sopenharmony_ci btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { 5778c2ecf20Sopenharmony_ci if (sdstat == SAM_STAT_COMMAND_TERMINATED) { 5788c2ecf20Sopenharmony_ci cmd->result = (DID_RESET << 16); 5798c2ecf20Sopenharmony_ci } else { 5808c2ecf20Sopenharmony_ci cmd->result = (DID_OK << 16) | sdstat; 5818c2ecf20Sopenharmony_ci if (sdstat == SAM_STAT_CHECK_CONDITION && 5828c2ecf20Sopenharmony_ci cmd->sense_buffer) 5838c2ecf20Sopenharmony_ci cmd->result |= (DRIVER_SENSE << 24); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci } else 5868c2ecf20Sopenharmony_ci switch (btstat) { 5878c2ecf20Sopenharmony_ci case BTSTAT_SUCCESS: 5888c2ecf20Sopenharmony_ci case BTSTAT_LINKED_COMMAND_COMPLETED: 5898c2ecf20Sopenharmony_ci case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: 5908c2ecf20Sopenharmony_ci /* 5918c2ecf20Sopenharmony_ci * Commands like INQUIRY may transfer less data than 5928c2ecf20Sopenharmony_ci * requested by the initiator via bufflen. Set residual 5938c2ecf20Sopenharmony_ci * count to make upper layer aware of the actual amount 5948c2ecf20Sopenharmony_ci * of data returned. There are cases when controller 5958c2ecf20Sopenharmony_ci * returns zero dataLen with non zero data - do not set 5968c2ecf20Sopenharmony_ci * residual count in that case. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_ci if (e->dataLen && (e->dataLen < scsi_bufflen(cmd))) 5998c2ecf20Sopenharmony_ci scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen); 6008c2ecf20Sopenharmony_ci cmd->result = (DID_OK << 16); 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci case BTSTAT_DATARUN: 6048c2ecf20Sopenharmony_ci case BTSTAT_DATA_UNDERRUN: 6058c2ecf20Sopenharmony_ci /* Report residual data in underruns */ 6068c2ecf20Sopenharmony_ci scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen); 6078c2ecf20Sopenharmony_ci cmd->result = (DID_ERROR << 16); 6088c2ecf20Sopenharmony_ci break; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci case BTSTAT_SELTIMEO: 6118c2ecf20Sopenharmony_ci /* Our emulation returns this for non-connected devs */ 6128c2ecf20Sopenharmony_ci cmd->result = (DID_BAD_TARGET << 16); 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci case BTSTAT_LUNMISMATCH: 6168c2ecf20Sopenharmony_ci case BTSTAT_TAGREJECT: 6178c2ecf20Sopenharmony_ci case BTSTAT_BADMSG: 6188c2ecf20Sopenharmony_ci cmd->result = (DRIVER_INVALID << 24); 6198c2ecf20Sopenharmony_ci fallthrough; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci case BTSTAT_HAHARDWARE: 6228c2ecf20Sopenharmony_ci case BTSTAT_INVPHASE: 6238c2ecf20Sopenharmony_ci case BTSTAT_HATIMEOUT: 6248c2ecf20Sopenharmony_ci case BTSTAT_NORESPONSE: 6258c2ecf20Sopenharmony_ci case BTSTAT_DISCONNECT: 6268c2ecf20Sopenharmony_ci case BTSTAT_HASOFTWARE: 6278c2ecf20Sopenharmony_ci case BTSTAT_BUSFREE: 6288c2ecf20Sopenharmony_ci case BTSTAT_SENSFAILED: 6298c2ecf20Sopenharmony_ci cmd->result |= (DID_ERROR << 16); 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci case BTSTAT_SENTRST: 6338c2ecf20Sopenharmony_ci case BTSTAT_RECVRST: 6348c2ecf20Sopenharmony_ci case BTSTAT_BUSRESET: 6358c2ecf20Sopenharmony_ci cmd->result = (DID_RESET << 16); 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci case BTSTAT_ABORTQUEUE: 6398c2ecf20Sopenharmony_ci cmd->result = (DID_BUS_BUSY << 16); 6408c2ecf20Sopenharmony_ci break; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci case BTSTAT_SCSIPARITY: 6438c2ecf20Sopenharmony_ci cmd->result = (DID_PARITY << 16); 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci default: 6478c2ecf20Sopenharmony_ci cmd->result = (DID_ERROR << 16); 6488c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 6498c2ecf20Sopenharmony_ci "Unknown completion status: 0x%x\n", 6508c2ecf20Sopenharmony_ci btstat); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci dev_dbg(&cmd->device->sdev_gendev, 6548c2ecf20Sopenharmony_ci "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n", 6558c2ecf20Sopenharmony_ci cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/* 6618c2ecf20Sopenharmony_ci * barrier usage : Since the PVSCSI device is emulated, there could be cases 6628c2ecf20Sopenharmony_ci * where we may want to serialize some accesses between the driver and the 6638c2ecf20Sopenharmony_ci * emulation layer. We use compiler barriers instead of the more expensive 6648c2ecf20Sopenharmony_ci * memory barriers because PVSCSI is only supported on X86 which has strong 6658c2ecf20Sopenharmony_ci * memory access ordering. 6668c2ecf20Sopenharmony_ci */ 6678c2ecf20Sopenharmony_cistatic void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 6708c2ecf20Sopenharmony_ci struct PVSCSIRingCmpDesc *ring = adapter->cmp_ring; 6718c2ecf20Sopenharmony_ci u32 cmp_entries = s->cmpNumEntriesLog2; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci while (s->cmpConsIdx != s->cmpProdIdx) { 6748c2ecf20Sopenharmony_ci struct PVSCSIRingCmpDesc *e = ring + (s->cmpConsIdx & 6758c2ecf20Sopenharmony_ci MASK(cmp_entries)); 6768c2ecf20Sopenharmony_ci /* 6778c2ecf20Sopenharmony_ci * This barrier() ensures that *e is not dereferenced while 6788c2ecf20Sopenharmony_ci * the device emulation still writes data into the slot. 6798c2ecf20Sopenharmony_ci * Since the device emulation advances s->cmpProdIdx only after 6808c2ecf20Sopenharmony_ci * updating the slot we want to check it first. 6818c2ecf20Sopenharmony_ci */ 6828c2ecf20Sopenharmony_ci barrier(); 6838c2ecf20Sopenharmony_ci pvscsi_complete_request(adapter, e); 6848c2ecf20Sopenharmony_ci /* 6858c2ecf20Sopenharmony_ci * This barrier() ensures that compiler doesn't reorder write 6868c2ecf20Sopenharmony_ci * to s->cmpConsIdx before the read of (*e) inside 6878c2ecf20Sopenharmony_ci * pvscsi_complete_request. Otherwise, device emulation may 6888c2ecf20Sopenharmony_ci * overwrite *e before we had a chance to read it. 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_ci barrier(); 6918c2ecf20Sopenharmony_ci s->cmpConsIdx++; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci/* 6968c2ecf20Sopenharmony_ci * Translate a Linux SCSI request into a request ring entry. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_cistatic int pvscsi_queue_ring(struct pvscsi_adapter *adapter, 6998c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct PVSCSIRingsState *s; 7028c2ecf20Sopenharmony_ci struct PVSCSIRingReqDesc *e; 7038c2ecf20Sopenharmony_ci struct scsi_device *sdev; 7048c2ecf20Sopenharmony_ci u32 req_entries; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci s = adapter->rings_state; 7078c2ecf20Sopenharmony_ci sdev = cmd->device; 7088c2ecf20Sopenharmony_ci req_entries = s->reqNumEntriesLog2; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* 7118c2ecf20Sopenharmony_ci * If this condition holds, we might have room on the request ring, but 7128c2ecf20Sopenharmony_ci * we might not have room on the completion ring for the response. 7138c2ecf20Sopenharmony_ci * However, we have already ruled out this possibility - we would not 7148c2ecf20Sopenharmony_ci * have successfully allocated a context if it were true, since we only 7158c2ecf20Sopenharmony_ci * have one context per request entry. Check for it anyway, since it 7168c2ecf20Sopenharmony_ci * would be a serious bug. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) { 7198c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: " 7208c2ecf20Sopenharmony_ci "ring full: reqProdIdx=%d cmpConsIdx=%d\n", 7218c2ecf20Sopenharmony_ci s->reqProdIdx, s->cmpConsIdx); 7228c2ecf20Sopenharmony_ci return -1; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci e = adapter->req_ring + (s->reqProdIdx & MASK(req_entries)); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci e->bus = sdev->channel; 7288c2ecf20Sopenharmony_ci e->target = sdev->id; 7298c2ecf20Sopenharmony_ci memset(e->lun, 0, sizeof(e->lun)); 7308c2ecf20Sopenharmony_ci e->lun[1] = sdev->lun; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (cmd->sense_buffer) { 7338c2ecf20Sopenharmony_ci ctx->sensePA = dma_map_single(&adapter->dev->dev, 7348c2ecf20Sopenharmony_ci cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, 7358c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 7368c2ecf20Sopenharmony_ci if (dma_mapping_error(&adapter->dev->dev, ctx->sensePA)) { 7378c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 7388c2ecf20Sopenharmony_ci "vmw_pvscsi: Failed to map sense buffer for DMA.\n"); 7398c2ecf20Sopenharmony_ci ctx->sensePA = 0; 7408c2ecf20Sopenharmony_ci return -ENOMEM; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci e->senseAddr = ctx->sensePA; 7438c2ecf20Sopenharmony_ci e->senseLen = SCSI_SENSE_BUFFERSIZE; 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci e->senseLen = 0; 7468c2ecf20Sopenharmony_ci e->senseAddr = 0; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci e->cdbLen = cmd->cmd_len; 7498c2ecf20Sopenharmony_ci e->vcpuHint = smp_processor_id(); 7508c2ecf20Sopenharmony_ci memcpy(e->cdb, cmd->cmnd, e->cdbLen); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci e->tag = SIMPLE_QUEUE_TAG; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_FROM_DEVICE) 7558c2ecf20Sopenharmony_ci e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST; 7568c2ecf20Sopenharmony_ci else if (cmd->sc_data_direction == DMA_TO_DEVICE) 7578c2ecf20Sopenharmony_ci e->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE; 7588c2ecf20Sopenharmony_ci else if (cmd->sc_data_direction == DMA_NONE) 7598c2ecf20Sopenharmony_ci e->flags = PVSCSI_FLAG_CMD_DIR_NONE; 7608c2ecf20Sopenharmony_ci else 7618c2ecf20Sopenharmony_ci e->flags = 0; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) { 7648c2ecf20Sopenharmony_ci if (cmd->sense_buffer) { 7658c2ecf20Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->sensePA, 7668c2ecf20Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 7678c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 7688c2ecf20Sopenharmony_ci ctx->sensePA = 0; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci return -ENOMEM; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci e->context = pvscsi_map_context(adapter, ctx); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci barrier(); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci s->reqProdIdx++; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 7858c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 7868c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx; 7878c2ecf20Sopenharmony_ci unsigned long flags; 7888c2ecf20Sopenharmony_ci unsigned char op; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci ctx = pvscsi_acquire_context(adapter, cmd); 7938c2ecf20Sopenharmony_ci if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) { 7948c2ecf20Sopenharmony_ci if (ctx) 7958c2ecf20Sopenharmony_ci pvscsi_release_context(adapter, ctx); 7968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 7978c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci cmd->scsi_done = done; 8018c2ecf20Sopenharmony_ci op = cmd->cmnd[0]; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci dev_dbg(&cmd->device->sdev_gendev, 8048c2ecf20Sopenharmony_ci "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci pvscsi_kick_io(adapter, op); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic DEF_SCSI_QCMD(pvscsi_queue) 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int pvscsi_abort(struct scsi_cmnd *cmd) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(cmd->device->host); 8188c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx; 8198c2ecf20Sopenharmony_ci unsigned long flags; 8208c2ecf20Sopenharmony_ci int result = SUCCESS; 8218c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(abort_cmp); 8228c2ecf20Sopenharmony_ci int done; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n", 8258c2ecf20Sopenharmony_ci adapter->host->host_no, cmd); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* 8308c2ecf20Sopenharmony_ci * Poll the completion ring first - we might be trying to abort 8318c2ecf20Sopenharmony_ci * a command that is waiting to be dispatched in the completion ring. 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_ci pvscsi_process_completion_ring(adapter); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * If there is no context for the command, it either already succeeded 8378c2ecf20Sopenharmony_ci * or else was never properly issued. Not our problem. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci ctx = pvscsi_find_context(adapter, cmd); 8408c2ecf20Sopenharmony_ci if (!ctx) { 8418c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, "Failed to abort cmd %p\n", cmd); 8428c2ecf20Sopenharmony_ci goto out; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* 8468c2ecf20Sopenharmony_ci * Mark that the command has been requested to be aborted and issue 8478c2ecf20Sopenharmony_ci * the abort. 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ci ctx->abort_cmp = &abort_cmp; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci pvscsi_abort_cmd(adapter, ctx); 8528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 8538c2ecf20Sopenharmony_ci /* Wait for 2 secs for the completion. */ 8548c2ecf20Sopenharmony_ci done = wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000)); 8558c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (!done) { 8588c2ecf20Sopenharmony_ci /* 8598c2ecf20Sopenharmony_ci * Failed to abort the command, unmark the fact that it 8608c2ecf20Sopenharmony_ci * was requested to be aborted. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci ctx->abort_cmp = NULL; 8638c2ecf20Sopenharmony_ci result = FAILED; 8648c2ecf20Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 8658c2ecf20Sopenharmony_ci "Failed to get completion for aborted cmd %p\n", 8668c2ecf20Sopenharmony_ci cmd); 8678c2ecf20Sopenharmony_ci goto out; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* 8718c2ecf20Sopenharmony_ci * Successfully aborted the command. 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_ci cmd->result = (DID_ABORT << 16); 8748c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ciout: 8778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 8788c2ecf20Sopenharmony_ci return result; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci/* 8828c2ecf20Sopenharmony_ci * Abort all outstanding requests. This is only safe to use if the completion 8838c2ecf20Sopenharmony_ci * ring will never be walked again or the device has been reset, because it 8848c2ecf20Sopenharmony_ci * destroys the 1-1 mapping between context field passed to emulation and our 8858c2ecf20Sopenharmony_ci * request structure. 8868c2ecf20Sopenharmony_ci */ 8878c2ecf20Sopenharmony_cistatic void pvscsi_reset_all(struct pvscsi_adapter *adapter) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci unsigned i; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci for (i = 0; i < adapter->req_depth; i++) { 8928c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx = &adapter->cmd_map[i]; 8938c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd = ctx->cmd; 8948c2ecf20Sopenharmony_ci if (cmd) { 8958c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, cmd, 8968c2ecf20Sopenharmony_ci "Forced reset on cmd %p\n", cmd); 8978c2ecf20Sopenharmony_ci pvscsi_unmap_buffers(adapter, ctx); 8988c2ecf20Sopenharmony_ci pvscsi_patch_sense(cmd); 8998c2ecf20Sopenharmony_ci pvscsi_release_context(adapter, ctx); 9008c2ecf20Sopenharmony_ci cmd->result = (DID_RESET << 16); 9018c2ecf20Sopenharmony_ci cmd->scsi_done(cmd); 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic int pvscsi_host_reset(struct scsi_cmnd *cmd) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 9098c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 9108c2ecf20Sopenharmony_ci unsigned long flags; 9118c2ecf20Sopenharmony_ci bool use_msg; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "SCSI Host reset\n"); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci use_msg = adapter->use_msg; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (use_msg) { 9208c2ecf20Sopenharmony_ci adapter->use_msg = false; 9218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* 9248c2ecf20Sopenharmony_ci * Now that we know that the ISR won't add more work on the 9258c2ecf20Sopenharmony_ci * workqueue we can safely flush any outstanding work. 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci flush_workqueue(adapter->workqueue); 9288c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* 9328c2ecf20Sopenharmony_ci * We're going to tear down the entire ring structure and set it back 9338c2ecf20Sopenharmony_ci * up, so stalling new requests until all completions are flushed and 9348c2ecf20Sopenharmony_ci * the rings are back in place. 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci pvscsi_process_request_ring(adapter); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci ll_adapter_reset(adapter); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* 9428c2ecf20Sopenharmony_ci * Now process any completions. Note we do this AFTER adapter reset, 9438c2ecf20Sopenharmony_ci * which is strange, but stops races where completions get posted 9448c2ecf20Sopenharmony_ci * between processing the ring and issuing the reset. The backend will 9458c2ecf20Sopenharmony_ci * not touch the ring memory after reset, so the immediately pre-reset 9468c2ecf20Sopenharmony_ci * completion ring state is still valid. 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_ci pvscsi_process_completion_ring(adapter); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci pvscsi_reset_all(adapter); 9518c2ecf20Sopenharmony_ci adapter->use_msg = use_msg; 9528c2ecf20Sopenharmony_ci pvscsi_setup_all_rings(adapter); 9538c2ecf20Sopenharmony_ci pvscsi_unmask_intr(adapter); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return SUCCESS; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic int pvscsi_bus_reset(struct scsi_cmnd *cmd) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 9638c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 9648c2ecf20Sopenharmony_ci unsigned long flags; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "SCSI Bus reset\n"); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* 9698c2ecf20Sopenharmony_ci * We don't want to queue new requests for this bus after 9708c2ecf20Sopenharmony_ci * flushing all pending requests to emulation, since new 9718c2ecf20Sopenharmony_ci * requests could then sneak in during this bus reset phase, 9728c2ecf20Sopenharmony_ci * so take the lock now. 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci pvscsi_process_request_ring(adapter); 9778c2ecf20Sopenharmony_ci ll_bus_reset(adapter); 9788c2ecf20Sopenharmony_ci pvscsi_process_completion_ring(adapter); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci return SUCCESS; 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic int pvscsi_device_reset(struct scsi_cmnd *cmd) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 9888c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 9898c2ecf20Sopenharmony_ci unsigned long flags; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "SCSI device reset on scsi%u:%u\n", 9928c2ecf20Sopenharmony_ci host->host_no, cmd->device->id); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /* 9958c2ecf20Sopenharmony_ci * We don't want to queue new requests for this device after flushing 9968c2ecf20Sopenharmony_ci * all pending requests to emulation, since new requests could then 9978c2ecf20Sopenharmony_ci * sneak in during this device reset phase, so take the lock now. 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci pvscsi_process_request_ring(adapter); 10028c2ecf20Sopenharmony_ci ll_device_reset(adapter, cmd->device->id); 10038c2ecf20Sopenharmony_ci pvscsi_process_completion_ring(adapter); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci return SUCCESS; 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic struct scsi_host_template pvscsi_template; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic const char *pvscsi_info(struct Scsi_Host *host) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 10158c2ecf20Sopenharmony_ci static char buf[256]; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci sprintf(buf, "VMware PVSCSI storage adapter rev %d, req/cmp/msg rings: " 10188c2ecf20Sopenharmony_ci "%u/%u/%u pages, cmd_per_lun=%u", adapter->rev, 10198c2ecf20Sopenharmony_ci adapter->req_pages, adapter->cmp_pages, adapter->msg_pages, 10208c2ecf20Sopenharmony_ci pvscsi_template.cmd_per_lun); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci return buf; 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cistatic struct scsi_host_template pvscsi_template = { 10268c2ecf20Sopenharmony_ci .module = THIS_MODULE, 10278c2ecf20Sopenharmony_ci .name = "VMware PVSCSI Host Adapter", 10288c2ecf20Sopenharmony_ci .proc_name = "vmw_pvscsi", 10298c2ecf20Sopenharmony_ci .info = pvscsi_info, 10308c2ecf20Sopenharmony_ci .queuecommand = pvscsi_queue, 10318c2ecf20Sopenharmony_ci .this_id = -1, 10328c2ecf20Sopenharmony_ci .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT, 10338c2ecf20Sopenharmony_ci .dma_boundary = UINT_MAX, 10348c2ecf20Sopenharmony_ci .max_sectors = 0xffff, 10358c2ecf20Sopenharmony_ci .change_queue_depth = pvscsi_change_queue_depth, 10368c2ecf20Sopenharmony_ci .eh_abort_handler = pvscsi_abort, 10378c2ecf20Sopenharmony_ci .eh_device_reset_handler = pvscsi_device_reset, 10388c2ecf20Sopenharmony_ci .eh_bus_reset_handler = pvscsi_bus_reset, 10398c2ecf20Sopenharmony_ci .eh_host_reset_handler = pvscsi_host_reset, 10408c2ecf20Sopenharmony_ci}; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic void pvscsi_process_msg(const struct pvscsi_adapter *adapter, 10438c2ecf20Sopenharmony_ci const struct PVSCSIRingMsgDesc *e) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 10468c2ecf20Sopenharmony_ci struct Scsi_Host *host = adapter->host; 10478c2ecf20Sopenharmony_ci struct scsi_device *sdev; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: msg type: 0x%x - MSG RING: %u/%u (%u) \n", 10508c2ecf20Sopenharmony_ci e->type, s->msgProdIdx, s->msgConsIdx, s->msgNumEntriesLog2); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci BUILD_BUG_ON(PVSCSI_MSG_LAST != 2); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (e->type == PVSCSI_MSG_DEV_ADDED) { 10558c2ecf20Sopenharmony_ci struct PVSCSIMsgDescDevStatusChanged *desc; 10568c2ecf20Sopenharmony_ci desc = (struct PVSCSIMsgDescDevStatusChanged *)e; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci printk(KERN_INFO 10598c2ecf20Sopenharmony_ci "vmw_pvscsi: msg: device added at scsi%u:%u:%u\n", 10608c2ecf20Sopenharmony_ci desc->bus, desc->target, desc->lun[1]); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (!scsi_host_get(host)) 10638c2ecf20Sopenharmony_ci return; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci sdev = scsi_device_lookup(host, desc->bus, desc->target, 10668c2ecf20Sopenharmony_ci desc->lun[1]); 10678c2ecf20Sopenharmony_ci if (sdev) { 10688c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: device already exists\n"); 10698c2ecf20Sopenharmony_ci scsi_device_put(sdev); 10708c2ecf20Sopenharmony_ci } else 10718c2ecf20Sopenharmony_ci scsi_add_device(adapter->host, desc->bus, 10728c2ecf20Sopenharmony_ci desc->target, desc->lun[1]); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci scsi_host_put(host); 10758c2ecf20Sopenharmony_ci } else if (e->type == PVSCSI_MSG_DEV_REMOVED) { 10768c2ecf20Sopenharmony_ci struct PVSCSIMsgDescDevStatusChanged *desc; 10778c2ecf20Sopenharmony_ci desc = (struct PVSCSIMsgDescDevStatusChanged *)e; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci printk(KERN_INFO 10808c2ecf20Sopenharmony_ci "vmw_pvscsi: msg: device removed at scsi%u:%u:%u\n", 10818c2ecf20Sopenharmony_ci desc->bus, desc->target, desc->lun[1]); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci if (!scsi_host_get(host)) 10848c2ecf20Sopenharmony_ci return; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci sdev = scsi_device_lookup(host, desc->bus, desc->target, 10878c2ecf20Sopenharmony_ci desc->lun[1]); 10888c2ecf20Sopenharmony_ci if (sdev) { 10898c2ecf20Sopenharmony_ci scsi_remove_device(sdev); 10908c2ecf20Sopenharmony_ci scsi_device_put(sdev); 10918c2ecf20Sopenharmony_ci } else 10928c2ecf20Sopenharmony_ci printk(KERN_INFO 10938c2ecf20Sopenharmony_ci "vmw_pvscsi: failed to lookup scsi%u:%u:%u\n", 10948c2ecf20Sopenharmony_ci desc->bus, desc->target, desc->lun[1]); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci scsi_host_put(host); 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic int pvscsi_msg_pending(const struct pvscsi_adapter *adapter) 11018c2ecf20Sopenharmony_ci{ 11028c2ecf20Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci return s->msgProdIdx != s->msgConsIdx; 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic void pvscsi_process_msg_ring(const struct pvscsi_adapter *adapter) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 11108c2ecf20Sopenharmony_ci struct PVSCSIRingMsgDesc *ring = adapter->msg_ring; 11118c2ecf20Sopenharmony_ci u32 msg_entries = s->msgNumEntriesLog2; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci while (pvscsi_msg_pending(adapter)) { 11148c2ecf20Sopenharmony_ci struct PVSCSIRingMsgDesc *e = ring + (s->msgConsIdx & 11158c2ecf20Sopenharmony_ci MASK(msg_entries)); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci barrier(); 11188c2ecf20Sopenharmony_ci pvscsi_process_msg(adapter, e); 11198c2ecf20Sopenharmony_ci barrier(); 11208c2ecf20Sopenharmony_ci s->msgConsIdx++; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic void pvscsi_msg_workqueue_handler(struct work_struct *data) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci adapter = container_of(data, struct pvscsi_adapter, work); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci pvscsi_process_msg_ring(adapter); 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_cistatic int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci char name[32]; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (!pvscsi_use_msg) 11388c2ecf20Sopenharmony_ci return 0; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, 11418c2ecf20Sopenharmony_ci PVSCSI_CMD_SETUP_MSG_RING); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS) == -1) 11448c2ecf20Sopenharmony_ci return 0; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), 11478c2ecf20Sopenharmony_ci "vmw_pvscsi_wq_%u", adapter->host->host_no); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci adapter->workqueue = create_singlethread_workqueue(name); 11508c2ecf20Sopenharmony_ci if (!adapter->workqueue) { 11518c2ecf20Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n"); 11528c2ecf20Sopenharmony_ci return 0; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci INIT_WORK(&adapter->work, pvscsi_msg_workqueue_handler); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci return 1; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter, 11608c2ecf20Sopenharmony_ci bool enable) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci u32 val; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if (!pvscsi_use_req_threshold) 11658c2ecf20Sopenharmony_ci return false; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, 11688c2ecf20Sopenharmony_ci PVSCSI_CMD_SETUP_REQCALLTHRESHOLD); 11698c2ecf20Sopenharmony_ci val = pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS); 11708c2ecf20Sopenharmony_ci if (val == -1) { 11718c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: device does not support req_threshold\n"); 11728c2ecf20Sopenharmony_ci return false; 11738c2ecf20Sopenharmony_ci } else { 11748c2ecf20Sopenharmony_ci struct PVSCSICmdDescSetupReqCall cmd_msg = { 0 }; 11758c2ecf20Sopenharmony_ci cmd_msg.enable = enable; 11768c2ecf20Sopenharmony_ci printk(KERN_INFO 11778c2ecf20Sopenharmony_ci "vmw_pvscsi: %sabling reqCallThreshold\n", 11788c2ecf20Sopenharmony_ci enable ? "en" : "dis"); 11798c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, 11808c2ecf20Sopenharmony_ci PVSCSI_CMD_SETUP_REQCALLTHRESHOLD, 11818c2ecf20Sopenharmony_ci &cmd_msg, sizeof(cmd_msg)); 11828c2ecf20Sopenharmony_ci return pvscsi_reg_read(adapter, 11838c2ecf20Sopenharmony_ci PVSCSI_REG_OFFSET_COMMAND_STATUS) != 0; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic irqreturn_t pvscsi_isr(int irq, void *devp) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = devp; 11908c2ecf20Sopenharmony_ci unsigned long flags; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 11938c2ecf20Sopenharmony_ci pvscsi_process_completion_ring(adapter); 11948c2ecf20Sopenharmony_ci if (adapter->use_msg && pvscsi_msg_pending(adapter)) 11958c2ecf20Sopenharmony_ci queue_work(adapter->workqueue, &adapter->work); 11968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic irqreturn_t pvscsi_shared_isr(int irq, void *devp) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = devp; 12048c2ecf20Sopenharmony_ci u32 val = pvscsi_read_intr_status(adapter); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (!(val & PVSCSI_INTR_ALL_SUPPORTED)) 12078c2ecf20Sopenharmony_ci return IRQ_NONE; 12088c2ecf20Sopenharmony_ci pvscsi_write_intr_status(devp, val); 12098c2ecf20Sopenharmony_ci return pvscsi_isr(irq, devp); 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx = adapter->cmd_map; 12158c2ecf20Sopenharmony_ci unsigned i; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci for (i = 0; i < adapter->req_depth; ++i, ++ctx) 12188c2ecf20Sopenharmony_ci free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE)); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(adapter->dev, 0), adapter); 12248c2ecf20Sopenharmony_ci pci_free_irq_vectors(adapter->dev); 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cistatic void pvscsi_release_resources(struct pvscsi_adapter *adapter) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci if (adapter->workqueue) 12308c2ecf20Sopenharmony_ci destroy_workqueue(adapter->workqueue); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (adapter->mmioBase) 12338c2ecf20Sopenharmony_ci pci_iounmap(adapter->dev, adapter->mmioBase); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci pci_release_regions(adapter->dev); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (adapter->cmd_map) { 12388c2ecf20Sopenharmony_ci pvscsi_free_sgls(adapter); 12398c2ecf20Sopenharmony_ci kfree(adapter->cmd_map); 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci if (adapter->rings_state) 12438c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, 12448c2ecf20Sopenharmony_ci adapter->rings_state, adapter->ringStatePA); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (adapter->req_ring) 12478c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 12488c2ecf20Sopenharmony_ci adapter->req_pages * PAGE_SIZE, 12498c2ecf20Sopenharmony_ci adapter->req_ring, adapter->reqRingPA); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci if (adapter->cmp_ring) 12528c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 12538c2ecf20Sopenharmony_ci adapter->cmp_pages * PAGE_SIZE, 12548c2ecf20Sopenharmony_ci adapter->cmp_ring, adapter->cmpRingPA); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (adapter->msg_ring) 12578c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 12588c2ecf20Sopenharmony_ci adapter->msg_pages * PAGE_SIZE, 12598c2ecf20Sopenharmony_ci adapter->msg_ring, adapter->msgRingPA); 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci/* 12638c2ecf20Sopenharmony_ci * Allocate scatter gather lists. 12648c2ecf20Sopenharmony_ci * 12658c2ecf20Sopenharmony_ci * These are statically allocated. Trying to be clever was not worth it. 12668c2ecf20Sopenharmony_ci * 12678c2ecf20Sopenharmony_ci * Dynamic allocation can fail, and we can't go deep into the memory 12688c2ecf20Sopenharmony_ci * allocator, since we're a SCSI driver, and trying too hard to allocate 12698c2ecf20Sopenharmony_ci * memory might generate disk I/O. We also don't want to fail disk I/O 12708c2ecf20Sopenharmony_ci * in that case because we can't get an allocation - the I/O could be 12718c2ecf20Sopenharmony_ci * trying to swap out data to free memory. Since that is pathological, 12728c2ecf20Sopenharmony_ci * just use a statically allocated scatter list. 12738c2ecf20Sopenharmony_ci * 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_cistatic int pvscsi_allocate_sg(struct pvscsi_adapter *adapter) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx; 12788c2ecf20Sopenharmony_ci int i; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci ctx = adapter->cmd_map; 12818c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct pvscsi_sg_list) > SGL_SIZE); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci for (i = 0; i < adapter->req_depth; ++i, ++ctx) { 12848c2ecf20Sopenharmony_ci ctx->sgl = (void *)__get_free_pages(GFP_KERNEL, 12858c2ecf20Sopenharmony_ci get_order(SGL_SIZE)); 12868c2ecf20Sopenharmony_ci ctx->sglPA = 0; 12878c2ecf20Sopenharmony_ci BUG_ON(!IS_ALIGNED(((unsigned long)ctx->sgl), PAGE_SIZE)); 12888c2ecf20Sopenharmony_ci if (!ctx->sgl) { 12898c2ecf20Sopenharmony_ci for (; i >= 0; --i, --ctx) { 12908c2ecf20Sopenharmony_ci free_pages((unsigned long)ctx->sgl, 12918c2ecf20Sopenharmony_ci get_order(SGL_SIZE)); 12928c2ecf20Sopenharmony_ci ctx->sgl = NULL; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci return -ENOMEM; 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci return 0; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci/* 13028c2ecf20Sopenharmony_ci * Query the device, fetch the config info and return the 13038c2ecf20Sopenharmony_ci * maximum number of targets on the adapter. In case of 13048c2ecf20Sopenharmony_ci * failure due to any reason return default i.e. 16. 13058c2ecf20Sopenharmony_ci */ 13068c2ecf20Sopenharmony_cistatic u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci struct PVSCSICmdDescConfigCmd cmd; 13098c2ecf20Sopenharmony_ci struct PVSCSIConfigPageHeader *header; 13108c2ecf20Sopenharmony_ci struct device *dev; 13118c2ecf20Sopenharmony_ci dma_addr_t configPagePA; 13128c2ecf20Sopenharmony_ci void *config_page; 13138c2ecf20Sopenharmony_ci u32 numPhys = 16; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci dev = pvscsi_dev(adapter); 13168c2ecf20Sopenharmony_ci config_page = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, 13178c2ecf20Sopenharmony_ci &configPagePA, GFP_KERNEL); 13188c2ecf20Sopenharmony_ci if (!config_page) { 13198c2ecf20Sopenharmony_ci dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n"); 13208c2ecf20Sopenharmony_ci goto exit; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci BUG_ON(configPagePA & ~PAGE_MASK); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci /* Fetch config info from the device. */ 13258c2ecf20Sopenharmony_ci cmd.configPageAddress = ((u64)PVSCSI_CONFIG_CONTROLLER_ADDRESS) << 32; 13268c2ecf20Sopenharmony_ci cmd.configPageNum = PVSCSI_CONFIG_PAGE_CONTROLLER; 13278c2ecf20Sopenharmony_ci cmd.cmpAddr = configPagePA; 13288c2ecf20Sopenharmony_ci cmd._pad = 0; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci /* 13318c2ecf20Sopenharmony_ci * Mark the completion page header with error values. If the device 13328c2ecf20Sopenharmony_ci * completes the command successfully, it sets the status values to 13338c2ecf20Sopenharmony_ci * indicate success. 13348c2ecf20Sopenharmony_ci */ 13358c2ecf20Sopenharmony_ci header = config_page; 13368c2ecf20Sopenharmony_ci memset(header, 0, sizeof *header); 13378c2ecf20Sopenharmony_ci header->hostStatus = BTSTAT_INVPARAM; 13388c2ecf20Sopenharmony_ci header->scsiStatus = SDSTAT_CHECK; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_CONFIG, &cmd, sizeof cmd); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci if (header->hostStatus == BTSTAT_SUCCESS && 13438c2ecf20Sopenharmony_ci header->scsiStatus == SDSTAT_GOOD) { 13448c2ecf20Sopenharmony_ci struct PVSCSIConfigPageController *config; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci config = config_page; 13478c2ecf20Sopenharmony_ci numPhys = config->numPhys; 13488c2ecf20Sopenharmony_ci } else 13498c2ecf20Sopenharmony_ci dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n", 13508c2ecf20Sopenharmony_ci header->hostStatus, header->scsiStatus); 13518c2ecf20Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, config_page, 13528c2ecf20Sopenharmony_ci configPagePA); 13538c2ecf20Sopenharmony_ciexit: 13548c2ecf20Sopenharmony_ci return numPhys; 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_cistatic int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci unsigned int irq_flag = PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY; 13608c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter; 13618c2ecf20Sopenharmony_ci struct pvscsi_adapter adapter_temp; 13628c2ecf20Sopenharmony_ci struct Scsi_Host *host = NULL; 13638c2ecf20Sopenharmony_ci unsigned int i; 13648c2ecf20Sopenharmony_ci int error; 13658c2ecf20Sopenharmony_ci u32 max_id; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci error = -ENODEV; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) 13708c2ecf20Sopenharmony_ci return error; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { 13738c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n"); 13748c2ecf20Sopenharmony_ci } else if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { 13758c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n"); 13768c2ecf20Sopenharmony_ci } else { 13778c2ecf20Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n"); 13788c2ecf20Sopenharmony_ci goto out_disable_device; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci /* 13828c2ecf20Sopenharmony_ci * Let's use a temp pvscsi_adapter struct until we find the number of 13838c2ecf20Sopenharmony_ci * targets on the adapter, after that we will switch to the real 13848c2ecf20Sopenharmony_ci * allocated struct. 13858c2ecf20Sopenharmony_ci */ 13868c2ecf20Sopenharmony_ci adapter = &adapter_temp; 13878c2ecf20Sopenharmony_ci memset(adapter, 0, sizeof(*adapter)); 13888c2ecf20Sopenharmony_ci adapter->dev = pdev; 13898c2ecf20Sopenharmony_ci adapter->rev = pdev->revision; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (pci_request_regions(pdev, "vmw_pvscsi")) { 13928c2ecf20Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n"); 13938c2ecf20Sopenharmony_ci goto out_disable_device; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 13978c2ecf20Sopenharmony_ci if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) 13988c2ecf20Sopenharmony_ci continue; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (pci_resource_len(pdev, i) < PVSCSI_MEM_SPACE_SIZE) 14018c2ecf20Sopenharmony_ci continue; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci break; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (i == DEVICE_COUNT_RESOURCE) { 14078c2ecf20Sopenharmony_ci printk(KERN_ERR 14088c2ecf20Sopenharmony_ci "vmw_pvscsi: adapter has no suitable MMIO region\n"); 14098c2ecf20Sopenharmony_ci goto out_release_resources_and_disable; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (!adapter->mmioBase) { 14158c2ecf20Sopenharmony_ci printk(KERN_ERR 14168c2ecf20Sopenharmony_ci "vmw_pvscsi: can't iomap for BAR %d memsize %lu\n", 14178c2ecf20Sopenharmony_ci i, PVSCSI_MEM_SPACE_SIZE); 14188c2ecf20Sopenharmony_ci goto out_release_resources_and_disable; 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci pci_set_master(pdev); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* 14248c2ecf20Sopenharmony_ci * Ask the device for max number of targets before deciding the 14258c2ecf20Sopenharmony_ci * default pvscsi_ring_pages value. 14268c2ecf20Sopenharmony_ci */ 14278c2ecf20Sopenharmony_ci max_id = pvscsi_get_max_targets(adapter); 14288c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: max_id: %u\n", max_id); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci if (pvscsi_ring_pages == 0) 14318c2ecf20Sopenharmony_ci /* 14328c2ecf20Sopenharmony_ci * Set the right default value. Up to 16 it is 8, above it is 14338c2ecf20Sopenharmony_ci * max. 14348c2ecf20Sopenharmony_ci */ 14358c2ecf20Sopenharmony_ci pvscsi_ring_pages = (max_id > 16) ? 14368c2ecf20Sopenharmony_ci PVSCSI_SETUP_RINGS_MAX_NUM_PAGES : 14378c2ecf20Sopenharmony_ci PVSCSI_DEFAULT_NUM_PAGES_PER_RING; 14388c2ecf20Sopenharmony_ci printk(KERN_INFO 14398c2ecf20Sopenharmony_ci "vmw_pvscsi: setting ring_pages to %d\n", 14408c2ecf20Sopenharmony_ci pvscsi_ring_pages); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci pvscsi_template.can_queue = 14438c2ecf20Sopenharmony_ci min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) * 14448c2ecf20Sopenharmony_ci PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; 14458c2ecf20Sopenharmony_ci pvscsi_template.cmd_per_lun = 14468c2ecf20Sopenharmony_ci min(pvscsi_template.can_queue, pvscsi_cmd_per_lun); 14478c2ecf20Sopenharmony_ci host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter)); 14488c2ecf20Sopenharmony_ci if (!host) { 14498c2ecf20Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n"); 14508c2ecf20Sopenharmony_ci goto out_release_resources_and_disable; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* 14548c2ecf20Sopenharmony_ci * Let's use the real pvscsi_adapter struct here onwards. 14558c2ecf20Sopenharmony_ci */ 14568c2ecf20Sopenharmony_ci adapter = shost_priv(host); 14578c2ecf20Sopenharmony_ci memset(adapter, 0, sizeof(*adapter)); 14588c2ecf20Sopenharmony_ci adapter->dev = pdev; 14598c2ecf20Sopenharmony_ci adapter->host = host; 14608c2ecf20Sopenharmony_ci /* 14618c2ecf20Sopenharmony_ci * Copy back what we already have to the allocated adapter struct. 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci adapter->rev = adapter_temp.rev; 14648c2ecf20Sopenharmony_ci adapter->mmioBase = adapter_temp.mmioBase; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci spin_lock_init(&adapter->hw_lock); 14678c2ecf20Sopenharmony_ci host->max_channel = 0; 14688c2ecf20Sopenharmony_ci host->max_lun = 1; 14698c2ecf20Sopenharmony_ci host->max_cmd_len = 16; 14708c2ecf20Sopenharmony_ci host->max_id = max_id; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, host); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci ll_adapter_reset(adapter); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci adapter->use_msg = pvscsi_setup_msg_workqueue(adapter); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci error = pvscsi_allocate_rings(adapter); 14798c2ecf20Sopenharmony_ci if (error) { 14808c2ecf20Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: unable to allocate ring memory\n"); 14818c2ecf20Sopenharmony_ci goto out_release_resources; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* 14858c2ecf20Sopenharmony_ci * From this point on we should reset the adapter if anything goes 14868c2ecf20Sopenharmony_ci * wrong. 14878c2ecf20Sopenharmony_ci */ 14888c2ecf20Sopenharmony_ci pvscsi_setup_all_rings(adapter); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci adapter->cmd_map = kcalloc(adapter->req_depth, 14918c2ecf20Sopenharmony_ci sizeof(struct pvscsi_ctx), GFP_KERNEL); 14928c2ecf20Sopenharmony_ci if (!adapter->cmd_map) { 14938c2ecf20Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to allocate memory.\n"); 14948c2ecf20Sopenharmony_ci error = -ENOMEM; 14958c2ecf20Sopenharmony_ci goto out_reset_adapter; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adapter->cmd_pool); 14998c2ecf20Sopenharmony_ci for (i = 0; i < adapter->req_depth; i++) { 15008c2ecf20Sopenharmony_ci struct pvscsi_ctx *ctx = adapter->cmd_map + i; 15018c2ecf20Sopenharmony_ci list_add(&ctx->list, &adapter->cmd_pool); 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci error = pvscsi_allocate_sg(adapter); 15058c2ecf20Sopenharmony_ci if (error) { 15068c2ecf20Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: unable to allocate s/g table\n"); 15078c2ecf20Sopenharmony_ci goto out_reset_adapter; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci if (pvscsi_disable_msix) 15118c2ecf20Sopenharmony_ci irq_flag &= ~PCI_IRQ_MSIX; 15128c2ecf20Sopenharmony_ci if (pvscsi_disable_msi) 15138c2ecf20Sopenharmony_ci irq_flag &= ~PCI_IRQ_MSI; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci error = pci_alloc_irq_vectors(adapter->dev, 1, 1, irq_flag); 15168c2ecf20Sopenharmony_ci if (error < 0) 15178c2ecf20Sopenharmony_ci goto out_reset_adapter; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true); 15208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n", 15218c2ecf20Sopenharmony_ci adapter->use_req_threshold ? "en" : "dis"); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (adapter->dev->msix_enabled || adapter->dev->msi_enabled) { 15248c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using MSI%s\n", 15258c2ecf20Sopenharmony_ci adapter->dev->msix_enabled ? "-X" : ""); 15268c2ecf20Sopenharmony_ci error = request_irq(pci_irq_vector(pdev, 0), pvscsi_isr, 15278c2ecf20Sopenharmony_ci 0, "vmw_pvscsi", adapter); 15288c2ecf20Sopenharmony_ci } else { 15298c2ecf20Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using INTx\n"); 15308c2ecf20Sopenharmony_ci error = request_irq(pci_irq_vector(pdev, 0), pvscsi_shared_isr, 15318c2ecf20Sopenharmony_ci IRQF_SHARED, "vmw_pvscsi", adapter); 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (error) { 15358c2ecf20Sopenharmony_ci printk(KERN_ERR 15368c2ecf20Sopenharmony_ci "vmw_pvscsi: unable to request IRQ: %d\n", error); 15378c2ecf20Sopenharmony_ci goto out_reset_adapter; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci error = scsi_add_host(host, &pdev->dev); 15418c2ecf20Sopenharmony_ci if (error) { 15428c2ecf20Sopenharmony_ci printk(KERN_ERR 15438c2ecf20Sopenharmony_ci "vmw_pvscsi: scsi_add_host failed: %d\n", error); 15448c2ecf20Sopenharmony_ci goto out_reset_adapter; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "VMware PVSCSI rev %d host #%u\n", 15488c2ecf20Sopenharmony_ci adapter->rev, host->host_no); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci pvscsi_unmask_intr(adapter); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci scsi_scan_host(host); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci return 0; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ciout_reset_adapter: 15578c2ecf20Sopenharmony_ci ll_adapter_reset(adapter); 15588c2ecf20Sopenharmony_ciout_release_resources: 15598c2ecf20Sopenharmony_ci pvscsi_shutdown_intr(adapter); 15608c2ecf20Sopenharmony_ci pvscsi_release_resources(adapter); 15618c2ecf20Sopenharmony_ci scsi_host_put(host); 15628c2ecf20Sopenharmony_ciout_disable_device: 15638c2ecf20Sopenharmony_ci pci_disable_device(pdev); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci return error; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ciout_release_resources_and_disable: 15688c2ecf20Sopenharmony_ci pvscsi_shutdown_intr(adapter); 15698c2ecf20Sopenharmony_ci pvscsi_release_resources(adapter); 15708c2ecf20Sopenharmony_ci goto out_disable_device; 15718c2ecf20Sopenharmony_ci} 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_cistatic void __pvscsi_shutdown(struct pvscsi_adapter *adapter) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci pvscsi_mask_intr(adapter); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci if (adapter->workqueue) 15788c2ecf20Sopenharmony_ci flush_workqueue(adapter->workqueue); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci pvscsi_shutdown_intr(adapter); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci pvscsi_process_request_ring(adapter); 15838c2ecf20Sopenharmony_ci pvscsi_process_completion_ring(adapter); 15848c2ecf20Sopenharmony_ci ll_adapter_reset(adapter); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic void pvscsi_shutdown(struct pci_dev *dev) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci struct Scsi_Host *host = pci_get_drvdata(dev); 15908c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci __pvscsi_shutdown(adapter); 15938c2ecf20Sopenharmony_ci} 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_cistatic void pvscsi_remove(struct pci_dev *pdev) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci struct Scsi_Host *host = pci_get_drvdata(pdev); 15988c2ecf20Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci scsi_remove_host(host); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci __pvscsi_shutdown(adapter); 16038c2ecf20Sopenharmony_ci pvscsi_release_resources(adapter); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci scsi_host_put(host); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci pci_disable_device(pdev); 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic struct pci_driver pvscsi_pci_driver = { 16118c2ecf20Sopenharmony_ci .name = "vmw_pvscsi", 16128c2ecf20Sopenharmony_ci .id_table = pvscsi_pci_tbl, 16138c2ecf20Sopenharmony_ci .probe = pvscsi_probe, 16148c2ecf20Sopenharmony_ci .remove = pvscsi_remove, 16158c2ecf20Sopenharmony_ci .shutdown = pvscsi_shutdown, 16168c2ecf20Sopenharmony_ci}; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_cistatic int __init pvscsi_init(void) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci pr_info("%s - version %s\n", 16218c2ecf20Sopenharmony_ci PVSCSI_LINUX_DRIVER_DESC, PVSCSI_DRIVER_VERSION_STRING); 16228c2ecf20Sopenharmony_ci return pci_register_driver(&pvscsi_pci_driver); 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_cistatic void __exit pvscsi_exit(void) 16268c2ecf20Sopenharmony_ci{ 16278c2ecf20Sopenharmony_ci pci_unregister_driver(&pvscsi_pci_driver); 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cimodule_init(pvscsi_init); 16318c2ecf20Sopenharmony_cimodule_exit(pvscsi_exit); 1632