aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-09 01:42:04 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 17:33:42 -0400
commit0cce165e2814bc8c08ab229db5e17013971dced7 (patch)
tree48dde48b2f1af5fee99bd4439914abde40b62912 /drivers/scsi/isci
parentd76689e46c8b2180c08575adc830cfda890ceb87 (diff)
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')
-rw-r--r--drivers/scsi/isci/remote_device.c52
-rw-r--r--drivers/scsi/isci/remote_device.h3
2 files changed, 53 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(
1289 return status; 1289 return status;
1290} 1290}
1291 1291
1292static void isci_remote_device_resume_from_abort_complete(void *cbparam)
1293{
1294 struct isci_remote_device *idev = cbparam;
1295 struct isci_host *ihost = idev->owning_port->owning_controller;
1296 scics_sds_remote_node_context_callback abort_resume_cb =
1297 idev->abort_resume_cb;
1298
1299 dev_dbg(scirdev_to_dev(idev), "%s: passing-along resume: %p\n",
1300 __func__, abort_resume_cb);
1301
1302 if (abort_resume_cb != NULL) {
1303 idev->abort_resume_cb = NULL;
1304 abort_resume_cb(idev->abort_resume_cbparam);
1305 }
1306 clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
1307 wake_up(&ihost->eventq);
1308}
1309
1310
1311void isci_remote_device_wait_for_resume_from_abort(
1312 struct isci_host *ihost,
1313 struct isci_remote_device *idev)
1314{
1315 dev_dbg(scirdev_to_dev(idev), "%s: starting resume wait: %p\n",
1316 __func__, idev);
1317
1318 #define MAX_RESUME_MSECS 5
1319 if (!wait_event_timeout(ihost->eventq,
1320 (!test_bit(IDEV_ABORT_PATH_RESUME_PENDING,
1321 &idev->flags)
1322 || test_bit(IDEV_STOP_PENDING, &idev->flags)),
1323 msecs_to_jiffies(MAX_RESUME_MSECS))) {
1324
1325 dev_warn(scirdev_to_dev(idev), "%s: #### Timeout waiting for "
1326 "resume: %p\n", __func__, idev);
1327 }
1328 clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
1329
1330 dev_dbg(scirdev_to_dev(idev), "%s: resume wait done: %p\n",
1331 __func__, idev);
1332}
1333
1292enum sci_status isci_remote_device_resume_from_abort( 1334enum sci_status isci_remote_device_resume_from_abort(
1293 struct isci_host *ihost, 1335 struct isci_host *ihost,
1294 struct isci_remote_device *idev) 1336 struct isci_remote_device *idev)
@@ -1300,12 +1342,18 @@ enum sci_status isci_remote_device_resume_from_abort(
1300 /* Preserve any current resume callbacks, for instance from other 1342 /* Preserve any current resume callbacks, for instance from other
1301 * resumptions. 1343 * resumptions.
1302 */ 1344 */
1345 idev->abort_resume_cb = idev->rnc.user_callback;
1346 idev->abort_resume_cbparam = idev->rnc.user_cookie;
1347 set_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
1303 clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags); 1348 clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
1304 status = sci_remote_device_resume(idev, idev->rnc.user_callback, 1349 status = sci_remote_device_resume(
1305 idev->rnc.user_cookie); 1350 idev, isci_remote_device_resume_from_abort_complete,
1351 idev);
1306 spin_unlock_irqrestore(&ihost->scic_lock, flags); 1352 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1353 isci_remote_device_wait_for_resume_from_abort(ihost, idev);
1307 return status; 1354 return status;
1308} 1355}
1356
1309/** 1357/**
1310 * sci_remote_device_start() - This method will start the supplied remote 1358 * sci_remote_device_start() - This method will start the supplied remote
1311 * device. This method enables normal IO requests to flow through to the 1359 * device. This method enables normal IO requests to flow through to the
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 53564c35cf24..ff34c4e8c1b1 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -87,6 +87,7 @@ struct isci_remote_device {
87 #define IDEV_IO_NCQERROR 5 87 #define IDEV_IO_NCQERROR 5
88 #define IDEV_RNC_LLHANG_ENABLED 6 88 #define IDEV_RNC_LLHANG_ENABLED 6
89 #define IDEV_ABORT_PATH_ACTIVE 7 89 #define IDEV_ABORT_PATH_ACTIVE 7
90 #define IDEV_ABORT_PATH_RESUME_PENDING 8
90 unsigned long flags; 91 unsigned long flags;
91 struct kref kref; 92 struct kref kref;
92 struct isci_port *isci_port; 93 struct isci_port *isci_port;
@@ -101,6 +102,8 @@ struct isci_remote_device {
101 u32 started_request_count; 102 u32 started_request_count;
102 struct isci_request *working_request; 103 struct isci_request *working_request;
103 u32 not_ready_reason; 104 u32 not_ready_reason;
105 scics_sds_remote_node_context_callback abort_resume_cb;
106 void *abort_resume_cbparam;
104}; 107};
105 108
106#define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000 109#define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000