162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Linux driver for VMware's para-virtualized SCSI HBA. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2008-2014, VMware, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 762306a36Sopenharmony_ci * under the terms of the GNU General Public License as published by the 862306a36Sopenharmony_ci * Free Software Foundation; version 2 of the License and no later version. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 1162306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 1262306a36Sopenharmony_ci * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 1362306a36Sopenharmony_ci * NON INFRINGEMENT. See the GNU General Public License for more 1462306a36Sopenharmony_ci * details. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 1762306a36Sopenharmony_ci * along with this program; if not, write to the Free Software 1862306a36Sopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/kernel.h> 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/interrupt.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <linux/workqueue.h> 2762306a36Sopenharmony_ci#include <linux/pci.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <scsi/scsi.h> 3062306a36Sopenharmony_ci#include <scsi/scsi_host.h> 3162306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 3262306a36Sopenharmony_ci#include <scsi/scsi_device.h> 3362306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "vmw_pvscsi.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciMODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC); 4062306a36Sopenharmony_ciMODULE_AUTHOR("VMware, Inc."); 4162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4262306a36Sopenharmony_ciMODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8 4562306a36Sopenharmony_ci#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1 4662306a36Sopenharmony_ci#define PVSCSI_DEFAULT_QUEUE_DEPTH 254 4762306a36Sopenharmony_ci#define SGL_SIZE PAGE_SIZE 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct pvscsi_sg_list { 5062306a36Sopenharmony_ci struct PVSCSISGElement sge[PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT]; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct pvscsi_ctx { 5462306a36Sopenharmony_ci /* 5562306a36Sopenharmony_ci * The index of the context in cmd_map serves as the context ID for a 5662306a36Sopenharmony_ci * 1-to-1 mapping completions back to requests. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci struct scsi_cmnd *cmd; 5962306a36Sopenharmony_ci struct pvscsi_sg_list *sgl; 6062306a36Sopenharmony_ci struct list_head list; 6162306a36Sopenharmony_ci dma_addr_t dataPA; 6262306a36Sopenharmony_ci dma_addr_t sensePA; 6362306a36Sopenharmony_ci dma_addr_t sglPA; 6462306a36Sopenharmony_ci struct completion *abort_cmp; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistruct pvscsi_adapter { 6862306a36Sopenharmony_ci char *mmioBase; 6962306a36Sopenharmony_ci u8 rev; 7062306a36Sopenharmony_ci bool use_msg; 7162306a36Sopenharmony_ci bool use_req_threshold; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci spinlock_t hw_lock; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci struct workqueue_struct *workqueue; 7662306a36Sopenharmony_ci struct work_struct work; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci struct PVSCSIRingReqDesc *req_ring; 7962306a36Sopenharmony_ci unsigned req_pages; 8062306a36Sopenharmony_ci unsigned req_depth; 8162306a36Sopenharmony_ci dma_addr_t reqRingPA; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci struct PVSCSIRingCmpDesc *cmp_ring; 8462306a36Sopenharmony_ci unsigned cmp_pages; 8562306a36Sopenharmony_ci dma_addr_t cmpRingPA; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci struct PVSCSIRingMsgDesc *msg_ring; 8862306a36Sopenharmony_ci unsigned msg_pages; 8962306a36Sopenharmony_ci dma_addr_t msgRingPA; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci struct PVSCSIRingsState *rings_state; 9262306a36Sopenharmony_ci dma_addr_t ringStatePA; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci struct pci_dev *dev; 9562306a36Sopenharmony_ci struct Scsi_Host *host; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci struct list_head cmd_pool; 9862306a36Sopenharmony_ci struct pvscsi_ctx *cmd_map; 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* Command line parameters */ 10362306a36Sopenharmony_cistatic int pvscsi_ring_pages; 10462306a36Sopenharmony_cistatic int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING; 10562306a36Sopenharmony_cistatic int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH; 10662306a36Sopenharmony_cistatic bool pvscsi_disable_msi; 10762306a36Sopenharmony_cistatic bool pvscsi_disable_msix; 10862306a36Sopenharmony_cistatic bool pvscsi_use_msg = true; 10962306a36Sopenharmony_cistatic bool pvscsi_use_req_threshold = true; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define PVSCSI_RW (S_IRUSR | S_IWUSR) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cimodule_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW); 11462306a36Sopenharmony_ciMODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default=" 11562306a36Sopenharmony_ci __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) 11662306a36Sopenharmony_ci "[up to 16 targets]," 11762306a36Sopenharmony_ci __stringify(PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) 11862306a36Sopenharmony_ci "[for 16+ targets])"); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cimodule_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW); 12162306a36Sopenharmony_ciMODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default=" 12262306a36Sopenharmony_ci __stringify(PVSCSI_DEFAULT_NUM_PAGES_MSG_RING) ")"); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cimodule_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW); 12562306a36Sopenharmony_ciMODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default=" 12662306a36Sopenharmony_ci __stringify(PVSCSI_DEFAULT_QUEUE_DEPTH) ")"); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cimodule_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW); 12962306a36Sopenharmony_ciMODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)"); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cimodule_param_named(disable_msix, pvscsi_disable_msix, bool, PVSCSI_RW); 13262306a36Sopenharmony_ciMODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)"); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cimodule_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW); 13562306a36Sopenharmony_ciMODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)"); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cimodule_param_named(use_req_threshold, pvscsi_use_req_threshold, 13862306a36Sopenharmony_ci bool, PVSCSI_RW); 13962306a36Sopenharmony_ciMODULE_PARM_DESC(use_req_threshold, "Use driver-based request coalescing if configured - (default=1)"); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct pci_device_id pvscsi_pci_tbl[] = { 14262306a36Sopenharmony_ci { PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) }, 14362306a36Sopenharmony_ci { 0 } 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pvscsi_pci_tbl); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic struct device * 14962306a36Sopenharmony_cipvscsi_dev(const struct pvscsi_adapter *adapter) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return &(adapter->dev->dev); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic struct pvscsi_ctx * 15562306a36Sopenharmony_cipvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct pvscsi_ctx *ctx, *end; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci end = &adapter->cmd_map[adapter->req_depth]; 16062306a36Sopenharmony_ci for (ctx = adapter->cmd_map; ctx < end; ctx++) 16162306a36Sopenharmony_ci if (ctx->cmd == cmd) 16262306a36Sopenharmony_ci return ctx; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return NULL; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic struct pvscsi_ctx * 16862306a36Sopenharmony_cipvscsi_acquire_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct pvscsi_ctx *ctx; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (list_empty(&adapter->cmd_pool)) 17362306a36Sopenharmony_ci return NULL; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci ctx = list_first_entry(&adapter->cmd_pool, struct pvscsi_ctx, list); 17662306a36Sopenharmony_ci ctx->cmd = cmd; 17762306a36Sopenharmony_ci list_del(&ctx->list); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return ctx; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void pvscsi_release_context(struct pvscsi_adapter *adapter, 18362306a36Sopenharmony_ci struct pvscsi_ctx *ctx) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci ctx->cmd = NULL; 18662306a36Sopenharmony_ci ctx->abort_cmp = NULL; 18762306a36Sopenharmony_ci list_add(&ctx->list, &adapter->cmd_pool); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* 19162306a36Sopenharmony_ci * Map a pvscsi_ctx struct to a context ID field value; we map to a simple 19262306a36Sopenharmony_ci * non-zero integer. ctx always points to an entry in cmd_map array, hence 19362306a36Sopenharmony_ci * the return value is always >=1. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_cistatic u64 pvscsi_map_context(const struct pvscsi_adapter *adapter, 19662306a36Sopenharmony_ci const struct pvscsi_ctx *ctx) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci return ctx - adapter->cmd_map + 1; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic struct pvscsi_ctx * 20262306a36Sopenharmony_cipvscsi_get_context(const struct pvscsi_adapter *adapter, u64 context) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci return &adapter->cmd_map[context - 1]; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void pvscsi_reg_write(const struct pvscsi_adapter *adapter, 20862306a36Sopenharmony_ci u32 offset, u32 val) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci writel(val, adapter->mmioBase + offset); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic u32 pvscsi_reg_read(const struct pvscsi_adapter *adapter, u32 offset) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return readl(adapter->mmioBase + offset); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci return pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_INTR_STATUS); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter, 22462306a36Sopenharmony_ci u32 val) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_STATUS, val); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void pvscsi_unmask_intr(const struct pvscsi_adapter *adapter) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci u32 intr_bits; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci intr_bits = PVSCSI_INTR_CMPL_MASK; 23462306a36Sopenharmony_ci if (adapter->use_msg) 23562306a36Sopenharmony_ci intr_bits |= PVSCSI_INTR_MSG_MASK; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, intr_bits); 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic void pvscsi_mask_intr(const struct pvscsi_adapter *adapter) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, 0); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic void pvscsi_write_cmd_desc(const struct pvscsi_adapter *adapter, 24662306a36Sopenharmony_ci u32 cmd, const void *desc, size_t len) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci const u32 *ptr = desc; 24962306a36Sopenharmony_ci size_t i; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci len /= sizeof(*ptr); 25262306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, cmd); 25362306a36Sopenharmony_ci for (i = 0; i < len; i++) 25462306a36Sopenharmony_ci pvscsi_reg_write(adapter, 25562306a36Sopenharmony_ci PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter, 25962306a36Sopenharmony_ci const struct pvscsi_ctx *ctx) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct PVSCSICmdDescAbortCmd cmd = { 0 }; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci cmd.target = ctx->cmd->device->id; 26462306a36Sopenharmony_ci cmd.context = pvscsi_map_context(adapter, ctx); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd)); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic void pvscsi_kick_rw_io(const struct pvscsi_adapter *adapter) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_RW_IO, 0); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int scsi_is_rw(unsigned char op) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci return op == READ_6 || op == WRITE_6 || 28262306a36Sopenharmony_ci op == READ_10 || op == WRITE_10 || 28362306a36Sopenharmony_ci op == READ_12 || op == WRITE_12 || 28462306a36Sopenharmony_ci op == READ_16 || op == WRITE_16; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void pvscsi_kick_io(const struct pvscsi_adapter *adapter, 28862306a36Sopenharmony_ci unsigned char op) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci if (scsi_is_rw(op)) { 29162306a36Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (!adapter->use_req_threshold || 29462306a36Sopenharmony_ci s->reqProdIdx - s->reqConsIdx >= s->reqCallThreshold) 29562306a36Sopenharmony_ci pvscsi_kick_rw_io(adapter); 29662306a36Sopenharmony_ci } else { 29762306a36Sopenharmony_ci pvscsi_process_request_ring(adapter); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void ll_adapter_reset(const struct pvscsi_adapter *adapter) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci dev_dbg(pvscsi_dev(adapter), "Adapter Reset on %p\n", adapter); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void ll_bus_reset(const struct pvscsi_adapter *adapter) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci dev_dbg(pvscsi_dev(adapter), "Resetting bus on %p\n", adapter); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct PVSCSICmdDescResetDevice cmd = { 0 }; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci dev_dbg(pvscsi_dev(adapter), "Resetting device: target=%u\n", target); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci cmd.target = target; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE, 32462306a36Sopenharmony_ci &cmd, sizeof(cmd)); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void pvscsi_create_sg(struct pvscsi_ctx *ctx, 32862306a36Sopenharmony_ci struct scatterlist *sg, unsigned count) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci unsigned i; 33162306a36Sopenharmony_ci struct PVSCSISGElement *sge; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci sge = &ctx->sgl->sge[0]; 33662306a36Sopenharmony_ci for (i = 0; i < count; i++, sg = sg_next(sg)) { 33762306a36Sopenharmony_ci sge[i].addr = sg_dma_address(sg); 33862306a36Sopenharmony_ci sge[i].length = sg_dma_len(sg); 33962306a36Sopenharmony_ci sge[i].flags = 0; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci/* 34462306a36Sopenharmony_ci * Map all data buffers for a command into PCI space and 34562306a36Sopenharmony_ci * setup the scatter/gather list if needed. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_cistatic int pvscsi_map_buffers(struct pvscsi_adapter *adapter, 34862306a36Sopenharmony_ci struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd, 34962306a36Sopenharmony_ci struct PVSCSIRingReqDesc *e) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci unsigned count; 35262306a36Sopenharmony_ci unsigned bufflen = scsi_bufflen(cmd); 35362306a36Sopenharmony_ci struct scatterlist *sg; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci e->dataLen = bufflen; 35662306a36Sopenharmony_ci e->dataAddr = 0; 35762306a36Sopenharmony_ci if (bufflen == 0) 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci sg = scsi_sglist(cmd); 36162306a36Sopenharmony_ci count = scsi_sg_count(cmd); 36262306a36Sopenharmony_ci if (count != 0) { 36362306a36Sopenharmony_ci int segs = scsi_dma_map(cmd); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (segs == -ENOMEM) { 36662306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 36762306a36Sopenharmony_ci "vmw_pvscsi: Failed to map cmd sglist for DMA.\n"); 36862306a36Sopenharmony_ci return -ENOMEM; 36962306a36Sopenharmony_ci } else if (segs > 1) { 37062306a36Sopenharmony_ci pvscsi_create_sg(ctx, sg, segs); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; 37362306a36Sopenharmony_ci ctx->sglPA = dma_map_single(&adapter->dev->dev, 37462306a36Sopenharmony_ci ctx->sgl, SGL_SIZE, DMA_TO_DEVICE); 37562306a36Sopenharmony_ci if (dma_mapping_error(&adapter->dev->dev, ctx->sglPA)) { 37662306a36Sopenharmony_ci scmd_printk(KERN_ERR, cmd, 37762306a36Sopenharmony_ci "vmw_pvscsi: Failed to map ctx sglist for DMA.\n"); 37862306a36Sopenharmony_ci scsi_dma_unmap(cmd); 37962306a36Sopenharmony_ci ctx->sglPA = 0; 38062306a36Sopenharmony_ci return -ENOMEM; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci e->dataAddr = ctx->sglPA; 38362306a36Sopenharmony_ci } else 38462306a36Sopenharmony_ci e->dataAddr = sg_dma_address(sg); 38562306a36Sopenharmony_ci } else { 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * In case there is no S/G list, scsi_sglist points 38862306a36Sopenharmony_ci * directly to the buffer. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci ctx->dataPA = dma_map_single(&adapter->dev->dev, sg, bufflen, 39162306a36Sopenharmony_ci cmd->sc_data_direction); 39262306a36Sopenharmony_ci if (dma_mapping_error(&adapter->dev->dev, ctx->dataPA)) { 39362306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 39462306a36Sopenharmony_ci "vmw_pvscsi: Failed to map direct data buffer for DMA.\n"); 39562306a36Sopenharmony_ci return -ENOMEM; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci e->dataAddr = ctx->dataPA; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* 40462306a36Sopenharmony_ci * The device incorrectly doesn't clear the first byte of the sense 40562306a36Sopenharmony_ci * buffer in some cases. We have to do it ourselves. 40662306a36Sopenharmony_ci * Otherwise we run into trouble when SWIOTLB is forced. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_cistatic void pvscsi_patch_sense(struct scsi_cmnd *cmd) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci if (cmd->sense_buffer) 41162306a36Sopenharmony_ci cmd->sense_buffer[0] = 0; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, 41562306a36Sopenharmony_ci struct pvscsi_ctx *ctx) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct scsi_cmnd *cmd; 41862306a36Sopenharmony_ci unsigned bufflen; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci cmd = ctx->cmd; 42162306a36Sopenharmony_ci bufflen = scsi_bufflen(cmd); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (bufflen != 0) { 42462306a36Sopenharmony_ci unsigned count = scsi_sg_count(cmd); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (count != 0) { 42762306a36Sopenharmony_ci scsi_dma_unmap(cmd); 42862306a36Sopenharmony_ci if (ctx->sglPA) { 42962306a36Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->sglPA, 43062306a36Sopenharmony_ci SGL_SIZE, DMA_TO_DEVICE); 43162306a36Sopenharmony_ci ctx->sglPA = 0; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci } else 43462306a36Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->dataPA, 43562306a36Sopenharmony_ci bufflen, cmd->sc_data_direction); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci if (cmd->sense_buffer) 43862306a36Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->sensePA, 43962306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci adapter->rings_state = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, 44562306a36Sopenharmony_ci &adapter->ringStatePA, GFP_KERNEL); 44662306a36Sopenharmony_ci if (!adapter->rings_state) 44762306a36Sopenharmony_ci return -ENOMEM; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci adapter->req_pages = min(PVSCSI_MAX_NUM_PAGES_REQ_RING, 45062306a36Sopenharmony_ci pvscsi_ring_pages); 45162306a36Sopenharmony_ci adapter->req_depth = adapter->req_pages 45262306a36Sopenharmony_ci * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; 45362306a36Sopenharmony_ci adapter->req_ring = dma_alloc_coherent(&adapter->dev->dev, 45462306a36Sopenharmony_ci adapter->req_pages * PAGE_SIZE, &adapter->reqRingPA, 45562306a36Sopenharmony_ci GFP_KERNEL); 45662306a36Sopenharmony_ci if (!adapter->req_ring) 45762306a36Sopenharmony_ci return -ENOMEM; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING, 46062306a36Sopenharmony_ci pvscsi_ring_pages); 46162306a36Sopenharmony_ci adapter->cmp_ring = dma_alloc_coherent(&adapter->dev->dev, 46262306a36Sopenharmony_ci adapter->cmp_pages * PAGE_SIZE, &adapter->cmpRingPA, 46362306a36Sopenharmony_ci GFP_KERNEL); 46462306a36Sopenharmony_ci if (!adapter->cmp_ring) 46562306a36Sopenharmony_ci return -ENOMEM; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->ringStatePA, PAGE_SIZE)); 46862306a36Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->reqRingPA, PAGE_SIZE)); 46962306a36Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->cmpRingPA, PAGE_SIZE)); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (!adapter->use_msg) 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING, 47562306a36Sopenharmony_ci pvscsi_msg_ring_pages); 47662306a36Sopenharmony_ci adapter->msg_ring = dma_alloc_coherent(&adapter->dev->dev, 47762306a36Sopenharmony_ci adapter->msg_pages * PAGE_SIZE, &adapter->msgRingPA, 47862306a36Sopenharmony_ci GFP_KERNEL); 47962306a36Sopenharmony_ci if (!adapter->msg_ring) 48062306a36Sopenharmony_ci return -ENOMEM; 48162306a36Sopenharmony_ci BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE)); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct PVSCSICmdDescSetupRings cmd = { 0 }; 48962306a36Sopenharmony_ci dma_addr_t base; 49062306a36Sopenharmony_ci unsigned i; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci cmd.ringsStatePPN = adapter->ringStatePA >> PAGE_SHIFT; 49362306a36Sopenharmony_ci cmd.reqRingNumPages = adapter->req_pages; 49462306a36Sopenharmony_ci cmd.cmpRingNumPages = adapter->cmp_pages; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci base = adapter->reqRingPA; 49762306a36Sopenharmony_ci for (i = 0; i < adapter->req_pages; i++) { 49862306a36Sopenharmony_ci cmd.reqRingPPNs[i] = base >> PAGE_SHIFT; 49962306a36Sopenharmony_ci base += PAGE_SIZE; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci base = adapter->cmpRingPA; 50362306a36Sopenharmony_ci for (i = 0; i < adapter->cmp_pages; i++) { 50462306a36Sopenharmony_ci cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT; 50562306a36Sopenharmony_ci base += PAGE_SIZE; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci memset(adapter->rings_state, 0, PAGE_SIZE); 50962306a36Sopenharmony_ci memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE); 51062306a36Sopenharmony_ci memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS, 51362306a36Sopenharmony_ci &cmd, sizeof(cmd)); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (adapter->use_msg) { 51662306a36Sopenharmony_ci struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 }; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci cmd_msg.numPages = adapter->msg_pages; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci base = adapter->msgRingPA; 52162306a36Sopenharmony_ci for (i = 0; i < adapter->msg_pages; i++) { 52262306a36Sopenharmony_ci cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT; 52362306a36Sopenharmony_ci base += PAGE_SIZE; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci memset(adapter->msg_ring, 0, adapter->msg_pages * PAGE_SIZE); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_MSG_RING, 52862306a36Sopenharmony_ci &cmd_msg, sizeof(cmd_msg)); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int pvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci if (!sdev->tagged_supported) 53562306a36Sopenharmony_ci qdepth = 1; 53662306a36Sopenharmony_ci return scsi_change_queue_depth(sdev, qdepth); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/* 54062306a36Sopenharmony_ci * Pull a completion descriptor off and pass the completion back 54162306a36Sopenharmony_ci * to the SCSI mid layer. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_cistatic void pvscsi_complete_request(struct pvscsi_adapter *adapter, 54462306a36Sopenharmony_ci const struct PVSCSIRingCmpDesc *e) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct pvscsi_ctx *ctx; 54762306a36Sopenharmony_ci struct scsi_cmnd *cmd; 54862306a36Sopenharmony_ci struct completion *abort_cmp; 54962306a36Sopenharmony_ci u32 btstat = e->hostStatus; 55062306a36Sopenharmony_ci u32 sdstat = e->scsiStatus; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci ctx = pvscsi_get_context(adapter, e->context); 55362306a36Sopenharmony_ci cmd = ctx->cmd; 55462306a36Sopenharmony_ci abort_cmp = ctx->abort_cmp; 55562306a36Sopenharmony_ci pvscsi_unmap_buffers(adapter, ctx); 55662306a36Sopenharmony_ci if (sdstat != SAM_STAT_CHECK_CONDITION) 55762306a36Sopenharmony_ci pvscsi_patch_sense(cmd); 55862306a36Sopenharmony_ci pvscsi_release_context(adapter, ctx); 55962306a36Sopenharmony_ci if (abort_cmp) { 56062306a36Sopenharmony_ci /* 56162306a36Sopenharmony_ci * The command was requested to be aborted. Just signal that 56262306a36Sopenharmony_ci * the request completed and swallow the actual cmd completion 56362306a36Sopenharmony_ci * here. The abort handler will post a completion for this 56462306a36Sopenharmony_ci * command indicating that it got successfully aborted. 56562306a36Sopenharmony_ci */ 56662306a36Sopenharmony_ci complete(abort_cmp); 56762306a36Sopenharmony_ci return; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci cmd->result = 0; 57162306a36Sopenharmony_ci if (sdstat != SAM_STAT_GOOD && 57262306a36Sopenharmony_ci (btstat == BTSTAT_SUCCESS || 57362306a36Sopenharmony_ci btstat == BTSTAT_LINKED_COMMAND_COMPLETED || 57462306a36Sopenharmony_ci btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { 57562306a36Sopenharmony_ci if (sdstat == SAM_STAT_COMMAND_TERMINATED) { 57662306a36Sopenharmony_ci cmd->result = (DID_RESET << 16); 57762306a36Sopenharmony_ci } else { 57862306a36Sopenharmony_ci cmd->result = (DID_OK << 16) | sdstat; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci } else 58162306a36Sopenharmony_ci switch (btstat) { 58262306a36Sopenharmony_ci case BTSTAT_SUCCESS: 58362306a36Sopenharmony_ci case BTSTAT_LINKED_COMMAND_COMPLETED: 58462306a36Sopenharmony_ci case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * Commands like INQUIRY may transfer less data than 58762306a36Sopenharmony_ci * requested by the initiator via bufflen. Set residual 58862306a36Sopenharmony_ci * count to make upper layer aware of the actual amount 58962306a36Sopenharmony_ci * of data returned. There are cases when controller 59062306a36Sopenharmony_ci * returns zero dataLen with non zero data - do not set 59162306a36Sopenharmony_ci * residual count in that case. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci if (e->dataLen && (e->dataLen < scsi_bufflen(cmd))) 59462306a36Sopenharmony_ci scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen); 59562306a36Sopenharmony_ci cmd->result = (DID_OK << 16); 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci case BTSTAT_DATARUN: 59962306a36Sopenharmony_ci case BTSTAT_DATA_UNDERRUN: 60062306a36Sopenharmony_ci /* Report residual data in underruns */ 60162306a36Sopenharmony_ci scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen); 60262306a36Sopenharmony_ci cmd->result = (DID_ERROR << 16); 60362306a36Sopenharmony_ci break; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci case BTSTAT_SELTIMEO: 60662306a36Sopenharmony_ci /* Our emulation returns this for non-connected devs */ 60762306a36Sopenharmony_ci cmd->result = (DID_BAD_TARGET << 16); 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci case BTSTAT_LUNMISMATCH: 61162306a36Sopenharmony_ci case BTSTAT_TAGREJECT: 61262306a36Sopenharmony_ci case BTSTAT_BADMSG: 61362306a36Sopenharmony_ci case BTSTAT_HAHARDWARE: 61462306a36Sopenharmony_ci case BTSTAT_INVPHASE: 61562306a36Sopenharmony_ci case BTSTAT_HATIMEOUT: 61662306a36Sopenharmony_ci case BTSTAT_NORESPONSE: 61762306a36Sopenharmony_ci case BTSTAT_DISCONNECT: 61862306a36Sopenharmony_ci case BTSTAT_HASOFTWARE: 61962306a36Sopenharmony_ci case BTSTAT_BUSFREE: 62062306a36Sopenharmony_ci case BTSTAT_SENSFAILED: 62162306a36Sopenharmony_ci cmd->result |= (DID_ERROR << 16); 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci case BTSTAT_SENTRST: 62562306a36Sopenharmony_ci case BTSTAT_RECVRST: 62662306a36Sopenharmony_ci case BTSTAT_BUSRESET: 62762306a36Sopenharmony_ci cmd->result = (DID_RESET << 16); 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci case BTSTAT_ABORTQUEUE: 63162306a36Sopenharmony_ci cmd->result = (DID_BUS_BUSY << 16); 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci case BTSTAT_SCSIPARITY: 63562306a36Sopenharmony_ci cmd->result = (DID_PARITY << 16); 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci default: 63962306a36Sopenharmony_ci cmd->result = (DID_ERROR << 16); 64062306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 64162306a36Sopenharmony_ci "Unknown completion status: 0x%x\n", 64262306a36Sopenharmony_ci btstat); 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci dev_dbg(&cmd->device->sdev_gendev, 64662306a36Sopenharmony_ci "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n", 64762306a36Sopenharmony_ci cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci scsi_done(cmd); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci/* 65362306a36Sopenharmony_ci * barrier usage : Since the PVSCSI device is emulated, there could be cases 65462306a36Sopenharmony_ci * where we may want to serialize some accesses between the driver and the 65562306a36Sopenharmony_ci * emulation layer. We use compiler barriers instead of the more expensive 65662306a36Sopenharmony_ci * memory barriers because PVSCSI is only supported on X86 which has strong 65762306a36Sopenharmony_ci * memory access ordering. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_cistatic void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 66262306a36Sopenharmony_ci struct PVSCSIRingCmpDesc *ring = adapter->cmp_ring; 66362306a36Sopenharmony_ci u32 cmp_entries = s->cmpNumEntriesLog2; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci while (s->cmpConsIdx != s->cmpProdIdx) { 66662306a36Sopenharmony_ci struct PVSCSIRingCmpDesc *e = ring + (s->cmpConsIdx & 66762306a36Sopenharmony_ci MASK(cmp_entries)); 66862306a36Sopenharmony_ci /* 66962306a36Sopenharmony_ci * This barrier() ensures that *e is not dereferenced while 67062306a36Sopenharmony_ci * the device emulation still writes data into the slot. 67162306a36Sopenharmony_ci * Since the device emulation advances s->cmpProdIdx only after 67262306a36Sopenharmony_ci * updating the slot we want to check it first. 67362306a36Sopenharmony_ci */ 67462306a36Sopenharmony_ci barrier(); 67562306a36Sopenharmony_ci pvscsi_complete_request(adapter, e); 67662306a36Sopenharmony_ci /* 67762306a36Sopenharmony_ci * This barrier() ensures that compiler doesn't reorder write 67862306a36Sopenharmony_ci * to s->cmpConsIdx before the read of (*e) inside 67962306a36Sopenharmony_ci * pvscsi_complete_request. Otherwise, device emulation may 68062306a36Sopenharmony_ci * overwrite *e before we had a chance to read it. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci barrier(); 68362306a36Sopenharmony_ci s->cmpConsIdx++; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci/* 68862306a36Sopenharmony_ci * Translate a Linux SCSI request into a request ring entry. 68962306a36Sopenharmony_ci */ 69062306a36Sopenharmony_cistatic int pvscsi_queue_ring(struct pvscsi_adapter *adapter, 69162306a36Sopenharmony_ci struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct PVSCSIRingsState *s; 69462306a36Sopenharmony_ci struct PVSCSIRingReqDesc *e; 69562306a36Sopenharmony_ci struct scsi_device *sdev; 69662306a36Sopenharmony_ci u32 req_entries; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci s = adapter->rings_state; 69962306a36Sopenharmony_ci sdev = cmd->device; 70062306a36Sopenharmony_ci req_entries = s->reqNumEntriesLog2; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* 70362306a36Sopenharmony_ci * If this condition holds, we might have room on the request ring, but 70462306a36Sopenharmony_ci * we might not have room on the completion ring for the response. 70562306a36Sopenharmony_ci * However, we have already ruled out this possibility - we would not 70662306a36Sopenharmony_ci * have successfully allocated a context if it were true, since we only 70762306a36Sopenharmony_ci * have one context per request entry. Check for it anyway, since it 70862306a36Sopenharmony_ci * would be a serious bug. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) { 71162306a36Sopenharmony_ci scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: " 71262306a36Sopenharmony_ci "ring full: reqProdIdx=%d cmpConsIdx=%d\n", 71362306a36Sopenharmony_ci s->reqProdIdx, s->cmpConsIdx); 71462306a36Sopenharmony_ci return -1; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci e = adapter->req_ring + (s->reqProdIdx & MASK(req_entries)); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci e->bus = sdev->channel; 72062306a36Sopenharmony_ci e->target = sdev->id; 72162306a36Sopenharmony_ci memset(e->lun, 0, sizeof(e->lun)); 72262306a36Sopenharmony_ci e->lun[1] = sdev->lun; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (cmd->sense_buffer) { 72562306a36Sopenharmony_ci ctx->sensePA = dma_map_single(&adapter->dev->dev, 72662306a36Sopenharmony_ci cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, 72762306a36Sopenharmony_ci DMA_FROM_DEVICE); 72862306a36Sopenharmony_ci if (dma_mapping_error(&adapter->dev->dev, ctx->sensePA)) { 72962306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 73062306a36Sopenharmony_ci "vmw_pvscsi: Failed to map sense buffer for DMA.\n"); 73162306a36Sopenharmony_ci ctx->sensePA = 0; 73262306a36Sopenharmony_ci return -ENOMEM; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci e->senseAddr = ctx->sensePA; 73562306a36Sopenharmony_ci e->senseLen = SCSI_SENSE_BUFFERSIZE; 73662306a36Sopenharmony_ci } else { 73762306a36Sopenharmony_ci e->senseLen = 0; 73862306a36Sopenharmony_ci e->senseAddr = 0; 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci e->cdbLen = cmd->cmd_len; 74162306a36Sopenharmony_ci e->vcpuHint = smp_processor_id(); 74262306a36Sopenharmony_ci memcpy(e->cdb, cmd->cmnd, e->cdbLen); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci e->tag = SIMPLE_QUEUE_TAG; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (cmd->sc_data_direction == DMA_FROM_DEVICE) 74762306a36Sopenharmony_ci e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST; 74862306a36Sopenharmony_ci else if (cmd->sc_data_direction == DMA_TO_DEVICE) 74962306a36Sopenharmony_ci e->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE; 75062306a36Sopenharmony_ci else if (cmd->sc_data_direction == DMA_NONE) 75162306a36Sopenharmony_ci e->flags = PVSCSI_FLAG_CMD_DIR_NONE; 75262306a36Sopenharmony_ci else 75362306a36Sopenharmony_ci e->flags = 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) { 75662306a36Sopenharmony_ci if (cmd->sense_buffer) { 75762306a36Sopenharmony_ci dma_unmap_single(&adapter->dev->dev, ctx->sensePA, 75862306a36Sopenharmony_ci SCSI_SENSE_BUFFERSIZE, 75962306a36Sopenharmony_ci DMA_FROM_DEVICE); 76062306a36Sopenharmony_ci ctx->sensePA = 0; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci return -ENOMEM; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci e->context = pvscsi_map_context(adapter, ctx); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci barrier(); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci s->reqProdIdx++; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int pvscsi_queue_lck(struct scsi_cmnd *cmd) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 77762306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 77862306a36Sopenharmony_ci struct pvscsi_ctx *ctx; 77962306a36Sopenharmony_ci unsigned long flags; 78062306a36Sopenharmony_ci unsigned char op; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci ctx = pvscsi_acquire_context(adapter, cmd); 78562306a36Sopenharmony_ci if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) { 78662306a36Sopenharmony_ci if (ctx) 78762306a36Sopenharmony_ci pvscsi_release_context(adapter, ctx); 78862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 78962306a36Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci op = cmd->cmnd[0]; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci dev_dbg(&cmd->device->sdev_gendev, 79562306a36Sopenharmony_ci "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci pvscsi_kick_io(adapter, op); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic DEF_SCSI_QCMD(pvscsi_queue) 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int pvscsi_abort(struct scsi_cmnd *cmd) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(cmd->device->host); 80962306a36Sopenharmony_ci struct pvscsi_ctx *ctx; 81062306a36Sopenharmony_ci unsigned long flags; 81162306a36Sopenharmony_ci int result = SUCCESS; 81262306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(abort_cmp); 81362306a36Sopenharmony_ci int done; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n", 81662306a36Sopenharmony_ci adapter->host->host_no, cmd); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* 82162306a36Sopenharmony_ci * Poll the completion ring first - we might be trying to abort 82262306a36Sopenharmony_ci * a command that is waiting to be dispatched in the completion ring. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci pvscsi_process_completion_ring(adapter); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* 82762306a36Sopenharmony_ci * If there is no context for the command, it either already succeeded 82862306a36Sopenharmony_ci * or else was never properly issued. Not our problem. 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_ci ctx = pvscsi_find_context(adapter, cmd); 83162306a36Sopenharmony_ci if (!ctx) { 83262306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, "Failed to abort cmd %p\n", cmd); 83362306a36Sopenharmony_ci goto out; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* 83762306a36Sopenharmony_ci * Mark that the command has been requested to be aborted and issue 83862306a36Sopenharmony_ci * the abort. 83962306a36Sopenharmony_ci */ 84062306a36Sopenharmony_ci ctx->abort_cmp = &abort_cmp; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci pvscsi_abort_cmd(adapter, ctx); 84362306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 84462306a36Sopenharmony_ci /* Wait for 2 secs for the completion. */ 84562306a36Sopenharmony_ci done = wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000)); 84662306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (!done) { 84962306a36Sopenharmony_ci /* 85062306a36Sopenharmony_ci * Failed to abort the command, unmark the fact that it 85162306a36Sopenharmony_ci * was requested to be aborted. 85262306a36Sopenharmony_ci */ 85362306a36Sopenharmony_ci ctx->abort_cmp = NULL; 85462306a36Sopenharmony_ci result = FAILED; 85562306a36Sopenharmony_ci scmd_printk(KERN_DEBUG, cmd, 85662306a36Sopenharmony_ci "Failed to get completion for aborted cmd %p\n", 85762306a36Sopenharmony_ci cmd); 85862306a36Sopenharmony_ci goto out; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* 86262306a36Sopenharmony_ci * Successfully aborted the command. 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_ci cmd->result = (DID_ABORT << 16); 86562306a36Sopenharmony_ci scsi_done(cmd); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ciout: 86862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 86962306a36Sopenharmony_ci return result; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci/* 87362306a36Sopenharmony_ci * Abort all outstanding requests. This is only safe to use if the completion 87462306a36Sopenharmony_ci * ring will never be walked again or the device has been reset, because it 87562306a36Sopenharmony_ci * destroys the 1-1 mapping between context field passed to emulation and our 87662306a36Sopenharmony_ci * request structure. 87762306a36Sopenharmony_ci */ 87862306a36Sopenharmony_cistatic void pvscsi_reset_all(struct pvscsi_adapter *adapter) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci unsigned i; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci for (i = 0; i < adapter->req_depth; i++) { 88362306a36Sopenharmony_ci struct pvscsi_ctx *ctx = &adapter->cmd_map[i]; 88462306a36Sopenharmony_ci struct scsi_cmnd *cmd = ctx->cmd; 88562306a36Sopenharmony_ci if (cmd) { 88662306a36Sopenharmony_ci scmd_printk(KERN_ERR, cmd, 88762306a36Sopenharmony_ci "Forced reset on cmd %p\n", cmd); 88862306a36Sopenharmony_ci pvscsi_unmap_buffers(adapter, ctx); 88962306a36Sopenharmony_ci pvscsi_patch_sense(cmd); 89062306a36Sopenharmony_ci pvscsi_release_context(adapter, ctx); 89162306a36Sopenharmony_ci cmd->result = (DID_RESET << 16); 89262306a36Sopenharmony_ci scsi_done(cmd); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int pvscsi_host_reset(struct scsi_cmnd *cmd) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 90062306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 90162306a36Sopenharmony_ci unsigned long flags; 90262306a36Sopenharmony_ci bool use_msg; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "SCSI Host reset\n"); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci use_msg = adapter->use_msg; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (use_msg) { 91162306a36Sopenharmony_ci adapter->use_msg = false; 91262306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* 91562306a36Sopenharmony_ci * Now that we know that the ISR won't add more work on the 91662306a36Sopenharmony_ci * workqueue we can safely flush any outstanding work. 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_ci flush_workqueue(adapter->workqueue); 91962306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* 92362306a36Sopenharmony_ci * We're going to tear down the entire ring structure and set it back 92462306a36Sopenharmony_ci * up, so stalling new requests until all completions are flushed and 92562306a36Sopenharmony_ci * the rings are back in place. 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci pvscsi_process_request_ring(adapter); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci ll_adapter_reset(adapter); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* 93362306a36Sopenharmony_ci * Now process any completions. Note we do this AFTER adapter reset, 93462306a36Sopenharmony_ci * which is strange, but stops races where completions get posted 93562306a36Sopenharmony_ci * between processing the ring and issuing the reset. The backend will 93662306a36Sopenharmony_ci * not touch the ring memory after reset, so the immediately pre-reset 93762306a36Sopenharmony_ci * completion ring state is still valid. 93862306a36Sopenharmony_ci */ 93962306a36Sopenharmony_ci pvscsi_process_completion_ring(adapter); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci pvscsi_reset_all(adapter); 94262306a36Sopenharmony_ci adapter->use_msg = use_msg; 94362306a36Sopenharmony_ci pvscsi_setup_all_rings(adapter); 94462306a36Sopenharmony_ci pvscsi_unmask_intr(adapter); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return SUCCESS; 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic int pvscsi_bus_reset(struct scsi_cmnd *cmd) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 95462306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 95562306a36Sopenharmony_ci unsigned long flags; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "SCSI Bus reset\n"); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci /* 96062306a36Sopenharmony_ci * We don't want to queue new requests for this bus after 96162306a36Sopenharmony_ci * flushing all pending requests to emulation, since new 96262306a36Sopenharmony_ci * requests could then sneak in during this bus reset phase, 96362306a36Sopenharmony_ci * so take the lock now. 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci pvscsi_process_request_ring(adapter); 96862306a36Sopenharmony_ci ll_bus_reset(adapter); 96962306a36Sopenharmony_ci pvscsi_process_completion_ring(adapter); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return SUCCESS; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic int pvscsi_device_reset(struct scsi_cmnd *cmd) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct Scsi_Host *host = cmd->device->host; 97962306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 98062306a36Sopenharmony_ci unsigned long flags; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci scmd_printk(KERN_INFO, cmd, "SCSI device reset on scsi%u:%u\n", 98362306a36Sopenharmony_ci host->host_no, cmd->device->id); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* 98662306a36Sopenharmony_ci * We don't want to queue new requests for this device after flushing 98762306a36Sopenharmony_ci * all pending requests to emulation, since new requests could then 98862306a36Sopenharmony_ci * sneak in during this device reset phase, so take the lock now. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci pvscsi_process_request_ring(adapter); 99362306a36Sopenharmony_ci ll_device_reset(adapter, cmd->device->id); 99462306a36Sopenharmony_ci pvscsi_process_completion_ring(adapter); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci return SUCCESS; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic struct scsi_host_template pvscsi_template; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic const char *pvscsi_info(struct Scsi_Host *host) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 100662306a36Sopenharmony_ci static char buf[256]; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci sprintf(buf, "VMware PVSCSI storage adapter rev %d, req/cmp/msg rings: " 100962306a36Sopenharmony_ci "%u/%u/%u pages, cmd_per_lun=%u", adapter->rev, 101062306a36Sopenharmony_ci adapter->req_pages, adapter->cmp_pages, adapter->msg_pages, 101162306a36Sopenharmony_ci pvscsi_template.cmd_per_lun); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci return buf; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic struct scsi_host_template pvscsi_template = { 101762306a36Sopenharmony_ci .module = THIS_MODULE, 101862306a36Sopenharmony_ci .name = "VMware PVSCSI Host Adapter", 101962306a36Sopenharmony_ci .proc_name = "vmw_pvscsi", 102062306a36Sopenharmony_ci .info = pvscsi_info, 102162306a36Sopenharmony_ci .queuecommand = pvscsi_queue, 102262306a36Sopenharmony_ci .this_id = -1, 102362306a36Sopenharmony_ci .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT, 102462306a36Sopenharmony_ci .dma_boundary = UINT_MAX, 102562306a36Sopenharmony_ci .max_sectors = 0xffff, 102662306a36Sopenharmony_ci .change_queue_depth = pvscsi_change_queue_depth, 102762306a36Sopenharmony_ci .eh_abort_handler = pvscsi_abort, 102862306a36Sopenharmony_ci .eh_device_reset_handler = pvscsi_device_reset, 102962306a36Sopenharmony_ci .eh_bus_reset_handler = pvscsi_bus_reset, 103062306a36Sopenharmony_ci .eh_host_reset_handler = pvscsi_host_reset, 103162306a36Sopenharmony_ci}; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic void pvscsi_process_msg(const struct pvscsi_adapter *adapter, 103462306a36Sopenharmony_ci const struct PVSCSIRingMsgDesc *e) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 103762306a36Sopenharmony_ci struct Scsi_Host *host = adapter->host; 103862306a36Sopenharmony_ci struct scsi_device *sdev; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: msg type: 0x%x - MSG RING: %u/%u (%u) \n", 104162306a36Sopenharmony_ci e->type, s->msgProdIdx, s->msgConsIdx, s->msgNumEntriesLog2); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci BUILD_BUG_ON(PVSCSI_MSG_LAST != 2); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if (e->type == PVSCSI_MSG_DEV_ADDED) { 104662306a36Sopenharmony_ci struct PVSCSIMsgDescDevStatusChanged *desc; 104762306a36Sopenharmony_ci desc = (struct PVSCSIMsgDescDevStatusChanged *)e; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci printk(KERN_INFO 105062306a36Sopenharmony_ci "vmw_pvscsi: msg: device added at scsi%u:%u:%u\n", 105162306a36Sopenharmony_ci desc->bus, desc->target, desc->lun[1]); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (!scsi_host_get(host)) 105462306a36Sopenharmony_ci return; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci sdev = scsi_device_lookup(host, desc->bus, desc->target, 105762306a36Sopenharmony_ci desc->lun[1]); 105862306a36Sopenharmony_ci if (sdev) { 105962306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: device already exists\n"); 106062306a36Sopenharmony_ci scsi_device_put(sdev); 106162306a36Sopenharmony_ci } else 106262306a36Sopenharmony_ci scsi_add_device(adapter->host, desc->bus, 106362306a36Sopenharmony_ci desc->target, desc->lun[1]); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci scsi_host_put(host); 106662306a36Sopenharmony_ci } else if (e->type == PVSCSI_MSG_DEV_REMOVED) { 106762306a36Sopenharmony_ci struct PVSCSIMsgDescDevStatusChanged *desc; 106862306a36Sopenharmony_ci desc = (struct PVSCSIMsgDescDevStatusChanged *)e; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci printk(KERN_INFO 107162306a36Sopenharmony_ci "vmw_pvscsi: msg: device removed at scsi%u:%u:%u\n", 107262306a36Sopenharmony_ci desc->bus, desc->target, desc->lun[1]); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (!scsi_host_get(host)) 107562306a36Sopenharmony_ci return; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci sdev = scsi_device_lookup(host, desc->bus, desc->target, 107862306a36Sopenharmony_ci desc->lun[1]); 107962306a36Sopenharmony_ci if (sdev) { 108062306a36Sopenharmony_ci scsi_remove_device(sdev); 108162306a36Sopenharmony_ci scsi_device_put(sdev); 108262306a36Sopenharmony_ci } else 108362306a36Sopenharmony_ci printk(KERN_INFO 108462306a36Sopenharmony_ci "vmw_pvscsi: failed to lookup scsi%u:%u:%u\n", 108562306a36Sopenharmony_ci desc->bus, desc->target, desc->lun[1]); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci scsi_host_put(host); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cistatic int pvscsi_msg_pending(const struct pvscsi_adapter *adapter) 109262306a36Sopenharmony_ci{ 109362306a36Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return s->msgProdIdx != s->msgConsIdx; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic void pvscsi_process_msg_ring(const struct pvscsi_adapter *adapter) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci struct PVSCSIRingsState *s = adapter->rings_state; 110162306a36Sopenharmony_ci struct PVSCSIRingMsgDesc *ring = adapter->msg_ring; 110262306a36Sopenharmony_ci u32 msg_entries = s->msgNumEntriesLog2; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci while (pvscsi_msg_pending(adapter)) { 110562306a36Sopenharmony_ci struct PVSCSIRingMsgDesc *e = ring + (s->msgConsIdx & 110662306a36Sopenharmony_ci MASK(msg_entries)); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci barrier(); 110962306a36Sopenharmony_ci pvscsi_process_msg(adapter, e); 111062306a36Sopenharmony_ci barrier(); 111162306a36Sopenharmony_ci s->msgConsIdx++; 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic void pvscsi_msg_workqueue_handler(struct work_struct *data) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci struct pvscsi_adapter *adapter; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci adapter = container_of(data, struct pvscsi_adapter, work); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci pvscsi_process_msg_ring(adapter); 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci char name[32]; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (!pvscsi_use_msg) 112962306a36Sopenharmony_ci return 0; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, 113262306a36Sopenharmony_ci PVSCSI_CMD_SETUP_MSG_RING); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS) == -1) 113562306a36Sopenharmony_ci return 0; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci snprintf(name, sizeof(name), 113862306a36Sopenharmony_ci "vmw_pvscsi_wq_%u", adapter->host->host_no); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci adapter->workqueue = create_singlethread_workqueue(name); 114162306a36Sopenharmony_ci if (!adapter->workqueue) { 114262306a36Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n"); 114362306a36Sopenharmony_ci return 0; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci INIT_WORK(&adapter->work, pvscsi_msg_workqueue_handler); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci return 1; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter, 115162306a36Sopenharmony_ci bool enable) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci u32 val; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (!pvscsi_use_req_threshold) 115662306a36Sopenharmony_ci return false; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, 115962306a36Sopenharmony_ci PVSCSI_CMD_SETUP_REQCALLTHRESHOLD); 116062306a36Sopenharmony_ci val = pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS); 116162306a36Sopenharmony_ci if (val == -1) { 116262306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: device does not support req_threshold\n"); 116362306a36Sopenharmony_ci return false; 116462306a36Sopenharmony_ci } else { 116562306a36Sopenharmony_ci struct PVSCSICmdDescSetupReqCall cmd_msg = { 0 }; 116662306a36Sopenharmony_ci cmd_msg.enable = enable; 116762306a36Sopenharmony_ci printk(KERN_INFO 116862306a36Sopenharmony_ci "vmw_pvscsi: %sabling reqCallThreshold\n", 116962306a36Sopenharmony_ci enable ? "en" : "dis"); 117062306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, 117162306a36Sopenharmony_ci PVSCSI_CMD_SETUP_REQCALLTHRESHOLD, 117262306a36Sopenharmony_ci &cmd_msg, sizeof(cmd_msg)); 117362306a36Sopenharmony_ci return pvscsi_reg_read(adapter, 117462306a36Sopenharmony_ci PVSCSI_REG_OFFSET_COMMAND_STATUS) != 0; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic irqreturn_t pvscsi_isr(int irq, void *devp) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci struct pvscsi_adapter *adapter = devp; 118162306a36Sopenharmony_ci unsigned long flags; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci spin_lock_irqsave(&adapter->hw_lock, flags); 118462306a36Sopenharmony_ci pvscsi_process_completion_ring(adapter); 118562306a36Sopenharmony_ci if (adapter->use_msg && pvscsi_msg_pending(adapter)) 118662306a36Sopenharmony_ci queue_work(adapter->workqueue, &adapter->work); 118762306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->hw_lock, flags); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci return IRQ_HANDLED; 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic irqreturn_t pvscsi_shared_isr(int irq, void *devp) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct pvscsi_adapter *adapter = devp; 119562306a36Sopenharmony_ci u32 val = pvscsi_read_intr_status(adapter); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (!(val & PVSCSI_INTR_ALL_SUPPORTED)) 119862306a36Sopenharmony_ci return IRQ_NONE; 119962306a36Sopenharmony_ci pvscsi_write_intr_status(devp, val); 120062306a36Sopenharmony_ci return pvscsi_isr(irq, devp); 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct pvscsi_ctx *ctx = adapter->cmd_map; 120662306a36Sopenharmony_ci unsigned i; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci for (i = 0; i < adapter->req_depth; ++i, ++ctx) 120962306a36Sopenharmony_ci free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE)); 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci free_irq(pci_irq_vector(adapter->dev, 0), adapter); 121562306a36Sopenharmony_ci pci_free_irq_vectors(adapter->dev); 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_cistatic void pvscsi_release_resources(struct pvscsi_adapter *adapter) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci if (adapter->workqueue) 122162306a36Sopenharmony_ci destroy_workqueue(adapter->workqueue); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (adapter->mmioBase) 122462306a36Sopenharmony_ci pci_iounmap(adapter->dev, adapter->mmioBase); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci pci_release_regions(adapter->dev); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if (adapter->cmd_map) { 122962306a36Sopenharmony_ci pvscsi_free_sgls(adapter); 123062306a36Sopenharmony_ci kfree(adapter->cmd_map); 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (adapter->rings_state) 123462306a36Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, 123562306a36Sopenharmony_ci adapter->rings_state, adapter->ringStatePA); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (adapter->req_ring) 123862306a36Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 123962306a36Sopenharmony_ci adapter->req_pages * PAGE_SIZE, 124062306a36Sopenharmony_ci adapter->req_ring, adapter->reqRingPA); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci if (adapter->cmp_ring) 124362306a36Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 124462306a36Sopenharmony_ci adapter->cmp_pages * PAGE_SIZE, 124562306a36Sopenharmony_ci adapter->cmp_ring, adapter->cmpRingPA); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (adapter->msg_ring) 124862306a36Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, 124962306a36Sopenharmony_ci adapter->msg_pages * PAGE_SIZE, 125062306a36Sopenharmony_ci adapter->msg_ring, adapter->msgRingPA); 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci/* 125462306a36Sopenharmony_ci * Allocate scatter gather lists. 125562306a36Sopenharmony_ci * 125662306a36Sopenharmony_ci * These are statically allocated. Trying to be clever was not worth it. 125762306a36Sopenharmony_ci * 125862306a36Sopenharmony_ci * Dynamic allocation can fail, and we can't go deep into the memory 125962306a36Sopenharmony_ci * allocator, since we're a SCSI driver, and trying too hard to allocate 126062306a36Sopenharmony_ci * memory might generate disk I/O. We also don't want to fail disk I/O 126162306a36Sopenharmony_ci * in that case because we can't get an allocation - the I/O could be 126262306a36Sopenharmony_ci * trying to swap out data to free memory. Since that is pathological, 126362306a36Sopenharmony_ci * just use a statically allocated scatter list. 126462306a36Sopenharmony_ci * 126562306a36Sopenharmony_ci */ 126662306a36Sopenharmony_cistatic int pvscsi_allocate_sg(struct pvscsi_adapter *adapter) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci struct pvscsi_ctx *ctx; 126962306a36Sopenharmony_ci int i; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci ctx = adapter->cmd_map; 127262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct pvscsi_sg_list) > SGL_SIZE); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci for (i = 0; i < adapter->req_depth; ++i, ++ctx) { 127562306a36Sopenharmony_ci ctx->sgl = (void *)__get_free_pages(GFP_KERNEL, 127662306a36Sopenharmony_ci get_order(SGL_SIZE)); 127762306a36Sopenharmony_ci ctx->sglPA = 0; 127862306a36Sopenharmony_ci BUG_ON(!IS_ALIGNED(((unsigned long)ctx->sgl), PAGE_SIZE)); 127962306a36Sopenharmony_ci if (!ctx->sgl) { 128062306a36Sopenharmony_ci for (; i >= 0; --i, --ctx) { 128162306a36Sopenharmony_ci free_pages((unsigned long)ctx->sgl, 128262306a36Sopenharmony_ci get_order(SGL_SIZE)); 128362306a36Sopenharmony_ci ctx->sgl = NULL; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci return -ENOMEM; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci return 0; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci/* 129362306a36Sopenharmony_ci * Query the device, fetch the config info and return the 129462306a36Sopenharmony_ci * maximum number of targets on the adapter. In case of 129562306a36Sopenharmony_ci * failure due to any reason return default i.e. 16. 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_cistatic u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci struct PVSCSICmdDescConfigCmd cmd; 130062306a36Sopenharmony_ci struct PVSCSIConfigPageHeader *header; 130162306a36Sopenharmony_ci struct device *dev; 130262306a36Sopenharmony_ci dma_addr_t configPagePA; 130362306a36Sopenharmony_ci void *config_page; 130462306a36Sopenharmony_ci u32 numPhys = 16; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci dev = pvscsi_dev(adapter); 130762306a36Sopenharmony_ci config_page = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, 130862306a36Sopenharmony_ci &configPagePA, GFP_KERNEL); 130962306a36Sopenharmony_ci if (!config_page) { 131062306a36Sopenharmony_ci dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n"); 131162306a36Sopenharmony_ci goto exit; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci BUG_ON(configPagePA & ~PAGE_MASK); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci /* Fetch config info from the device. */ 131662306a36Sopenharmony_ci cmd.configPageAddress = ((u64)PVSCSI_CONFIG_CONTROLLER_ADDRESS) << 32; 131762306a36Sopenharmony_ci cmd.configPageNum = PVSCSI_CONFIG_PAGE_CONTROLLER; 131862306a36Sopenharmony_ci cmd.cmpAddr = configPagePA; 131962306a36Sopenharmony_ci cmd._pad = 0; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* 132262306a36Sopenharmony_ci * Mark the completion page header with error values. If the device 132362306a36Sopenharmony_ci * completes the command successfully, it sets the status values to 132462306a36Sopenharmony_ci * indicate success. 132562306a36Sopenharmony_ci */ 132662306a36Sopenharmony_ci header = config_page; 132762306a36Sopenharmony_ci header->hostStatus = BTSTAT_INVPARAM; 132862306a36Sopenharmony_ci header->scsiStatus = SDSTAT_CHECK; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_CONFIG, &cmd, sizeof cmd); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci if (header->hostStatus == BTSTAT_SUCCESS && 133362306a36Sopenharmony_ci header->scsiStatus == SDSTAT_GOOD) { 133462306a36Sopenharmony_ci struct PVSCSIConfigPageController *config; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci config = config_page; 133762306a36Sopenharmony_ci numPhys = config->numPhys; 133862306a36Sopenharmony_ci } else 133962306a36Sopenharmony_ci dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n", 134062306a36Sopenharmony_ci header->hostStatus, header->scsiStatus); 134162306a36Sopenharmony_ci dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, config_page, 134262306a36Sopenharmony_ci configPagePA); 134362306a36Sopenharmony_ciexit: 134462306a36Sopenharmony_ci return numPhys; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci unsigned int irq_flag = PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY; 135062306a36Sopenharmony_ci struct pvscsi_adapter *adapter; 135162306a36Sopenharmony_ci struct pvscsi_adapter adapter_temp; 135262306a36Sopenharmony_ci struct Scsi_Host *host = NULL; 135362306a36Sopenharmony_ci unsigned int i; 135462306a36Sopenharmony_ci int error; 135562306a36Sopenharmony_ci u32 max_id; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci error = -ENODEV; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if (pci_enable_device(pdev)) 136062306a36Sopenharmony_ci return error; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { 136362306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n"); 136462306a36Sopenharmony_ci } else if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { 136562306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n"); 136662306a36Sopenharmony_ci } else { 136762306a36Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n"); 136862306a36Sopenharmony_ci goto out_disable_device; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* 137262306a36Sopenharmony_ci * Let's use a temp pvscsi_adapter struct until we find the number of 137362306a36Sopenharmony_ci * targets on the adapter, after that we will switch to the real 137462306a36Sopenharmony_ci * allocated struct. 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ci adapter = &adapter_temp; 137762306a36Sopenharmony_ci memset(adapter, 0, sizeof(*adapter)); 137862306a36Sopenharmony_ci adapter->dev = pdev; 137962306a36Sopenharmony_ci adapter->rev = pdev->revision; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (pci_request_regions(pdev, "vmw_pvscsi")) { 138262306a36Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n"); 138362306a36Sopenharmony_ci goto out_disable_device; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 138762306a36Sopenharmony_ci if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) 138862306a36Sopenharmony_ci continue; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (pci_resource_len(pdev, i) < PVSCSI_MEM_SPACE_SIZE) 139162306a36Sopenharmony_ci continue; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci break; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (i == DEVICE_COUNT_RESOURCE) { 139762306a36Sopenharmony_ci printk(KERN_ERR 139862306a36Sopenharmony_ci "vmw_pvscsi: adapter has no suitable MMIO region\n"); 139962306a36Sopenharmony_ci goto out_release_resources_and_disable; 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (!adapter->mmioBase) { 140562306a36Sopenharmony_ci printk(KERN_ERR 140662306a36Sopenharmony_ci "vmw_pvscsi: can't iomap for BAR %d memsize %lu\n", 140762306a36Sopenharmony_ci i, PVSCSI_MEM_SPACE_SIZE); 140862306a36Sopenharmony_ci goto out_release_resources_and_disable; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci pci_set_master(pdev); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci /* 141462306a36Sopenharmony_ci * Ask the device for max number of targets before deciding the 141562306a36Sopenharmony_ci * default pvscsi_ring_pages value. 141662306a36Sopenharmony_ci */ 141762306a36Sopenharmony_ci max_id = pvscsi_get_max_targets(adapter); 141862306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: max_id: %u\n", max_id); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (pvscsi_ring_pages == 0) 142162306a36Sopenharmony_ci /* 142262306a36Sopenharmony_ci * Set the right default value. Up to 16 it is 8, above it is 142362306a36Sopenharmony_ci * max. 142462306a36Sopenharmony_ci */ 142562306a36Sopenharmony_ci pvscsi_ring_pages = (max_id > 16) ? 142662306a36Sopenharmony_ci PVSCSI_SETUP_RINGS_MAX_NUM_PAGES : 142762306a36Sopenharmony_ci PVSCSI_DEFAULT_NUM_PAGES_PER_RING; 142862306a36Sopenharmony_ci printk(KERN_INFO 142962306a36Sopenharmony_ci "vmw_pvscsi: setting ring_pages to %d\n", 143062306a36Sopenharmony_ci pvscsi_ring_pages); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci pvscsi_template.can_queue = 143362306a36Sopenharmony_ci min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) * 143462306a36Sopenharmony_ci PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; 143562306a36Sopenharmony_ci pvscsi_template.cmd_per_lun = 143662306a36Sopenharmony_ci min(pvscsi_template.can_queue, pvscsi_cmd_per_lun); 143762306a36Sopenharmony_ci host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter)); 143862306a36Sopenharmony_ci if (!host) { 143962306a36Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n"); 144062306a36Sopenharmony_ci goto out_release_resources_and_disable; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci /* 144462306a36Sopenharmony_ci * Let's use the real pvscsi_adapter struct here onwards. 144562306a36Sopenharmony_ci */ 144662306a36Sopenharmony_ci adapter = shost_priv(host); 144762306a36Sopenharmony_ci memset(adapter, 0, sizeof(*adapter)); 144862306a36Sopenharmony_ci adapter->dev = pdev; 144962306a36Sopenharmony_ci adapter->host = host; 145062306a36Sopenharmony_ci /* 145162306a36Sopenharmony_ci * Copy back what we already have to the allocated adapter struct. 145262306a36Sopenharmony_ci */ 145362306a36Sopenharmony_ci adapter->rev = adapter_temp.rev; 145462306a36Sopenharmony_ci adapter->mmioBase = adapter_temp.mmioBase; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci spin_lock_init(&adapter->hw_lock); 145762306a36Sopenharmony_ci host->max_channel = 0; 145862306a36Sopenharmony_ci host->max_lun = 1; 145962306a36Sopenharmony_ci host->max_cmd_len = 16; 146062306a36Sopenharmony_ci host->max_id = max_id; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci pci_set_drvdata(pdev, host); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci ll_adapter_reset(adapter); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci adapter->use_msg = pvscsi_setup_msg_workqueue(adapter); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci error = pvscsi_allocate_rings(adapter); 146962306a36Sopenharmony_ci if (error) { 147062306a36Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: unable to allocate ring memory\n"); 147162306a36Sopenharmony_ci goto out_release_resources; 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci /* 147562306a36Sopenharmony_ci * From this point on we should reset the adapter if anything goes 147662306a36Sopenharmony_ci * wrong. 147762306a36Sopenharmony_ci */ 147862306a36Sopenharmony_ci pvscsi_setup_all_rings(adapter); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci adapter->cmd_map = kcalloc(adapter->req_depth, 148162306a36Sopenharmony_ci sizeof(struct pvscsi_ctx), GFP_KERNEL); 148262306a36Sopenharmony_ci if (!adapter->cmd_map) { 148362306a36Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: failed to allocate memory.\n"); 148462306a36Sopenharmony_ci error = -ENOMEM; 148562306a36Sopenharmony_ci goto out_reset_adapter; 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci INIT_LIST_HEAD(&adapter->cmd_pool); 148962306a36Sopenharmony_ci for (i = 0; i < adapter->req_depth; i++) { 149062306a36Sopenharmony_ci struct pvscsi_ctx *ctx = adapter->cmd_map + i; 149162306a36Sopenharmony_ci list_add(&ctx->list, &adapter->cmd_pool); 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci error = pvscsi_allocate_sg(adapter); 149562306a36Sopenharmony_ci if (error) { 149662306a36Sopenharmony_ci printk(KERN_ERR "vmw_pvscsi: unable to allocate s/g table\n"); 149762306a36Sopenharmony_ci goto out_reset_adapter; 149862306a36Sopenharmony_ci } 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ci if (pvscsi_disable_msix) 150162306a36Sopenharmony_ci irq_flag &= ~PCI_IRQ_MSIX; 150262306a36Sopenharmony_ci if (pvscsi_disable_msi) 150362306a36Sopenharmony_ci irq_flag &= ~PCI_IRQ_MSI; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci error = pci_alloc_irq_vectors(adapter->dev, 1, 1, irq_flag); 150662306a36Sopenharmony_ci if (error < 0) 150762306a36Sopenharmony_ci goto out_reset_adapter; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true); 151062306a36Sopenharmony_ci printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n", 151162306a36Sopenharmony_ci adapter->use_req_threshold ? "en" : "dis"); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if (adapter->dev->msix_enabled || adapter->dev->msi_enabled) { 151462306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using MSI%s\n", 151562306a36Sopenharmony_ci adapter->dev->msix_enabled ? "-X" : ""); 151662306a36Sopenharmony_ci error = request_irq(pci_irq_vector(pdev, 0), pvscsi_isr, 151762306a36Sopenharmony_ci 0, "vmw_pvscsi", adapter); 151862306a36Sopenharmony_ci } else { 151962306a36Sopenharmony_ci printk(KERN_INFO "vmw_pvscsi: using INTx\n"); 152062306a36Sopenharmony_ci error = request_irq(pci_irq_vector(pdev, 0), pvscsi_shared_isr, 152162306a36Sopenharmony_ci IRQF_SHARED, "vmw_pvscsi", adapter); 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (error) { 152562306a36Sopenharmony_ci printk(KERN_ERR 152662306a36Sopenharmony_ci "vmw_pvscsi: unable to request IRQ: %d\n", error); 152762306a36Sopenharmony_ci goto out_reset_adapter; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci error = scsi_add_host(host, &pdev->dev); 153162306a36Sopenharmony_ci if (error) { 153262306a36Sopenharmony_ci printk(KERN_ERR 153362306a36Sopenharmony_ci "vmw_pvscsi: scsi_add_host failed: %d\n", error); 153462306a36Sopenharmony_ci goto out_reset_adapter; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci dev_info(&pdev->dev, "VMware PVSCSI rev %d host #%u\n", 153862306a36Sopenharmony_ci adapter->rev, host->host_no); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci pvscsi_unmask_intr(adapter); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci scsi_scan_host(host); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci return 0; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ciout_reset_adapter: 154762306a36Sopenharmony_ci ll_adapter_reset(adapter); 154862306a36Sopenharmony_ciout_release_resources: 154962306a36Sopenharmony_ci pvscsi_shutdown_intr(adapter); 155062306a36Sopenharmony_ci pvscsi_release_resources(adapter); 155162306a36Sopenharmony_ci scsi_host_put(host); 155262306a36Sopenharmony_ciout_disable_device: 155362306a36Sopenharmony_ci pci_disable_device(pdev); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci return error; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ciout_release_resources_and_disable: 155862306a36Sopenharmony_ci pvscsi_shutdown_intr(adapter); 155962306a36Sopenharmony_ci pvscsi_release_resources(adapter); 156062306a36Sopenharmony_ci goto out_disable_device; 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic void __pvscsi_shutdown(struct pvscsi_adapter *adapter) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci pvscsi_mask_intr(adapter); 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (adapter->workqueue) 156862306a36Sopenharmony_ci flush_workqueue(adapter->workqueue); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci pvscsi_shutdown_intr(adapter); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci pvscsi_process_request_ring(adapter); 157362306a36Sopenharmony_ci pvscsi_process_completion_ring(adapter); 157462306a36Sopenharmony_ci ll_adapter_reset(adapter); 157562306a36Sopenharmony_ci} 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_cistatic void pvscsi_shutdown(struct pci_dev *dev) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci struct Scsi_Host *host = pci_get_drvdata(dev); 158062306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci __pvscsi_shutdown(adapter); 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_cistatic void pvscsi_remove(struct pci_dev *pdev) 158662306a36Sopenharmony_ci{ 158762306a36Sopenharmony_ci struct Scsi_Host *host = pci_get_drvdata(pdev); 158862306a36Sopenharmony_ci struct pvscsi_adapter *adapter = shost_priv(host); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci scsi_remove_host(host); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci __pvscsi_shutdown(adapter); 159362306a36Sopenharmony_ci pvscsi_release_resources(adapter); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci scsi_host_put(host); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci pci_disable_device(pdev); 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic struct pci_driver pvscsi_pci_driver = { 160162306a36Sopenharmony_ci .name = "vmw_pvscsi", 160262306a36Sopenharmony_ci .id_table = pvscsi_pci_tbl, 160362306a36Sopenharmony_ci .probe = pvscsi_probe, 160462306a36Sopenharmony_ci .remove = pvscsi_remove, 160562306a36Sopenharmony_ci .shutdown = pvscsi_shutdown, 160662306a36Sopenharmony_ci}; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic int __init pvscsi_init(void) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci pr_info("%s - version %s\n", 161162306a36Sopenharmony_ci PVSCSI_LINUX_DRIVER_DESC, PVSCSI_DRIVER_VERSION_STRING); 161262306a36Sopenharmony_ci return pci_register_driver(&pvscsi_pci_driver); 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_cistatic void __exit pvscsi_exit(void) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci pci_unregister_driver(&pvscsi_pci_driver); 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cimodule_init(pvscsi_init); 162162306a36Sopenharmony_cimodule_exit(pvscsi_exit); 1622