aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-06-20 18:11:22 -0400
committerDan Williams <dan.j.williams@intel.com>2011-07-03 07:04:50 -0400
commit980d3aeb3828b0fdf2a0b2e893d238130b014575 (patch)
tree76fcb476d6cb9ab4d8307ec7ff4dcfffbf1d296f /drivers/scsi
parent77c852f312243192b1f2ce7fc56d678784786692 (diff)
isci: fix isci_terminate_pending() list management
Walk through the list of pending requests being careful to consider that multiple requests can be terminated when the lock is dropped (i.e. invalidating the 'next' reference established by list_for_each_entry_safe). Also noticed that all callers to isci_terminate_pending_requests() specifying terminating, so just drop the parameter. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/isci/remote_device.c2
-rw-r--r--drivers/scsi/isci/request.h5
-rw-r--r--drivers/scsi/isci/task.c131
3 files changed, 67 insertions, 71 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 3b555dcbe569..45592ad33c3b 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1272,7 +1272,7 @@ void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remot
1272 "%s: idev = %p\n", __func__, idev); 1272 "%s: idev = %p\n", __func__, idev);
1273 1273
1274 /* Cleanup all requests pending for this device. */ 1274 /* Cleanup all requests pending for this device. */
1275 isci_terminate_pending_requests(ihost, idev, terminating); 1275 isci_terminate_pending_requests(ihost, idev);
1276 1276
1277 dev_dbg(&ihost->pdev->dev, 1277 dev_dbg(&ihost->pdev->dev,
1278 "%s: idev = %p, done\n", __func__, idev); 1278 "%s: idev = %p, done\n", __func__, idev);
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 547c35cbe459..ac9368c5a6b5 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -776,9 +776,8 @@ isci_request_io_request_get_next_sge(struct isci_request *request,
776} 776}
777 777
778void 778void
779isci_terminate_pending_requests(struct isci_host *isci_host, 779isci_terminate_pending_requests(struct isci_host *ihost,
780 struct isci_remote_device *isci_device, 780 struct isci_remote_device *idev);
781 enum isci_request_status new_request_state);
782enum sci_status 781enum sci_status
783scic_task_request_construct(struct scic_sds_controller *scic, 782scic_task_request_construct(struct scic_sds_controller *scic,
784 struct scic_sds_remote_device *sci_dev, 783 struct scic_sds_remote_device *sci_dev,
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 573cf1c9e81d..01032dc2c116 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -796,81 +796,79 @@ static void isci_terminate_request_core(
796 * @isci_host: This parameter specifies SCU. 796 * @isci_host: This parameter specifies SCU.
797 * @isci_device: This parameter specifies the target. 797 * @isci_device: This parameter specifies the target.
798 * 798 *
799 *
800 */ 799 */
801void isci_terminate_pending_requests( 800void isci_terminate_pending_requests(struct isci_host *ihost,
802 struct isci_host *isci_host, 801 struct isci_remote_device *idev)
803 struct isci_remote_device *isci_device,
804 enum isci_request_status new_request_state)
805{ 802{
806 struct isci_request *request; 803 struct completion request_completion;
807 struct isci_request *next_request;
808 unsigned long flags;
809 enum isci_request_status old_state; 804 enum isci_request_status old_state;
810 DECLARE_COMPLETION_ONSTACK(request_completion); 805 unsigned long flags;
811 806 LIST_HEAD(list);
812 dev_dbg(&isci_host->pdev->dev,
813 "%s: isci_device = %p (new request state = %d)\n",
814 __func__, isci_device, new_request_state);
815 807
816 spin_lock_irqsave(&isci_host->scic_lock, flags); 808 spin_lock_irqsave(&ihost->scic_lock, flags);
809 list_splice_init(&idev->reqs_in_process, &list);
817 810
818 /* Iterate through the list. */ 811 /* assumes that isci_terminate_request_core deletes from the list */
819 list_for_each_entry_safe(request, next_request, 812 while (!list_empty(&list)) {
820 &isci_device->reqs_in_process, dev_node) { 813 struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node);
821 814
822 init_completion(&request_completion); 815 /* Change state to "terminating" if it is currently
816 * "started".
817 */
818 old_state = isci_request_change_started_to_newstate(ireq,
819 &request_completion,
820 terminating);
821 switch (old_state) {
822 case started:
823 case completed:
824 case aborting:
825 break;
826 default:
827 /* termination in progress, or otherwise dispositioned.
828 * We know the request was on 'list' so should be safe
829 * to move it back to reqs_in_process
830 */
831 list_move(&ireq->dev_node, &idev->reqs_in_process);
832 ireq = NULL;
833 break;
834 }
823 835
824 /* Change state to "new_request_state" if it is currently 836 if (!ireq)
825 * "started". 837 continue;
826 */ 838 spin_unlock_irqrestore(&ihost->scic_lock, flags);
827 old_state = isci_request_change_started_to_newstate(
828 request,
829 &request_completion,
830 new_request_state);
831 839
832 spin_unlock_irqrestore(&isci_host->scic_lock, flags); 840 init_completion(&request_completion);
833 841
834 if ((old_state == started) || 842 dev_dbg(&ihost->pdev->dev,
835 (old_state == completed) || 843 "%s: idev=%p request=%p; task=%p old_state=%d\n",
836 (old_state == aborting)) { 844 __func__, idev, ireq,
837 845 ireq->ttype == io_task ? isci_request_access_task(ireq) : NULL,
838 dev_warn(&isci_host->pdev->dev, 846 old_state);
839 "%s: isci_device=%p request=%p; task=%p " 847
840 "old_state=%d\n", 848 /* If the old_state is started:
841 __func__, 849 * This request was not already being aborted. If it had been,
842 isci_device, request, 850 * then the aborting I/O (ie. the TMF request) would not be in
843 ((request->ttype == io_task) 851 * the aborting state, and thus would be terminated here. Note
844 ? isci_request_access_task(request) 852 * that since the TMF completion's call to the kernel function
845 : NULL), 853 * "complete()" does not happen until the pending I/O request
846 old_state); 854 * terminate fully completes, we do not have to implement a
847 855 * special wait here for already aborting requests - the
848 /* If the old_state is started: 856 * termination of the TMF request will force the request
849 * This request was not already being aborted. If it had been, 857 * to finish it's already started terminate.
850 * then the aborting I/O (ie. the TMF request) would not be in 858 *
851 * the aborting state, and thus would be terminated here. Note 859 * If old_state == completed:
852 * that since the TMF completion's call to the kernel function 860 * This request completed from the SCU hardware perspective
853 * "complete()" does not happen until the pending I/O request 861 * and now just needs cleaning up in terms of freeing the
854 * terminate fully completes, we do not have to implement a 862 * request and potentially calling up to libsas.
855 * special wait here for already aborting requests - the 863 *
856 * termination of the TMF request will force the request 864 * If old_state == aborting:
857 * to finish it's already started terminate. 865 * This request has already gone through a TMF timeout, but may
858 * 866 * not have been terminated; needs cleaning up at least.
859 * If old_state == completed: 867 */
860 * This request completed from the SCU hardware perspective 868 isci_terminate_request_core(ihost, idev, ireq);
861 * and now just needs cleaning up in terms of freeing the 869 spin_lock_irqsave(&ihost->scic_lock, flags);
862 * request and potentially calling up to libsas.
863 *
864 * If old_state == aborting:
865 * This request has already gone through a TMF timeout, but may
866 * not have been terminated; needs cleaning up at least.
867 */
868 isci_terminate_request_core(isci_host, isci_device,
869 request);
870 }
871 spin_lock_irqsave(&isci_host->scic_lock, flags);
872 } 870 }
873 spin_unlock_irqrestore(&isci_host->scic_lock, flags); 871 spin_unlock_irqrestore(&ihost->scic_lock, flags);
874} 872}
875 873
876/** 874/**
@@ -965,8 +963,7 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun)
965 if (ret == TMF_RESP_FUNC_COMPLETE) 963 if (ret == TMF_RESP_FUNC_COMPLETE)
966 /* Terminate all I/O now. */ 964 /* Terminate all I/O now. */
967 isci_terminate_pending_requests(isci_host, 965 isci_terminate_pending_requests(isci_host,
968 isci_device, 966 isci_device);
969 terminating);
970 967
971 return ret; 968 return ret;
972} 969}