[SCSI] ibmvfc: Fix double completion on abort timeout
authorBrian King <brking@linux.vnet.ibm.com>
Fri, 24 Aug 2012 21:50:59 +0000 (16:50 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Mon, 24 Sep 2012 08:10:58 +0000 (12:10 +0400)
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>
drivers/scsi/ibmvscsi/ibmvfc.c

index 134a0ae85bb7d8d996252879b8dfb5b413f4ac0f..4f73daccc9f1849e28bb75a369accbbad27e9d77 100644 (file)
@@ -2241,6 +2241,21 @@ static int ibmvfc_match_key(struct ibmvfc_event *evt, void *key)
        return 0;
 }
 
+/**
+ * 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;
                }
        }