From: Brian King <brking@linux.vnet.ibm.com>
Subject: ibmvfc: Fix double completion on abort timeout
Git-commit: a077c7faf3cb3e28303ba431148a85f613f4e955
Patch-mainline: yes
References: bnc#788452
    
    If an abort request times out to the virtual fibre channel adapter,
    the ibmvfc driver will kick off a reset of the adapter. This
    patch ensures we wait for the both the abort request and the
    request being aborted to be completed prior to exiting the
    eh_abort handler. This fixes a bug where the ibmvfc driver
    was erroneously returning success to the eh_abort handler
    then later sending back a response to the same command.
    
Signed-off-by: Brian King <brking@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Acked-by: Torsten Duwe <duwe@suse.de>

 drivers/scsi/ibmvscsi/ibmvfc.c |   30 +++++++++++++++++++++++++++++-
 1 files changed, 29 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 134a0ae..4f73dac 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -2242,6 +2242,21 @@ static int ibmvfc_match_key(struct ibmvfc_event *evt, void *key)
 }
 
 /**
+ * ibmvfc_match_evt - Match function for specified event
+ * @evt:	ibmvfc event struct
+ * @match:	event to match
+ *
+ * Returns:
+ *	1 if event matches key / 0 if event does not match key
+ **/
+static int ibmvfc_match_evt(struct ibmvfc_event *evt, void *match)
+{
+	if (evt == match)
+		return 1;
+	return 0;
+}
+
+/**
  * ibmvfc_abort_task_set - Abort outstanding commands to the device
  * @sdev:	scsi device to abort commands
  *
@@ -2322,7 +2337,20 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev)
 		if (rc) {
 			sdev_printk(KERN_INFO, sdev, "Cancel failed, resetting host\n");
 			ibmvfc_reset_host(vhost);
-			rsp_rc = 0;
+			rsp_rc = -EIO;
+			rc = ibmvfc_wait_for_ops(vhost, sdev->hostdata, ibmvfc_match_key);
+
+			if (rc == SUCCESS)
+				rsp_rc = 0;
+
+			rc = ibmvfc_wait_for_ops(vhost, evt, ibmvfc_match_evt);
+			if (rc != SUCCESS) {
+				spin_lock_irqsave(vhost->host->host_lock, flags);
+				ibmvfc_hard_reset_host(vhost);
+				spin_unlock_irqrestore(vhost->host->host_lock, flags);
+				rsp_rc = 0;
+			}
+
 			goto out;
 		}
 	}
