summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-08 22:42:02 -0800
committerDan Williams <dan.j.williams@intel.com>2012-05-17 14:33:41 -0700
commit0c3ce38f1bc8b6a6d8df0959e3c0dece31f9350c (patch)
tree22d5fb8aaea17b1ea51b060e51f5a709e382c6e0 /drivers/scsi/isci
parent31a38ef0a5ad12dbe262ca55d0a905657be55a8d (diff)
downloadlinux-0c3ce38f1bc8b6a6d8df0959e3c0dece31f9350c.tar.bz2
isci: When in the abort path, defeat other resume calls until done.
Completion of I/Os during the one of the abort path interface calls from libsas can drive remote device state changes and the resumption of the device RNC. This is a problem when the abort path is attempting to cleanup outstanding I/O at the same time - the resumption can prevent the termination from occuring correctly. 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.c2
-rw-r--r--drivers/scsi/isci/remote_device.h1
-rw-r--r--drivers/scsi/isci/remote_node_context.c126
3 files changed, 83 insertions, 46 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index acc94a454a1f..d1c2a2294a32 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1266,6 +1266,7 @@ enum sci_status isci_remote_device_resume_from_abort(
/* Preserve any current resume callbacks, for instance from other
* resumptions.
*/
+ clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
status = sci_remote_device_resume(idev, idev->rnc.user_callback,
idev->rnc.user_cookie);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
@@ -1501,6 +1502,7 @@ enum sci_status isci_remote_device_suspend_terminate(
/* Put the device into suspension. */
spin_lock_irqsave(&ihost->scic_lock, flags);
+ set_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index d1d18925fbfc..53564c35cf24 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -86,6 +86,7 @@ struct isci_remote_device {
#define IDEV_IO_READY 4
#define IDEV_IO_NCQERROR 5
#define IDEV_RNC_LLHANG_ENABLED 6
+ #define IDEV_ABORT_PATH_ACTIVE 7
unsigned long flags;
struct kref kref;
struct isci_port *isci_port;
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 77c8b5138b7e..faeae9554ee3 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -161,6 +161,14 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
rnc->ssp.oaf_more_compatibility_features = 0;
}
+static void sci_remote_node_context_save_cbparams(
+ struct sci_remote_node_context *sci_rnc,
+ scics_sds_remote_node_context_callback callback,
+ void *callback_parameter)
+{
+ sci_rnc->user_callback = callback;
+ sci_rnc->user_cookie = callback_parameter;
+}
/**
*
* @sci_rnc:
@@ -179,10 +187,9 @@ static void sci_remote_node_context_setup_to_resume(
{
if (sci_rnc->destination_state != RNC_DEST_FINAL) {
sci_rnc->destination_state = dest_param;
- if (callback != NULL) {
- sci_rnc->user_callback = callback;
- sci_rnc->user_cookie = callback_parameter;
- }
+ if (callback != NULL)
+ sci_remote_node_context_save_cbparams(
+ sci_rnc, callback, callback_parameter);
}
}
@@ -648,67 +655,94 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
void *cb_p)
{
enum scis_sds_remote_node_context_states state;
+ struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
state = sci_rnc->sm.current_state_id;
- dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
- "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d\n",
- __func__, rnc_state_name(state), cb_fn, cb_p,
- sci_rnc->destination_state);
+ dev_dbg(scirdev_to_dev(idev),
+ "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d; "
+ "dev resume path %s\n",
+ __func__, rnc_state_name(state), cb_fn, cb_p,
+ sci_rnc->destination_state,
+ test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)
+ ? "<abort active>" : "<normal>");
switch (state) {
case SCI_RNC_INITIAL:
if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
return SCI_FAILURE_INVALID_STATE;
- sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
- RNC_DEST_READY);
- sci_remote_node_context_construct_buffer(sci_rnc);
- sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
+ if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+ sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+ cb_p);
+ else {
+ sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn,
+ cb_p, RNC_DEST_READY);
+ sci_remote_node_context_construct_buffer(sci_rnc);
+ sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
+ }
return SCI_SUCCESS;
+
case SCI_RNC_POSTING:
case SCI_RNC_INVALIDATING:
case SCI_RNC_RESUMING:
- /* We are still waiting to post when a resume was requested. */
- switch (sci_rnc->destination_state) {
- case RNC_DEST_SUSPENDED:
- case RNC_DEST_SUSPENDED_RESUME:
- /* Previously waiting to suspend after posting. Now
- * continue onto resumption.
+ if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+ sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+ cb_p);
+ else {
+ /* We are still waiting to post when a resume was
+ * requested.
*/
- sci_remote_node_context_setup_to_resume(
- sci_rnc, cb_fn, cb_p,
- RNC_DEST_SUSPENDED_RESUME);
- break;
- default:
- sci_remote_node_context_setup_to_resume(
- sci_rnc, cb_fn, cb_p,
- RNC_DEST_READY);
- break;
+ switch (sci_rnc->destination_state) {
+ case RNC_DEST_SUSPENDED:
+ case RNC_DEST_SUSPENDED_RESUME:
+ /* Previously waiting to suspend after posting.
+ * Now continue onto resumption.
+ */
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p,
+ RNC_DEST_SUSPENDED_RESUME);
+ break;
+ default:
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p,
+ RNC_DEST_READY);
+ break;
+ }
}
return SCI_SUCCESS;
+
case SCI_RNC_TX_SUSPENDED:
- case SCI_RNC_TX_RX_SUSPENDED: {
- struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
- struct domain_device *dev = idev->domain_dev;
-
- /* If this is an expander attached SATA device we must
- * invalidate and repost the RNC since this is the only way
- * to clear the TCi to NCQ tag mapping table for the RNi.
- * All other device types we can just resume.
- */
- sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
- RNC_DEST_READY);
+ case SCI_RNC_TX_RX_SUSPENDED:
+ if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+ sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+ cb_p);
+ else {
+ struct domain_device *dev = idev->domain_dev;
+ /* If this is an expander attached SATA device we must
+ * invalidate and repost the RNC since this is the only
+ * way to clear the TCi to NCQ tag mapping table for
+ * the RNi. All other device types we can just resume.
+ */
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p, RNC_DEST_READY);
- if (dev_is_sata(dev) && dev->parent)
- sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
- else
- sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
+ if (dev_is_sata(dev) && dev->parent)
+ sci_change_state(&sci_rnc->sm,
+ SCI_RNC_INVALIDATING);
+ else
+ sci_change_state(&sci_rnc->sm,
+ SCI_RNC_RESUMING);
+ }
return SCI_SUCCESS;
- }
+
case SCI_RNC_AWAIT_SUSPENSION:
- sci_remote_node_context_setup_to_resume(
- sci_rnc, cb_fn, cb_p,
- RNC_DEST_SUSPENDED_RESUME);
+ if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+ sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+ cb_p);
+ else
+ sci_remote_node_context_setup_to_resume(
+ sci_rnc, cb_fn, cb_p,
+ RNC_DEST_SUSPENDED_RESUME);
return SCI_SUCCESS;
default:
dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),