diff options
author | Jeff Skirvin <jeffrey.d.skirvin@intel.com> | 2011-03-04 17:06:42 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 06:55:29 -0400 |
commit | a5fde225364df30507ba1a5aafeec85e595000d3 (patch) | |
tree | d86c9daaafe01e9df139fe0569d7d21ce6fa3f8d /drivers/scsi/isci/request.c | |
parent | 11b00c194cfbd0eb0d90f32c096508b2bb8be6ec (diff) |
isci: fix completion / abort path.
Corrected use of the request state_lock in the completion callback.
In the case where an abort (or reset) thread is trying to terminate an
I/O request, it sets the request state to "aborting" (or "terminating")
if the state is still "starting". One of the bugs was to never set the
state to "completed". Another was to not correctly recognize the
situation where the I/O had completed but the sas_task was still pending
callback to task_done - this was typically a problem in the LUN and
device reset cases.
It is now possible that we leave isci_task_abort_task() with
request->io_request_completion pointing to localy allocated
aborted_io_completion struct. It may result in a system crash.
Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Maciej Trela <Maciej.Trela@intel.com>
Signed-off-by: Jacek Danecki <Jacek.Danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/request.c')
-rw-r--r-- | drivers/scsi/isci/request.c | 52 |
1 files changed, 29 insertions, 23 deletions
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 8039f1c72f72..c88e270b2b40 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c | |||
@@ -814,9 +814,8 @@ static void isci_task_save_for_upper_layer_completion( | |||
814 | break; | 814 | break; |
815 | 815 | ||
816 | case isci_perform_aborted_io_completion: | 816 | case isci_perform_aborted_io_completion: |
817 | /* | 817 | /* No notification to libsas because this request is |
818 | * No notification because this request is already | 818 | * already in the abort path. |
819 | * in the abort path. | ||
820 | */ | 819 | */ |
821 | dev_warn(&host->pdev->dev, | 820 | dev_warn(&host->pdev->dev, |
822 | "%s: Aborted - task = %p, response=%d, status=%d\n", | 821 | "%s: Aborted - task = %p, response=%d, status=%d\n", |
@@ -824,6 +823,19 @@ static void isci_task_save_for_upper_layer_completion( | |||
824 | task, | 823 | task, |
825 | response, | 824 | response, |
826 | status); | 825 | status); |
826 | |||
827 | /* Wake up whatever process was waiting for this | ||
828 | * request to complete. | ||
829 | */ | ||
830 | WARN_ON(request->io_request_completion == NULL); | ||
831 | |||
832 | if (request->io_request_completion != NULL) { | ||
833 | |||
834 | /* Signal whoever is waiting that this | ||
835 | * request is complete. | ||
836 | */ | ||
837 | complete(request->io_request_completion); | ||
838 | } | ||
827 | break; | 839 | break; |
828 | 840 | ||
829 | case isci_perform_error_io_completion: | 841 | case isci_perform_error_io_completion: |
@@ -847,7 +859,7 @@ static void isci_task_save_for_upper_layer_completion( | |||
847 | response, | 859 | response, |
848 | status); | 860 | status); |
849 | 861 | ||
850 | /* Add to the aborted list. */ | 862 | /* Add to the error to libsas list. */ |
851 | list_add(&request->completed_node, | 863 | list_add(&request->completed_node, |
852 | &host->requests_to_errorback); | 864 | &host->requests_to_errorback); |
853 | break; | 865 | break; |
@@ -873,8 +885,6 @@ void isci_request_io_request_complete( | |||
873 | struct ssp_response_iu *resp_iu; | 885 | struct ssp_response_iu *resp_iu; |
874 | void *resp_buf; | 886 | void *resp_buf; |
875 | unsigned long task_flags; | 887 | unsigned long task_flags; |
876 | unsigned long state_flags; | ||
877 | struct completion *io_request_completion; | ||
878 | struct isci_remote_device *isci_device = request->isci_device; | 888 | struct isci_remote_device *isci_device = request->isci_device; |
879 | enum service_response response = SAS_TASK_UNDELIVERED; | 889 | enum service_response response = SAS_TASK_UNDELIVERED; |
880 | enum exec_status status = SAS_ABORTED_TASK; | 890 | enum exec_status status = SAS_ABORTED_TASK; |
@@ -891,9 +901,8 @@ void isci_request_io_request_complete( | |||
891 | task->data_dir, | 901 | task->data_dir, |
892 | completion_status); | 902 | completion_status); |
893 | 903 | ||
894 | spin_lock_irqsave(&request->state_lock, state_flags); | 904 | spin_lock(&request->state_lock); |
895 | request_status = isci_request_get_state(request); | 905 | request_status = isci_request_get_state(request); |
896 | spin_unlock_irqrestore(&request->state_lock, state_flags); | ||
897 | 906 | ||
898 | /* Decode the request status. Note that if the request has been | 907 | /* Decode the request status. Note that if the request has been |
899 | * aborted by a task management function, we don't care | 908 | * aborted by a task management function, we don't care |
@@ -928,6 +937,8 @@ void isci_request_io_request_complete( | |||
928 | 937 | ||
929 | complete_to_host = isci_perform_aborted_io_completion; | 938 | complete_to_host = isci_perform_aborted_io_completion; |
930 | /* This was an aborted request. */ | 939 | /* This was an aborted request. */ |
940 | |||
941 | spin_unlock(&request->state_lock); | ||
931 | break; | 942 | break; |
932 | 943 | ||
933 | case aborting: | 944 | case aborting: |
@@ -955,6 +966,8 @@ void isci_request_io_request_complete( | |||
955 | complete_to_host = isci_perform_aborted_io_completion; | 966 | complete_to_host = isci_perform_aborted_io_completion; |
956 | 967 | ||
957 | /* This was an aborted request. */ | 968 | /* This was an aborted request. */ |
969 | |||
970 | spin_unlock(&request->state_lock); | ||
958 | break; | 971 | break; |
959 | 972 | ||
960 | case terminating: | 973 | case terminating: |
@@ -977,13 +990,20 @@ void isci_request_io_request_complete( | |||
977 | else | 990 | else |
978 | status = SAS_ABORTED_TASK; | 991 | status = SAS_ABORTED_TASK; |
979 | 992 | ||
980 | complete_to_host = isci_perform_normal_io_completion; | 993 | complete_to_host = isci_perform_aborted_io_completion; |
981 | 994 | ||
982 | /* This was a terminated request. */ | 995 | /* This was a terminated request. */ |
996 | |||
997 | spin_unlock(&request->state_lock); | ||
983 | break; | 998 | break; |
984 | 999 | ||
985 | default: | 1000 | default: |
986 | 1001 | ||
1002 | /* The request is done from an SCU HW perspective. */ | ||
1003 | request->status = completed; | ||
1004 | |||
1005 | spin_unlock(&request->state_lock); | ||
1006 | |||
987 | /* This is an active request being completed from the core. */ | 1007 | /* This is an active request being completed from the core. */ |
988 | switch (completion_status) { | 1008 | switch (completion_status) { |
989 | 1009 | ||
@@ -1185,20 +1205,6 @@ void isci_request_io_request_complete( | |||
1185 | */ | 1205 | */ |
1186 | request->sci_request_handle = NULL; | 1206 | request->sci_request_handle = NULL; |
1187 | 1207 | ||
1188 | /* Save possible completion ptr. */ | ||
1189 | io_request_completion = request->io_request_completion; | ||
1190 | |||
1191 | if (io_request_completion) { | ||
1192 | |||
1193 | /* This is inherantly a regular I/O request, | ||
1194 | * since we are currently in the regular | ||
1195 | * I/O completion callback function. | ||
1196 | * Signal whoever is waiting that this | ||
1197 | * request is complete. | ||
1198 | */ | ||
1199 | complete(io_request_completion); | ||
1200 | } | ||
1201 | |||
1202 | isci_host_can_dequeue(isci_host, 1); | 1208 | isci_host_can_dequeue(isci_host, 1); |
1203 | } | 1209 | } |
1204 | 1210 | ||