--- zzzz-none-000/linux-3.10.107/drivers/scsi/vmw_pvscsi.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/scsi/vmw_pvscsi.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,7 +1,7 @@ /* * Linux driver for VMware's para-virtualized SCSI HBA. * - * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. + * Copyright (C) 2008-2014, VMware, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -32,6 +32,7 @@ #include #include #include +#include #include "vmw_pvscsi.h" @@ -44,7 +45,7 @@ #define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8 #define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1 -#define PVSCSI_DEFAULT_QUEUE_DEPTH 64 +#define PVSCSI_DEFAULT_QUEUE_DEPTH 254 #define SGL_SIZE PAGE_SIZE struct pvscsi_sg_list { @@ -62,6 +63,7 @@ dma_addr_t dataPA; dma_addr_t sensePA; dma_addr_t sglPA; + struct completion *abort_cmp; }; struct pvscsi_adapter { @@ -71,6 +73,7 @@ bool use_msi; bool use_msix; bool use_msg; + bool use_req_threshold; spinlock_t hw_lock; @@ -102,18 +105,22 @@ /* Command line parameters */ -static int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING; +static int pvscsi_ring_pages; static int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING; static int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH; static bool pvscsi_disable_msi; static bool pvscsi_disable_msix; static bool pvscsi_use_msg = true; +static bool pvscsi_use_req_threshold = true; #define PVSCSI_RW (S_IRUSR | S_IWUSR) module_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW); MODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default=" - __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) ")"); + __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) + "[up to 16 targets]," + __stringify(PVSCSI_SETUP_RINGS_MAX_NUM_PAGES) + "[for 16+ targets])"); module_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW); MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default=" @@ -121,7 +128,7 @@ module_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW); MODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default=" - __stringify(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")"); + __stringify(PVSCSI_DEFAULT_QUEUE_DEPTH) ")"); module_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW); MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)"); @@ -132,6 +139,10 @@ module_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW); MODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)"); +module_param_named(use_req_threshold, pvscsi_use_req_threshold, + bool, PVSCSI_RW); +MODULE_PARM_DESC(use_req_threshold, "Use driver-based request coalescing if configured - (default=1)"); + static const struct pci_device_id pvscsi_pci_tbl[] = { { PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) }, { 0 } @@ -177,6 +188,7 @@ struct pvscsi_ctx *ctx) { ctx->cmd = NULL; + ctx->abort_cmp = NULL; list_add(&ctx->list, &adapter->cmd_pool); } @@ -280,10 +292,15 @@ static void pvscsi_kick_io(const struct pvscsi_adapter *adapter, unsigned char op) { - if (scsi_is_rw(op)) - pvscsi_kick_rw_io(adapter); - else + if (scsi_is_rw(op)) { + struct PVSCSIRingsState *s = adapter->rings_state; + + if (!adapter->use_req_threshold || + s->reqProdIdx - s->reqConsIdx >= s->reqCallThreshold) + pvscsi_kick_rw_io(adapter); + } else { pvscsi_process_request_ring(adapter); + } } static void ll_adapter_reset(const struct pvscsi_adapter *adapter) @@ -487,6 +504,13 @@ } } +static int pvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + if (!sdev->tagged_supported) + qdepth = 1; + return scsi_change_queue_depth(sdev, qdepth); +} + /* * Pull a completion descriptor off and pass the completion back * to the SCSI mid layer. @@ -496,15 +520,27 @@ { struct pvscsi_ctx *ctx; struct scsi_cmnd *cmd; + struct completion *abort_cmp; u32 btstat = e->hostStatus; u32 sdstat = e->scsiStatus; ctx = pvscsi_get_context(adapter, e->context); cmd = ctx->cmd; + abort_cmp = ctx->abort_cmp; pvscsi_unmap_buffers(adapter, ctx); pvscsi_release_context(adapter, ctx); - cmd->result = 0; + if (abort_cmp) { + /* + * The command was requested to be aborted. Just signal that + * the request completed and swallow the actual cmd completion + * here. The abort handler will post a completion for this + * command indicating that it got successfully aborted. + */ + complete(abort_cmp); + return; + } + cmd->result = 0; if (sdstat != SAM_STAT_GOOD && (btstat == BTSTAT_SUCCESS || btstat == BTSTAT_LINKED_COMMAND_COMPLETED || @@ -665,10 +701,6 @@ memcpy(e->cdb, cmd->cmnd, e->cdbLen); e->tag = SIMPLE_QUEUE_TAG; - if (sdev->tagged_supported && - (cmd->tag == HEAD_OF_QUEUE_TAG || - cmd->tag == ORDERED_QUEUE_TAG)) - e->tag = cmd->tag; if (cmd->sc_data_direction == DMA_FROM_DEVICE) e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST; @@ -726,6 +758,8 @@ struct pvscsi_adapter *adapter = shost_priv(cmd->device->host); struct pvscsi_ctx *ctx; unsigned long flags; + int result = SUCCESS; + DECLARE_COMPLETION_ONSTACK(abort_cmp); scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n", adapter->host->host_no, cmd); @@ -748,13 +782,40 @@ goto out; } + /* + * Mark that the command has been requested to be aborted and issue + * the abort. + */ + ctx->abort_cmp = &abort_cmp; + pvscsi_abort_cmd(adapter, ctx); + spin_unlock_irqrestore(&adapter->hw_lock, flags); + /* Wait for 2 secs for the completion. */ + wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000)); + spin_lock_irqsave(&adapter->hw_lock, flags); - pvscsi_process_completion_ring(adapter); + if (!completion_done(&abort_cmp)) { + /* + * Failed to abort the command, unmark the fact that it + * was requested to be aborted. + */ + ctx->abort_cmp = NULL; + result = FAILED; + scmd_printk(KERN_DEBUG, cmd, + "Failed to get completion for aborted cmd %p\n", + cmd); + goto out; + } + + /* + * Successfully aborted the command. + */ + cmd->result = (DID_ABORT << 16); + cmd->scsi_done(cmd); out: spin_unlock_irqrestore(&adapter->hw_lock, flags); - return SUCCESS; + return result; } /* @@ -911,6 +972,7 @@ .dma_boundary = UINT_MAX, .max_sectors = 0xffff, .use_clustering = ENABLE_CLUSTERING, + .change_queue_depth = pvscsi_change_queue_depth, .eh_abort_handler = pvscsi_abort, .eh_device_reset_handler = pvscsi_device_reset, .eh_bus_reset_handler = pvscsi_bus_reset, @@ -1034,6 +1096,34 @@ return 1; } +static bool pvscsi_setup_req_threshold(struct pvscsi_adapter *adapter, + bool enable) +{ + u32 val; + + if (!pvscsi_use_req_threshold) + return false; + + pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, + PVSCSI_CMD_SETUP_REQCALLTHRESHOLD); + val = pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS); + if (val == -1) { + printk(KERN_INFO "vmw_pvscsi: device does not support req_threshold\n"); + return false; + } else { + struct PVSCSICmdDescSetupReqCall cmd_msg = { 0 }; + cmd_msg.enable = enable; + printk(KERN_INFO + "vmw_pvscsi: %sabling reqCallThreshold\n", + enable ? "en" : "dis"); + pvscsi_write_cmd_desc(adapter, + PVSCSI_CMD_SETUP_REQCALLTHRESHOLD, + &cmd_msg, sizeof(cmd_msg)); + return pvscsi_reg_read(adapter, + PVSCSI_REG_OFFSET_COMMAND_STATUS) != 0; + } +} + static irqreturn_t pvscsi_isr(int irq, void *devp) { struct pvscsi_adapter *adapter = devp; @@ -1078,7 +1168,7 @@ struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION }; int ret; - ret = pci_enable_msix(adapter->dev, &entry, 1); + ret = pci_enable_msix_exact(adapter->dev, &entry, 1); if (ret) return ret; @@ -1236,11 +1326,12 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pvscsi_adapter *adapter; - struct Scsi_Host *host; - struct device *dev; + struct pvscsi_adapter adapter_temp; + struct Scsi_Host *host = NULL; unsigned int i; unsigned long flags = 0; int error; + u32 max_id; error = -ENODEV; @@ -1258,34 +1349,19 @@ goto out_disable_device; } - pvscsi_template.can_queue = - min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) * - PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - pvscsi_template.cmd_per_lun = - min(pvscsi_template.can_queue, pvscsi_cmd_per_lun); - host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter)); - if (!host) { - printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n"); - goto out_disable_device; - } - - adapter = shost_priv(host); + /* + * Let's use a temp pvscsi_adapter struct until we find the number of + * targets on the adapter, after that we will switch to the real + * allocated struct. + */ + adapter = &adapter_temp; memset(adapter, 0, sizeof(*adapter)); adapter->dev = pdev; - adapter->host = host; - - spin_lock_init(&adapter->hw_lock); - - host->max_channel = 0; - host->max_id = 16; - host->max_lun = 1; - host->max_cmd_len = 16; - adapter->rev = pdev->revision; if (pci_request_regions(pdev, "vmw_pvscsi")) { printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n"); - goto out_free_host; + goto out_disable_device; } for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { @@ -1301,7 +1377,7 @@ if (i == DEVICE_COUNT_RESOURCE) { printk(KERN_ERR "vmw_pvscsi: adapter has no suitable MMIO region\n"); - goto out_release_resources; + goto out_release_resources_and_disable; } adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE); @@ -1310,10 +1386,60 @@ printk(KERN_ERR "vmw_pvscsi: can't iomap for BAR %d memsize %lu\n", i, PVSCSI_MEM_SPACE_SIZE); - goto out_release_resources; + goto out_release_resources_and_disable; } pci_set_master(pdev); + + /* + * Ask the device for max number of targets before deciding the + * default pvscsi_ring_pages value. + */ + max_id = pvscsi_get_max_targets(adapter); + printk(KERN_INFO "vmw_pvscsi: max_id: %u\n", max_id); + + if (pvscsi_ring_pages == 0) + /* + * Set the right default value. Up to 16 it is 8, above it is + * max. + */ + pvscsi_ring_pages = (max_id > 16) ? + PVSCSI_SETUP_RINGS_MAX_NUM_PAGES : + PVSCSI_DEFAULT_NUM_PAGES_PER_RING; + printk(KERN_INFO + "vmw_pvscsi: setting ring_pages to %d\n", + pvscsi_ring_pages); + + pvscsi_template.can_queue = + min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) * + PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; + pvscsi_template.cmd_per_lun = + min(pvscsi_template.can_queue, pvscsi_cmd_per_lun); + host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter)); + if (!host) { + printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n"); + goto out_release_resources_and_disable; + } + + /* + * Let's use the real pvscsi_adapter struct here onwards. + */ + adapter = shost_priv(host); + memset(adapter, 0, sizeof(*adapter)); + adapter->dev = pdev; + adapter->host = host; + /* + * Copy back what we already have to the allocated adapter struct. + */ + adapter->rev = adapter_temp.rev; + adapter->mmioBase = adapter_temp.mmioBase; + + spin_lock_init(&adapter->hw_lock); + host->max_channel = 0; + host->max_lun = 1; + host->max_cmd_len = 16; + host->max_id = max_id; + pci_set_drvdata(pdev, host); ll_adapter_reset(adapter); @@ -1327,13 +1453,6 @@ } /* - * Ask the device for max number of targets. - */ - host->max_id = pvscsi_get_max_targets(adapter); - dev = pvscsi_dev(adapter); - dev_info(dev, "vmw_pvscsi: host->max_id: %u\n", host->max_id); - - /* * From this point on we should reset the adapter if anything goes * wrong. */ @@ -1373,6 +1492,10 @@ flags = IRQF_SHARED; } + adapter->use_req_threshold = pvscsi_setup_req_threshold(adapter, true); + printk(KERN_DEBUG "vmw_pvscsi: driver-based request coalescing %sabled\n", + adapter->use_req_threshold ? "en" : "dis"); + error = request_irq(adapter->irq, pvscsi_isr, flags, "vmw_pvscsi", adapter); if (error) { @@ -1402,13 +1525,15 @@ ll_adapter_reset(adapter); out_release_resources: pvscsi_release_resources(adapter); -out_free_host: scsi_host_put(host); out_disable_device: - pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); return error; + +out_release_resources_and_disable: + pvscsi_release_resources(adapter); + goto out_disable_device; } static void __pvscsi_shutdown(struct pvscsi_adapter *adapter) @@ -1445,7 +1570,6 @@ scsi_host_put(host); - pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); }