isci: Wait for RNC resumption before leaving the abort path.
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>
Fri, 9 Mar 2012 06:42:04 +0000 (22:42 -0800)
committerDan Williams <dan.j.williams@intel.com>
Thu, 17 May 2012 21:33:42 +0000 (14:33 -0700)
In the case of TMF execution, or device resets, wait for the RNC to fully
resume before returning to the caller.  This ensures that the remote
device will not fail I/O requests while waiting for the RNC resumption to
complete.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/scsi/isci/remote_device.c
drivers/scsi/isci/remote_device.h

index adeda64e512a6349144b37e227c246f1ef93d61b..37e9bdead6f65c30632ecf8b5988e6de115045a0 100644 (file)
@@ -1289,6 +1289,48 @@ enum sci_status sci_remote_device_resume(
        return status;
 }
 
+static void isci_remote_device_resume_from_abort_complete(void *cbparam)
+{
+       struct isci_remote_device *idev = cbparam;
+       struct isci_host *ihost = idev->owning_port->owning_controller;
+       scics_sds_remote_node_context_callback abort_resume_cb =
+               idev->abort_resume_cb;
+
+       dev_dbg(scirdev_to_dev(idev), "%s: passing-along resume: %p\n",
+               __func__, abort_resume_cb);
+
+       if (abort_resume_cb != NULL) {
+               idev->abort_resume_cb = NULL;
+               abort_resume_cb(idev->abort_resume_cbparam);
+       }
+       clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+       wake_up(&ihost->eventq);
+}
+
+
+void isci_remote_device_wait_for_resume_from_abort(
+       struct isci_host *ihost,
+       struct isci_remote_device *idev)
+{
+       dev_dbg(scirdev_to_dev(idev), "%s: starting resume wait: %p\n",
+                __func__, idev);
+
+       #define MAX_RESUME_MSECS 5
+       if (!wait_event_timeout(ihost->eventq,
+                              (!test_bit(IDEV_ABORT_PATH_RESUME_PENDING,
+                                         &idev->flags)
+                               || test_bit(IDEV_STOP_PENDING, &idev->flags)),
+                              msecs_to_jiffies(MAX_RESUME_MSECS))) {
+
+               dev_warn(scirdev_to_dev(idev), "%s: #### Timeout waiting for "
+                        "resume: %p\n", __func__, idev);
+       }
+       clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+
+       dev_dbg(scirdev_to_dev(idev), "%s: resume wait done: %p\n",
+                __func__, idev);
+}
+
 enum sci_status isci_remote_device_resume_from_abort(
        struct isci_host *ihost,
        struct isci_remote_device *idev)
@@ -1300,12 +1342,18 @@ enum sci_status isci_remote_device_resume_from_abort(
        /* Preserve any current resume callbacks, for instance from other
         * resumptions.
         */
+       idev->abort_resume_cb = idev->rnc.user_callback;
+       idev->abort_resume_cbparam = idev->rnc.user_cookie;
+       set_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
        clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
-       status = sci_remote_device_resume(idev, idev->rnc.user_callback,
-                                         idev->rnc.user_cookie);
+       status = sci_remote_device_resume(
+                       idev, isci_remote_device_resume_from_abort_complete,
+                       idev);
        spin_unlock_irqrestore(&ihost->scic_lock, flags);
+       isci_remote_device_wait_for_resume_from_abort(ihost, idev);
        return status;
 }
+
 /**
  * sci_remote_device_start() - This method will start the supplied remote
  *    device.  This method enables normal IO requests to flow through to the
index 53564c35cf2461f5e540a76245acb518cd10168f..ff34c4e8c1b16f32741bddf7cd1a1ccad9d8c3fe 100644 (file)
@@ -87,6 +87,7 @@ struct isci_remote_device {
        #define IDEV_IO_NCQERROR 5
        #define IDEV_RNC_LLHANG_ENABLED 6
        #define IDEV_ABORT_PATH_ACTIVE 7
+       #define IDEV_ABORT_PATH_RESUME_PENDING 8
        unsigned long flags;
        struct kref kref;
        struct isci_port *isci_port;
@@ -101,6 +102,8 @@ struct isci_remote_device {
        u32 started_request_count;
        struct isci_request *working_request;
        u32 not_ready_reason;
+       scics_sds_remote_node_context_callback abort_resume_cb;
+       void *abort_resume_cbparam;
 };
 
 #define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000