summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/remote_device.c
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-08 22:42:04 -0800
committerDan Williams <dan.j.williams@intel.com>2012-05-17 14:33:42 -0700
commit0cce165e2814bc8c08ab229db5e17013971dced7 (patch)
tree48dde48b2f1af5fee99bd4439914abde40b62912 /drivers/scsi/isci/remote_device.c
parentd76689e46c8b2180c08575adc830cfda890ceb87 (diff)
downloadlinux-0cce165e2814bc8c08ab229db5e17013971dced7.tar.bz2
isci: Wait for RNC resumption before leaving the abort path.
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>
Diffstat (limited to 'drivers/scsi/isci/remote_device.c')
-rw-r--r--drivers/scsi/isci/remote_device.c52
1 files changed, 50 insertions, 2 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index adeda64e512a..37e9bdead6f6 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -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