mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
31a38ef0a5
commit
0c3ce38f1b
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
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 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)),
|
||||
|
|
Loading…
Reference in New Issue