diff options
author | Arvind Kumar <arvindkumar@vmware.com> | 2014-03-08 12:51:12 -0800 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2014-03-19 15:04:45 -0700 |
commit | a2713cceb3a8efef8b86bec06f10689c95ddbc8c (patch) | |
tree | 66ae4312f340d057675091a9c240fe5bb09ce470 /drivers/scsi/vmw_pvscsi.c | |
parent | 4909cc2b89715c2dfd4c466a37cc08b2b3890fed (diff) |
[SCSI] vmw_pvscsi: Fix pvscsi_abort() function.
This change ensures that pvscsi_abort() function returns SUCCESS
only when the command in question was actually completed, otherwise
returns FAILURE. The code before change, was causing a bug where
driver tries to complete a command to the mid-layer while the mid-layer
has already requested the driver to abort that command, in response
to which the driver has responded with SUCCESS causing mid-layer
to free the command struct.
Signed-off-by: Arvind Kumar <arvindkumar@vmware.com>
Tested-by: Ewan Milne <emilne@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/vmw_pvscsi.c')
-rw-r--r-- | drivers/scsi/vmw_pvscsi.c | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index b9755ec0e81..7c5abd7f6c6 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -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 @@ -62,6 +62,7 @@ struct pvscsi_ctx { dma_addr_t dataPA; dma_addr_t sensePA; dma_addr_t sglPA; + struct completion *abort_cmp; }; struct pvscsi_adapter { @@ -177,6 +178,7 @@ static void pvscsi_release_context(struct pvscsi_adapter *adapter, struct pvscsi_ctx *ctx) { ctx->cmd = NULL; + ctx->abort_cmp = NULL; list_add(&ctx->list, &adapter->cmd_pool); } @@ -496,15 +498,27 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, { 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 || @@ -726,6 +740,8 @@ static int pvscsi_abort(struct scsi_cmnd *cmd) 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 +764,40 @@ static int pvscsi_abort(struct scsi_cmnd *cmd) 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; } /* |