diff options
author | Jeff Skirvin <jeffrey.d.skirvin@intel.com> | 2012-03-09 01:42:02 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2012-05-17 17:33:41 -0400 |
commit | 0c3ce38f1bc8b6a6d8df0959e3c0dece31f9350c (patch) | |
tree | 22d5fb8aaea17b1ea51b060e51f5a709e382c6e0 /drivers/scsi/isci | |
parent | 31a38ef0a5ad12dbe262ca55d0a905657be55a8d (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.c | 2 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.h | 1 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_node_context.c | 126 |
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 | ||
164 | static 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)), |