diff options
Diffstat (limited to 'drivers/scsi/vmw_pvscsi.c')
| -rw-r--r-- | drivers/scsi/vmw_pvscsi.c | 153 |
1 files changed, 86 insertions, 67 deletions
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index c374e3b5c678..32242d86cf5b 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -17,8 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * - * Maintained by: Jim Gill <jgill@vmware.com> - * */ #include <linux/kernel.h> @@ -335,7 +333,7 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx, BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT); sge = &ctx->sgl->sge[0]; - for (i = 0; i < count; i++, sg++) { + for (i = 0; i < count; i++, sg = sg_next(sg)) { sge[i].addr = sg_dma_address(sg); sge[i].length = sg_dma_len(sg); sge[i].flags = 0; @@ -365,16 +363,16 @@ static int pvscsi_map_buffers(struct pvscsi_adapter *adapter, int segs = scsi_dma_map(cmd); if (segs == -ENOMEM) { - scmd_printk(KERN_ERR, cmd, + scmd_printk(KERN_DEBUG, cmd, "vmw_pvscsi: Failed to map cmd sglist for DMA.\n"); return -ENOMEM; } else if (segs > 1) { pvscsi_create_sg(ctx, sg, segs); e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; - ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl, - SGL_SIZE, PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(adapter->dev, ctx->sglPA)) { + ctx->sglPA = dma_map_single(&adapter->dev->dev, + ctx->sgl, SGL_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(&adapter->dev->dev, ctx->sglPA)) { scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: Failed to map ctx sglist for DMA.\n"); scsi_dma_unmap(cmd); @@ -389,10 +387,10 @@ static int pvscsi_map_buffers(struct pvscsi_adapter *adapter, * In case there is no S/G list, scsi_sglist points * directly to the buffer. */ - ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen, + ctx->dataPA = dma_map_single(&adapter->dev->dev, sg, bufflen, cmd->sc_data_direction); - if (pci_dma_mapping_error(adapter->dev, ctx->dataPA)) { - scmd_printk(KERN_ERR, cmd, + if (dma_mapping_error(&adapter->dev->dev, ctx->dataPA)) { + scmd_printk(KERN_DEBUG, cmd, "vmw_pvscsi: Failed to map direct data buffer for DMA.\n"); return -ENOMEM; } @@ -402,6 +400,17 @@ static int pvscsi_map_buffers(struct pvscsi_adapter *adapter, return 0; } +/* + * The device incorrectly doesn't clear the first byte of the sense + * buffer in some cases. We have to do it ourselves. + * Otherwise we run into trouble when SWIOTLB is forced. + */ +static void pvscsi_patch_sense(struct scsi_cmnd *cmd) +{ + if (cmd->sense_buffer) + cmd->sense_buffer[0] = 0; +} + static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx) { @@ -417,23 +426,23 @@ static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, if (count != 0) { scsi_dma_unmap(cmd); if (ctx->sglPA) { - pci_unmap_single(adapter->dev, ctx->sglPA, - SGL_SIZE, PCI_DMA_TODEVICE); + dma_unmap_single(&adapter->dev->dev, ctx->sglPA, + SGL_SIZE, DMA_TO_DEVICE); ctx->sglPA = 0; } } else - pci_unmap_single(adapter->dev, ctx->dataPA, bufflen, - cmd->sc_data_direction); + dma_unmap_single(&adapter->dev->dev, ctx->dataPA, + bufflen, cmd->sc_data_direction); } if (cmd->sense_buffer) - pci_unmap_single(adapter->dev, ctx->sensePA, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&adapter->dev->dev, ctx->sensePA, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); } static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) { - adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE, - &adapter->ringStatePA); + adapter->rings_state = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, + &adapter->ringStatePA, GFP_KERNEL); if (!adapter->rings_state) return -ENOMEM; @@ -441,17 +450,17 @@ static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) pvscsi_ring_pages); adapter->req_depth = adapter->req_pages * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - adapter->req_ring = pci_alloc_consistent(adapter->dev, - adapter->req_pages * PAGE_SIZE, - &adapter->reqRingPA); + adapter->req_ring = dma_alloc_coherent(&adapter->dev->dev, + adapter->req_pages * PAGE_SIZE, &adapter->reqRingPA, + GFP_KERNEL); if (!adapter->req_ring) return -ENOMEM; adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING, pvscsi_ring_pages); - adapter->cmp_ring = pci_alloc_consistent(adapter->dev, - adapter->cmp_pages * PAGE_SIZE, - &adapter->cmpRingPA); + adapter->cmp_ring = dma_alloc_coherent(&adapter->dev->dev, + adapter->cmp_pages * PAGE_SIZE, &adapter->cmpRingPA, + GFP_KERNEL); if (!adapter->cmp_ring) return -ENOMEM; @@ -464,9 +473,9 @@ static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter) adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING, pvscsi_msg_ring_pages); - adapter->msg_ring = pci_alloc_consistent(adapter->dev, - adapter->msg_pages * PAGE_SIZE, - &adapter->msgRingPA); + adapter->msg_ring = dma_alloc_coherent(&adapter->dev->dev, + adapter->msg_pages * PAGE_SIZE, &adapter->msgRingPA, + GFP_KERNEL); if (!adapter->msg_ring) return -ENOMEM; BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE)); @@ -544,6 +553,8 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, cmd = ctx->cmd; abort_cmp = ctx->abort_cmp; pvscsi_unmap_buffers(adapter, ctx); + if (sdstat != SAM_STAT_CHECK_CONDITION) + pvscsi_patch_sense(cmd); pvscsi_release_context(adapter, ctx); if (abort_cmp) { /* @@ -561,15 +572,26 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, (btstat == BTSTAT_SUCCESS || btstat == BTSTAT_LINKED_COMMAND_COMPLETED || btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { - cmd->result = (DID_OK << 16) | sdstat; - if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer) - cmd->result |= (DRIVER_SENSE << 24); + if (sdstat == SAM_STAT_COMMAND_TERMINATED) { + cmd->result = (DID_RESET << 16); + } else { + cmd->result = (DID_OK << 16) | sdstat; + } } else switch (btstat) { case BTSTAT_SUCCESS: case BTSTAT_LINKED_COMMAND_COMPLETED: case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: - /* If everything went fine, let's move on.. */ + /* + * Commands like INQUIRY may transfer less data than + * requested by the initiator via bufflen. Set residual + * count to make upper layer aware of the actual amount + * of data returned. There are cases when controller + * returns zero dataLen with non zero data - do not set + * residual count in that case. + */ + if (e->dataLen && (e->dataLen < scsi_bufflen(cmd))) + scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen); cmd->result = (DID_OK << 16); break; @@ -588,9 +610,6 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, case BTSTAT_LUNMISMATCH: case BTSTAT_TAGREJECT: case BTSTAT_BADMSG: - cmd->result = (DRIVER_INVALID << 24); - /* fall through */ - case BTSTAT_HAHARDWARE: case BTSTAT_INVPHASE: case BTSTAT_HATIMEOUT: @@ -609,7 +628,7 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, break; case BTSTAT_ABORTQUEUE: - cmd->result = (DID_ABORT << 16); + cmd->result = (DID_BUS_BUSY << 16); break; case BTSTAT_SCSIPARITY: @@ -627,7 +646,7 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n", cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat); - cmd->scsi_done(cmd); + scsi_done(cmd); } /* @@ -703,11 +722,11 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, e->lun[1] = sdev->lun; if (cmd->sense_buffer) { - ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(adapter->dev, ctx->sensePA)) { - scmd_printk(KERN_ERR, cmd, + ctx->sensePA = dma_map_single(&adapter->dev->dev, + cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(&adapter->dev->dev, ctx->sensePA)) { + scmd_printk(KERN_DEBUG, cmd, "vmw_pvscsi: Failed to map sense buffer for DMA.\n"); ctx->sensePA = 0; return -ENOMEM; @@ -735,9 +754,9 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, if (pvscsi_map_buffers(adapter, ctx, cmd, e) != 0) { if (cmd->sense_buffer) { - pci_unmap_single(adapter->dev, ctx->sensePA, + dma_unmap_single(&adapter->dev->dev, ctx->sensePA, SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); ctx->sensePA = 0; } return -ENOMEM; @@ -752,12 +771,13 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, return 0; } -static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +static int pvscsi_queue_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct pvscsi_adapter *adapter = shost_priv(host); struct pvscsi_ctx *ctx; unsigned long flags; + unsigned char op; spin_lock_irqsave(&adapter->hw_lock, flags); @@ -769,14 +789,14 @@ static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd return SCSI_MLQUEUE_HOST_BUSY; } - cmd->scsi_done = done; + op = cmd->cmnd[0]; dev_dbg(&cmd->device->sdev_gendev, - "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]); + "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, op); spin_unlock_irqrestore(&adapter->hw_lock, flags); - pvscsi_kick_io(adapter, cmd->cmnd[0]); + pvscsi_kick_io(adapter, op); return 0; } @@ -842,7 +862,7 @@ static int pvscsi_abort(struct scsi_cmnd *cmd) * Successfully aborted the command. */ cmd->result = (DID_ABORT << 16); - cmd->scsi_done(cmd); + scsi_done(cmd); out: spin_unlock_irqrestore(&adapter->hw_lock, flags); @@ -866,9 +886,10 @@ static void pvscsi_reset_all(struct pvscsi_adapter *adapter) scmd_printk(KERN_ERR, cmd, "Forced reset on cmd %p\n", cmd); pvscsi_unmap_buffers(adapter, ctx); + pvscsi_patch_sense(cmd); pvscsi_release_context(adapter, ctx); cmd->result = (DID_RESET << 16); - cmd->scsi_done(cmd); + scsi_done(cmd); } } } @@ -887,7 +908,7 @@ static int pvscsi_host_reset(struct scsi_cmnd *cmd) use_msg = adapter->use_msg; if (use_msg) { - adapter->use_msg = 0; + adapter->use_msg = false; spin_unlock_irqrestore(&adapter->hw_lock, flags); /* @@ -1002,7 +1023,6 @@ static struct scsi_host_template pvscsi_template = { .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT, .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, @@ -1117,7 +1137,8 @@ static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter) snprintf(name, sizeof(name), "vmw_pvscsi_wq_%u", adapter->host->host_no); - adapter->workqueue = create_singlethread_workqueue(name); + adapter->workqueue = + alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name); if (!adapter->workqueue) { printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n"); return 0; @@ -1197,8 +1218,6 @@ static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter) static void pvscsi_release_resources(struct pvscsi_adapter *adapter) { - pvscsi_shutdown_intr(adapter); - if (adapter->workqueue) destroy_workqueue(adapter->workqueue); @@ -1213,21 +1232,21 @@ static void pvscsi_release_resources(struct pvscsi_adapter *adapter) } if (adapter->rings_state) - pci_free_consistent(adapter->dev, PAGE_SIZE, + dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, adapter->rings_state, adapter->ringStatePA); if (adapter->req_ring) - pci_free_consistent(adapter->dev, + dma_free_coherent(&adapter->dev->dev, adapter->req_pages * PAGE_SIZE, adapter->req_ring, adapter->reqRingPA); if (adapter->cmp_ring) - pci_free_consistent(adapter->dev, + dma_free_coherent(&adapter->dev->dev, adapter->cmp_pages * PAGE_SIZE, adapter->cmp_ring, adapter->cmpRingPA); if (adapter->msg_ring) - pci_free_consistent(adapter->dev, + dma_free_coherent(&adapter->dev->dev, adapter->msg_pages * PAGE_SIZE, adapter->msg_ring, adapter->msgRingPA); } @@ -1286,8 +1305,8 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) u32 numPhys = 16; dev = pvscsi_dev(adapter); - config_page = pci_alloc_consistent(adapter->dev, PAGE_SIZE, - &configPagePA); + config_page = dma_alloc_coherent(&adapter->dev->dev, PAGE_SIZE, + &configPagePA, GFP_KERNEL); if (!config_page) { dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n"); goto exit; @@ -1306,7 +1325,6 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) * indicate success. */ header = config_page; - memset(header, 0, sizeof *header); header->hostStatus = BTSTAT_INVPARAM; header->scsiStatus = SDSTAT_CHECK; @@ -1321,14 +1339,15 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) } else dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n", header->hostStatus, header->scsiStatus); - pci_free_consistent(adapter->dev, PAGE_SIZE, config_page, configPagePA); + dma_free_coherent(&adapter->dev->dev, PAGE_SIZE, config_page, + configPagePA); exit: return numPhys; } static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - unsigned int irq_flag = PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY; + unsigned int irq_flag = PCI_IRQ_ALL_TYPES; struct pvscsi_adapter *adapter; struct pvscsi_adapter adapter_temp; struct Scsi_Host *host = NULL; @@ -1341,11 +1360,9 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_enable_device(pdev)) return error; - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { + if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) { printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n"); - } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) { + } else if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n"); } else { printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n"); @@ -1530,6 +1547,7 @@ static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id) out_reset_adapter: ll_adapter_reset(adapter); out_release_resources: + pvscsi_shutdown_intr(adapter); pvscsi_release_resources(adapter); scsi_host_put(host); out_disable_device: @@ -1538,6 +1556,7 @@ out_disable_device: return error; out_release_resources_and_disable: + pvscsi_shutdown_intr(adapter); pvscsi_release_resources(adapter); goto out_disable_device; } |
