diff options
author | Arvind Kumar <arvindkumar@vmware.com> | 2014-03-08 15:51:12 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2014-03-19 18:04:45 -0400 |
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 b9755ec0e812..7c5abd7f6c67 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Linux driver for VMware's para-virtualized SCSI HBA. | 2 | * Linux driver for VMware's para-virtualized SCSI HBA. |
3 | * | 3 | * |
4 | * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. | 4 | * Copyright (C) 2008-2014, VMware, Inc. All Rights Reserved. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
@@ -62,6 +62,7 @@ struct pvscsi_ctx { | |||
62 | dma_addr_t dataPA; | 62 | dma_addr_t dataPA; |
63 | dma_addr_t sensePA; | 63 | dma_addr_t sensePA; |
64 | dma_addr_t sglPA; | 64 | dma_addr_t sglPA; |
65 | struct completion *abort_cmp; | ||
65 | }; | 66 | }; |
66 | 67 | ||
67 | struct pvscsi_adapter { | 68 | struct pvscsi_adapter { |
@@ -177,6 +178,7 @@ static void pvscsi_release_context(struct pvscsi_adapter *adapter, | |||
177 | struct pvscsi_ctx *ctx) | 178 | struct pvscsi_ctx *ctx) |
178 | { | 179 | { |
179 | ctx->cmd = NULL; | 180 | ctx->cmd = NULL; |
181 | ctx->abort_cmp = NULL; | ||
180 | list_add(&ctx->list, &adapter->cmd_pool); | 182 | list_add(&ctx->list, &adapter->cmd_pool); |
181 | } | 183 | } |
182 | 184 | ||
@@ -496,15 +498,27 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, | |||
496 | { | 498 | { |
497 | struct pvscsi_ctx *ctx; | 499 | struct pvscsi_ctx *ctx; |
498 | struct scsi_cmnd *cmd; | 500 | struct scsi_cmnd *cmd; |
501 | struct completion *abort_cmp; | ||
499 | u32 btstat = e->hostStatus; | 502 | u32 btstat = e->hostStatus; |
500 | u32 sdstat = e->scsiStatus; | 503 | u32 sdstat = e->scsiStatus; |
501 | 504 | ||
502 | ctx = pvscsi_get_context(adapter, e->context); | 505 | ctx = pvscsi_get_context(adapter, e->context); |
503 | cmd = ctx->cmd; | 506 | cmd = ctx->cmd; |
507 | abort_cmp = ctx->abort_cmp; | ||
504 | pvscsi_unmap_buffers(adapter, ctx); | 508 | pvscsi_unmap_buffers(adapter, ctx); |
505 | pvscsi_release_context(adapter, ctx); | 509 | pvscsi_release_context(adapter, ctx); |
506 | cmd->result = 0; | 510 | if (abort_cmp) { |
511 | /* | ||
512 | * The command was requested to be aborted. Just signal that | ||
513 | * the request completed and swallow the actual cmd completion | ||
514 | * here. The abort handler will post a completion for this | ||
515 | * command indicating that it got successfully aborted. | ||
516 | */ | ||
517 | complete(abort_cmp); | ||
518 | return; | ||
519 | } | ||
507 | 520 | ||
521 | cmd->result = 0; | ||
508 | if (sdstat != SAM_STAT_GOOD && | 522 | if (sdstat != SAM_STAT_GOOD && |
509 | (btstat == BTSTAT_SUCCESS || | 523 | (btstat == BTSTAT_SUCCESS || |
510 | btstat == BTSTAT_LINKED_COMMAND_COMPLETED || | 524 | btstat == BTSTAT_LINKED_COMMAND_COMPLETED || |
@@ -726,6 +740,8 @@ static int pvscsi_abort(struct scsi_cmnd *cmd) | |||
726 | struct pvscsi_adapter *adapter = shost_priv(cmd->device->host); | 740 | struct pvscsi_adapter *adapter = shost_priv(cmd->device->host); |
727 | struct pvscsi_ctx *ctx; | 741 | struct pvscsi_ctx *ctx; |
728 | unsigned long flags; | 742 | unsigned long flags; |
743 | int result = SUCCESS; | ||
744 | DECLARE_COMPLETION_ONSTACK(abort_cmp); | ||
729 | 745 | ||
730 | scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n", | 746 | scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n", |
731 | adapter->host->host_no, cmd); | 747 | adapter->host->host_no, cmd); |
@@ -748,13 +764,40 @@ static int pvscsi_abort(struct scsi_cmnd *cmd) | |||
748 | goto out; | 764 | goto out; |
749 | } | 765 | } |
750 | 766 | ||
767 | /* | ||
768 | * Mark that the command has been requested to be aborted and issue | ||
769 | * the abort. | ||
770 | */ | ||
771 | ctx->abort_cmp = &abort_cmp; | ||
772 | |||
751 | pvscsi_abort_cmd(adapter, ctx); | 773 | pvscsi_abort_cmd(adapter, ctx); |
774 | spin_unlock_irqrestore(&adapter->hw_lock, flags); | ||
775 | /* Wait for 2 secs for the completion. */ | ||
776 | wait_for_completion_timeout(&abort_cmp, msecs_to_jiffies(2000)); | ||
777 | spin_lock_irqsave(&adapter->hw_lock, flags); | ||
752 | 778 | ||
753 | pvscsi_process_completion_ring(adapter); | 779 | if (!completion_done(&abort_cmp)) { |
780 | /* | ||
781 | * Failed to abort the command, unmark the fact that it | ||
782 | * was requested to be aborted. | ||
783 | */ | ||
784 | ctx->abort_cmp = NULL; | ||
785 | result = FAILED; | ||
786 | scmd_printk(KERN_DEBUG, cmd, | ||
787 | "Failed to get completion for aborted cmd %p\n", | ||
788 | cmd); | ||
789 | goto out; | ||
790 | } | ||
791 | |||
792 | /* | ||
793 | * Successfully aborted the command. | ||
794 | */ | ||
795 | cmd->result = (DID_ABORT << 16); | ||
796 | cmd->scsi_done(cmd); | ||
754 | 797 | ||
755 | out: | 798 | out: |
756 | spin_unlock_irqrestore(&adapter->hw_lock, flags); | 799 | spin_unlock_irqrestore(&adapter->hw_lock, flags); |
757 | return SUCCESS; | 800 | return result; |
758 | } | 801 | } |
759 | 802 | ||
760 | /* | 803 | /* |