aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-09 01:42:02 -0500
committerDan Williams <dan.j.williams@intel.com>2012-05-17 17:33:41 -0400
commit0c3ce38f1bc8b6a6d8df0959e3c0dece31f9350c (patch)
tree22d5fb8aaea17b1ea51b060e51f5a709e382c6e0 /drivers/scsi/isci
parent31a38ef0a5ad12dbe262ca55d0a905657be55a8d (diff)
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(
1266 /* Preserve any current resume callbacks, for instance from other 1266 /* Preserve any current resume callbacks, for instance from other
1267 * resumptions. 1267 * resumptions.
1268 */ 1268 */
1269 clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
1269 status = sci_remote_device_resume(idev, idev->rnc.user_callback, 1270 status = sci_remote_device_resume(idev, idev->rnc.user_callback,
1270 idev->rnc.user_cookie); 1271 idev->rnc.user_cookie);
1271 spin_unlock_irqrestore(&ihost->scic_lock, flags); 1272 spin_unlock_irqrestore(&ihost->scic_lock, flags);
@@ -1501,6 +1502,7 @@ enum sci_status isci_remote_device_suspend_terminate(
1501 1502
1502 /* Put the device into suspension. */ 1503 /* Put the device into suspension. */
1503 spin_lock_irqsave(&ihost->scic_lock, flags); 1504 spin_lock_irqsave(&ihost->scic_lock, flags);
1505 set_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
1504 sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT); 1506 sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
1505 spin_unlock_irqrestore(&ihost->scic_lock, flags); 1507 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1506 1508
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 {
86 #define IDEV_IO_READY 4 86 #define IDEV_IO_READY 4
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 unsigned long flags; 90 unsigned long flags;
90 struct kref kref; 91 struct kref kref;
91 struct isci_port *isci_port; 92 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
161 rnc->ssp.oaf_more_compatibility_features = 0; 161 rnc->ssp.oaf_more_compatibility_features = 0;
162} 162}
163 163
164static void sci_remote_node_context_save_cbparams(
165 struct sci_remote_node_context *sci_rnc,
166 scics_sds_remote_node_context_callback callback,
167 void *callback_parameter)
168{
169 sci_rnc->user_callback = callback;
170 sci_rnc->user_cookie = callback_parameter;
171}
164/** 172/**
165 * 173 *
166 * @sci_rnc: 174 * @sci_rnc:
@@ -179,10 +187,9 @@ static void sci_remote_node_context_setup_to_resume(
179{ 187{
180 if (sci_rnc->destination_state != RNC_DEST_FINAL) { 188 if (sci_rnc->destination_state != RNC_DEST_FINAL) {
181 sci_rnc->destination_state = dest_param; 189 sci_rnc->destination_state = dest_param;
182 if (callback != NULL) { 190 if (callback != NULL)
183 sci_rnc->user_callback = callback; 191 sci_remote_node_context_save_cbparams(
184 sci_rnc->user_cookie = callback_parameter; 192 sci_rnc, callback, callback_parameter);
185 }
186 } 193 }
187} 194}
188 195
@@ -648,67 +655,94 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
648 void *cb_p) 655 void *cb_p)
649{ 656{
650 enum scis_sds_remote_node_context_states state; 657 enum scis_sds_remote_node_context_states state;
658 struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
651 659
652 state = sci_rnc->sm.current_state_id; 660 state = sci_rnc->sm.current_state_id;
653 dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), 661 dev_dbg(scirdev_to_dev(idev),
654 "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d\n", 662 "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d; "
655 __func__, rnc_state_name(state), cb_fn, cb_p, 663 "dev resume path %s\n",
656 sci_rnc->destination_state); 664 __func__, rnc_state_name(state), cb_fn, cb_p,
665 sci_rnc->destination_state,
666 test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)
667 ? "<abort active>" : "<normal>");
657 668
658 switch (state) { 669 switch (state) {
659 case SCI_RNC_INITIAL: 670 case SCI_RNC_INITIAL:
660 if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) 671 if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
661 return SCI_FAILURE_INVALID_STATE; 672 return SCI_FAILURE_INVALID_STATE;
662 673
663 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p, 674 if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
664 RNC_DEST_READY); 675 sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
665 sci_remote_node_context_construct_buffer(sci_rnc); 676 cb_p);
666 sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING); 677 else {
678 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn,
679 cb_p, RNC_DEST_READY);
680 sci_remote_node_context_construct_buffer(sci_rnc);
681 sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
682 }
667 return SCI_SUCCESS; 683 return SCI_SUCCESS;
684
668 case SCI_RNC_POSTING: 685 case SCI_RNC_POSTING:
669 case SCI_RNC_INVALIDATING: 686 case SCI_RNC_INVALIDATING:
670 case SCI_RNC_RESUMING: 687 case SCI_RNC_RESUMING:
671 /* We are still waiting to post when a resume was requested. */ 688 if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
672 switch (sci_rnc->destination_state) { 689 sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
673 case RNC_DEST_SUSPENDED: 690 cb_p);
674 case RNC_DEST_SUSPENDED_RESUME: 691 else {
675 /* Previously waiting to suspend after posting. Now 692 /* We are still waiting to post when a resume was
676 * continue onto resumption. 693 * requested.
677 */ 694 */
678 sci_remote_node_context_setup_to_resume( 695 switch (sci_rnc->destination_state) {
679 sci_rnc, cb_fn, cb_p, 696 case RNC_DEST_SUSPENDED:
680 RNC_DEST_SUSPENDED_RESUME); 697 case RNC_DEST_SUSPENDED_RESUME:
681 break; 698 /* Previously waiting to suspend after posting.
682 default: 699 * Now continue onto resumption.
683 sci_remote_node_context_setup_to_resume( 700 */
684 sci_rnc, cb_fn, cb_p, 701 sci_remote_node_context_setup_to_resume(
685 RNC_DEST_READY); 702 sci_rnc, cb_fn, cb_p,
686 break; 703 RNC_DEST_SUSPENDED_RESUME);
704 break;
705 default:
706 sci_remote_node_context_setup_to_resume(
707 sci_rnc, cb_fn, cb_p,
708 RNC_DEST_READY);
709 break;
710 }
687 } 711 }
688 return SCI_SUCCESS; 712 return SCI_SUCCESS;
713
689 case SCI_RNC_TX_SUSPENDED: 714 case SCI_RNC_TX_SUSPENDED:
690 case SCI_RNC_TX_RX_SUSPENDED: { 715 case SCI_RNC_TX_RX_SUSPENDED:
691 struct isci_remote_device *idev = rnc_to_dev(sci_rnc); 716 if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
692 struct domain_device *dev = idev->domain_dev; 717 sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
693 718 cb_p);
694 /* If this is an expander attached SATA device we must 719 else {
695 * invalidate and repost the RNC since this is the only way 720 struct domain_device *dev = idev->domain_dev;
696 * to clear the TCi to NCQ tag mapping table for the RNi. 721 /* If this is an expander attached SATA device we must
697 * All other device types we can just resume. 722 * invalidate and repost the RNC since this is the only
698 */ 723 * way to clear the TCi to NCQ tag mapping table for
699 sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p, 724 * the RNi. All other device types we can just resume.
700 RNC_DEST_READY); 725 */
726 sci_remote_node_context_setup_to_resume(
727 sci_rnc, cb_fn, cb_p, RNC_DEST_READY);
701 728
702 if (dev_is_sata(dev) && dev->parent) 729 if (dev_is_sata(dev) && dev->parent)
703 sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); 730 sci_change_state(&sci_rnc->sm,
704 else 731 SCI_RNC_INVALIDATING);
705 sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); 732 else
733 sci_change_state(&sci_rnc->sm,
734 SCI_RNC_RESUMING);
735 }
706 return SCI_SUCCESS; 736 return SCI_SUCCESS;
707 } 737
708 case SCI_RNC_AWAIT_SUSPENSION: 738 case SCI_RNC_AWAIT_SUSPENSION:
709 sci_remote_node_context_setup_to_resume( 739 if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
710 sci_rnc, cb_fn, cb_p, 740 sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
711 RNC_DEST_SUSPENDED_RESUME); 741 cb_p);
742 else
743 sci_remote_node_context_setup_to_resume(
744 sci_rnc, cb_fn, cb_p,
745 RNC_DEST_SUSPENDED_RESUME);
712 return SCI_SUCCESS; 746 return SCI_SUCCESS;
713 default: 747 default:
714 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), 748 dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),