diff options
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r-- | drivers/scsi/isci/remote_device.c | 47 | ||||
-rw-r--r-- | drivers/scsi/isci/remote_device.h | 2 | ||||
-rw-r--r-- | drivers/scsi/isci/task.c | 169 | ||||
-rw-r--r-- | drivers/scsi/isci/task.h | 33 |
4 files changed, 67 insertions, 184 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index fbf9ce28c3f5..20c77edd4711 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c | |||
@@ -1438,53 +1438,6 @@ int isci_remote_device_found(struct domain_device *domain_dev) | |||
1438 | 1438 | ||
1439 | return status == SCI_SUCCESS ? 0 : -ENODEV; | 1439 | return status == SCI_SUCCESS ? 0 : -ENODEV; |
1440 | } | 1440 | } |
1441 | /** | ||
1442 | * isci_device_is_reset_pending() - This function will check if there is any | ||
1443 | * pending reset condition on the device. | ||
1444 | * @request: This parameter is the isci_device object. | ||
1445 | * | ||
1446 | * true if there is a reset pending for the device. | ||
1447 | */ | ||
1448 | bool isci_device_is_reset_pending( | ||
1449 | struct isci_host *isci_host, | ||
1450 | struct isci_remote_device *isci_device) | ||
1451 | { | ||
1452 | struct isci_request *isci_request; | ||
1453 | struct isci_request *tmp_req; | ||
1454 | bool reset_is_pending = false; | ||
1455 | unsigned long flags; | ||
1456 | |||
1457 | dev_dbg(&isci_host->pdev->dev, | ||
1458 | "%s: isci_device = %p\n", __func__, isci_device); | ||
1459 | |||
1460 | spin_lock_irqsave(&isci_host->scic_lock, flags); | ||
1461 | |||
1462 | /* Check for reset on all pending requests. */ | ||
1463 | list_for_each_entry_safe(isci_request, tmp_req, | ||
1464 | &isci_device->reqs_in_process, dev_node) { | ||
1465 | dev_dbg(&isci_host->pdev->dev, | ||
1466 | "%s: isci_device = %p request = %p\n", | ||
1467 | __func__, isci_device, isci_request); | ||
1468 | |||
1469 | if (isci_request->ttype == io_task) { | ||
1470 | struct sas_task *task = isci_request_access_task( | ||
1471 | isci_request); | ||
1472 | |||
1473 | spin_lock(&task->task_state_lock); | ||
1474 | if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) | ||
1475 | reset_is_pending = true; | ||
1476 | spin_unlock(&task->task_state_lock); | ||
1477 | } | ||
1478 | } | ||
1479 | |||
1480 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | ||
1481 | |||
1482 | dev_dbg(&isci_host->pdev->dev, | ||
1483 | "%s: isci_device = %p reset_is_pending = %d\n", | ||
1484 | __func__, isci_device, reset_is_pending); | ||
1485 | |||
1486 | return reset_is_pending; | ||
1487 | } | ||
1488 | 1441 | ||
1489 | /** | 1442 | /** |
1490 | * isci_device_clear_reset_pending() - This function will clear if any pending | 1443 | * isci_device_clear_reset_pending() - This function will clear if any pending |
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h index e1747ea0d0ea..bee6dd2d0fe7 100644 --- a/drivers/scsi/isci/remote_device.h +++ b/drivers/scsi/isci/remote_device.h | |||
@@ -132,8 +132,6 @@ void isci_remote_device_nuke_requests(struct isci_host *ihost, | |||
132 | struct isci_remote_device *idev); | 132 | struct isci_remote_device *idev); |
133 | void isci_remote_device_gone(struct domain_device *domain_dev); | 133 | void isci_remote_device_gone(struct domain_device *domain_dev); |
134 | int isci_remote_device_found(struct domain_device *domain_dev); | 134 | int isci_remote_device_found(struct domain_device *domain_dev); |
135 | bool isci_device_is_reset_pending(struct isci_host *ihost, | ||
136 | struct isci_remote_device *idev); | ||
137 | void isci_device_clear_reset_pending(struct isci_host *ihost, | 135 | void isci_device_clear_reset_pending(struct isci_host *ihost, |
138 | struct isci_remote_device *idev); | 136 | struct isci_remote_device *idev); |
139 | /** | 137 | /** |
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c1f439bed717..ec85beb1f979 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c | |||
@@ -920,22 +920,14 @@ int isci_task_lu_reset(struct domain_device *domain_device, u8 *lun) | |||
920 | "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", | 920 | "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", |
921 | __func__, domain_device, isci_host, isci_device); | 921 | __func__, domain_device, isci_host, isci_device); |
922 | 922 | ||
923 | if (isci_device) | 923 | if (!isci_device) { |
924 | set_bit(IDEV_EH, &isci_device->flags); | 924 | /* If the device is gone, stop the escalations. */ |
925 | dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__); | ||
925 | 926 | ||
926 | /* If there is a device reset pending on any request in the | 927 | ret = TMF_RESP_FUNC_COMPLETE; |
927 | * device's list, fail this LUN reset request in order to | ||
928 | * escalate to the device reset. | ||
929 | */ | ||
930 | if (!isci_device || | ||
931 | isci_device_is_reset_pending(isci_host, isci_device)) { | ||
932 | dev_dbg(&isci_host->pdev->dev, | ||
933 | "%s: No dev (%p), or " | ||
934 | "RESET PENDING: domain_device=%p\n", | ||
935 | __func__, isci_device, domain_device); | ||
936 | ret = TMF_RESP_FUNC_FAILED; | ||
937 | goto out; | 928 | goto out; |
938 | } | 929 | } |
930 | set_bit(IDEV_EH, &isci_device->flags); | ||
939 | 931 | ||
940 | /* Send the task management part of the reset. */ | 932 | /* Send the task management part of the reset. */ |
941 | if (sas_protocol_ata(domain_device->tproto)) { | 933 | if (sas_protocol_ata(domain_device->tproto)) { |
@@ -1044,7 +1036,7 @@ int isci_task_abort_task(struct sas_task *task) | |||
1044 | struct isci_tmf tmf; | 1036 | struct isci_tmf tmf; |
1045 | int ret = TMF_RESP_FUNC_FAILED; | 1037 | int ret = TMF_RESP_FUNC_FAILED; |
1046 | unsigned long flags; | 1038 | unsigned long flags; |
1047 | bool any_dev_reset = false; | 1039 | int perform_termination = 0; |
1048 | 1040 | ||
1049 | /* Get the isci_request reference from the task. Note that | 1041 | /* Get the isci_request reference from the task. Note that |
1050 | * this check does not depend on the pending request list | 1042 | * this check does not depend on the pending request list |
@@ -1066,89 +1058,34 @@ int isci_task_abort_task(struct sas_task *task) | |||
1066 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | 1058 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); |
1067 | 1059 | ||
1068 | dev_dbg(&isci_host->pdev->dev, | 1060 | dev_dbg(&isci_host->pdev->dev, |
1069 | "%s: task = %p\n", __func__, task); | 1061 | "%s: dev = %p, task = %p, old_request == %p\n", |
1070 | 1062 | __func__, isci_device, task, old_request); | |
1071 | if (!isci_device || !old_request) | ||
1072 | goto out; | ||
1073 | 1063 | ||
1074 | set_bit(IDEV_EH, &isci_device->flags); | 1064 | if (isci_device) |
1075 | 1065 | set_bit(IDEV_EH, &isci_device->flags); | |
1076 | /* This version of the driver will fail abort requests for | ||
1077 | * SATA/STP. Failing the abort request this way will cause the | ||
1078 | * SCSI error handler thread to escalate to LUN reset | ||
1079 | */ | ||
1080 | if (sas_protocol_ata(task->task_proto)) { | ||
1081 | dev_dbg(&isci_host->pdev->dev, | ||
1082 | " task %p is for a STP/SATA device;" | ||
1083 | " returning TMF_RESP_FUNC_FAILED\n" | ||
1084 | " to cause a LUN reset...\n", task); | ||
1085 | goto out; | ||
1086 | } | ||
1087 | |||
1088 | dev_dbg(&isci_host->pdev->dev, | ||
1089 | "%s: old_request == %p\n", __func__, old_request); | ||
1090 | |||
1091 | any_dev_reset = isci_device_is_reset_pending(isci_host, isci_device); | ||
1092 | |||
1093 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
1094 | |||
1095 | any_dev_reset = any_dev_reset || (task->task_state_flags & SAS_TASK_NEED_DEV_RESET); | ||
1096 | 1066 | ||
1097 | /* If the extraction of the request reference from the task | 1067 | /* Device reset conditions signalled in task_state_flags are the |
1098 | * failed, then the request has been completed (or if there is a | 1068 | * responsbility of libsas to observe at the start of the error |
1099 | * pending reset then this abort request function must be failed | 1069 | * handler thread. |
1100 | * in order to escalate to the target reset). | ||
1101 | */ | 1070 | */ |
1102 | if ((old_request == NULL) || any_dev_reset) { | 1071 | if (!isci_device || !old_request) { |
1103 | 1072 | /* The request has already completed and there | |
1104 | /* If the device reset task flag is set, fail the task | 1073 | * is nothing to do here other than to set the task |
1105 | * management request. Otherwise, the original request | 1074 | * done bit, and indicate that the task abort function |
1106 | * has completed. | 1075 | * was sucessful. |
1107 | */ | 1076 | */ |
1108 | if (any_dev_reset) { | 1077 | spin_lock_irqsave(&task->task_state_lock, flags); |
1109 | 1078 | task->task_state_flags |= SAS_TASK_STATE_DONE; | |
1110 | /* Turn off the task's DONE to make sure this | 1079 | task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | |
1111 | * task is escalated to a target reset. | 1080 | SAS_TASK_STATE_PENDING); |
1112 | */ | 1081 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
1113 | task->task_state_flags &= ~SAS_TASK_STATE_DONE; | ||
1114 | |||
1115 | /* Make the reset happen as soon as possible. */ | ||
1116 | task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; | ||
1117 | |||
1118 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1119 | |||
1120 | /* Fail the task management request in order to | ||
1121 | * escalate to the target reset. | ||
1122 | */ | ||
1123 | ret = TMF_RESP_FUNC_FAILED; | ||
1124 | |||
1125 | dev_dbg(&isci_host->pdev->dev, | ||
1126 | "%s: Failing task abort in order to " | ||
1127 | "escalate to target reset because\n" | ||
1128 | "SAS_TASK_NEED_DEV_RESET is set for " | ||
1129 | "task %p on dev %p\n", | ||
1130 | __func__, task, isci_device); | ||
1131 | |||
1132 | |||
1133 | } else { | ||
1134 | /* The request has already completed and there | ||
1135 | * is nothing to do here other than to set the task | ||
1136 | * done bit, and indicate that the task abort function | ||
1137 | * was sucessful. | ||
1138 | */ | ||
1139 | isci_set_task_doneflags(task); | ||
1140 | |||
1141 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1142 | 1082 | ||
1143 | ret = TMF_RESP_FUNC_COMPLETE; | 1083 | ret = TMF_RESP_FUNC_COMPLETE; |
1144 | 1084 | ||
1145 | dev_dbg(&isci_host->pdev->dev, | 1085 | dev_dbg(&isci_host->pdev->dev, |
1146 | "%s: abort task not needed for %p\n", | 1086 | "%s: abort task not needed for %p\n", |
1147 | __func__, task); | 1087 | __func__, task); |
1148 | } | ||
1149 | goto out; | 1088 | goto out; |
1150 | } else { | ||
1151 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1152 | } | 1089 | } |
1153 | 1090 | ||
1154 | spin_lock_irqsave(&isci_host->scic_lock, flags); | 1091 | spin_lock_irqsave(&isci_host->scic_lock, flags); |
@@ -1177,24 +1114,44 @@ int isci_task_abort_task(struct sas_task *task) | |||
1177 | goto out; | 1114 | goto out; |
1178 | } | 1115 | } |
1179 | if (task->task_proto == SAS_PROTOCOL_SMP || | 1116 | if (task->task_proto == SAS_PROTOCOL_SMP || |
1117 | sas_protocol_ata(task->task_proto) || | ||
1180 | test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { | 1118 | test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { |
1181 | 1119 | ||
1182 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | 1120 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); |
1183 | 1121 | ||
1184 | dev_dbg(&isci_host->pdev->dev, | 1122 | dev_dbg(&isci_host->pdev->dev, |
1185 | "%s: SMP request (%d)" | 1123 | "%s: %s request" |
1186 | " or complete_in_target (%d), thus no TMF\n", | 1124 | " or complete_in_target (%d), thus no TMF\n", |
1187 | __func__, (task->task_proto == SAS_PROTOCOL_SMP), | 1125 | __func__, |
1126 | ((task->task_proto == SAS_PROTOCOL_SMP) | ||
1127 | ? "SMP" | ||
1128 | : (sas_protocol_ata(task->task_proto) | ||
1129 | ? "SATA/STP" | ||
1130 | : "<other>") | ||
1131 | ), | ||
1188 | test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)); | 1132 | test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)); |
1189 | 1133 | ||
1190 | /* Set the state on the task. */ | 1134 | if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { |
1191 | isci_task_all_done(task); | 1135 | spin_lock_irqsave(&task->task_state_lock, flags); |
1192 | 1136 | task->task_state_flags |= SAS_TASK_STATE_DONE; | |
1193 | ret = TMF_RESP_FUNC_COMPLETE; | 1137 | task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | |
1138 | SAS_TASK_STATE_PENDING); | ||
1139 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1140 | ret = TMF_RESP_FUNC_COMPLETE; | ||
1141 | } else { | ||
1142 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
1143 | task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | | ||
1144 | SAS_TASK_STATE_PENDING); | ||
1145 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1146 | } | ||
1194 | 1147 | ||
1195 | /* Stopping and SMP devices are not sent a TMF, and are not | 1148 | /* STP and SMP devices are not sent a TMF, but the |
1196 | * reset, but the outstanding I/O request is terminated below. | 1149 | * outstanding I/O request is terminated below. This is |
1150 | * because SATA/STP and SMP discovery path timeouts directly | ||
1151 | * call the abort task interface for cleanup. | ||
1197 | */ | 1152 | */ |
1153 | perform_termination = 1; | ||
1154 | |||
1198 | } else { | 1155 | } else { |
1199 | /* Fill in the tmf stucture */ | 1156 | /* Fill in the tmf stucture */ |
1200 | isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort, | 1157 | isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort, |
@@ -1203,22 +1160,24 @@ int isci_task_abort_task(struct sas_task *task) | |||
1203 | 1160 | ||
1204 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); | 1161 | spin_unlock_irqrestore(&isci_host->scic_lock, flags); |
1205 | 1162 | ||
1206 | #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* half second timeout. */ | 1163 | #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */ |
1207 | ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, | 1164 | ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, |
1208 | ISCI_ABORT_TASK_TIMEOUT_MS); | 1165 | ISCI_ABORT_TASK_TIMEOUT_MS); |
1209 | 1166 | ||
1210 | if (ret != TMF_RESP_FUNC_COMPLETE) | 1167 | if (ret == TMF_RESP_FUNC_COMPLETE) |
1168 | perform_termination = 1; | ||
1169 | else | ||
1211 | dev_dbg(&isci_host->pdev->dev, | 1170 | dev_dbg(&isci_host->pdev->dev, |
1212 | "%s: isci_task_send_tmf failed\n", | 1171 | "%s: isci_task_send_tmf failed\n", __func__); |
1213 | __func__); | ||
1214 | } | 1172 | } |
1215 | if (ret == TMF_RESP_FUNC_COMPLETE) { | 1173 | if (perform_termination) { |
1216 | set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags); | 1174 | set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags); |
1217 | 1175 | ||
1218 | /* Clean up the request on our side, and wait for the aborted | 1176 | /* Clean up the request on our side, and wait for the aborted |
1219 | * I/O to complete. | 1177 | * I/O to complete. |
1220 | */ | 1178 | */ |
1221 | isci_terminate_request_core(isci_host, isci_device, old_request); | 1179 | isci_terminate_request_core(isci_host, isci_device, |
1180 | old_request); | ||
1222 | } | 1181 | } |
1223 | 1182 | ||
1224 | /* Make sure we do not leave a reference to aborted_io_completion */ | 1183 | /* Make sure we do not leave a reference to aborted_io_completion */ |
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index c9ccd0b5ff53..bc78c0a41d5c 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h | |||
@@ -226,35 +226,6 @@ enum isci_completion_selection { | |||
226 | isci_perform_error_io_completion /* Use sas_task_abort */ | 226 | isci_perform_error_io_completion /* Use sas_task_abort */ |
227 | }; | 227 | }; |
228 | 228 | ||
229 | static inline void isci_set_task_doneflags( | ||
230 | struct sas_task *task) | ||
231 | { | ||
232 | /* Since no futher action will be taken on this task, | ||
233 | * make sure to mark it complete from the lldd perspective. | ||
234 | */ | ||
235 | task->task_state_flags |= SAS_TASK_STATE_DONE; | ||
236 | task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; | ||
237 | task->task_state_flags &= ~SAS_TASK_STATE_PENDING; | ||
238 | } | ||
239 | /** | ||
240 | * isci_task_all_done() - This function clears the task bits to indicate the | ||
241 | * LLDD is done with the task. | ||
242 | * | ||
243 | * | ||
244 | */ | ||
245 | static inline void isci_task_all_done( | ||
246 | struct sas_task *task) | ||
247 | { | ||
248 | unsigned long flags; | ||
249 | |||
250 | /* Since no futher action will be taken on this task, | ||
251 | * make sure to mark it complete from the lldd perspective. | ||
252 | */ | ||
253 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
254 | isci_set_task_doneflags(task); | ||
255 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
256 | } | ||
257 | |||
258 | /** | 229 | /** |
259 | * isci_task_set_completion_status() - This function sets the completion status | 230 | * isci_task_set_completion_status() - This function sets the completion status |
260 | * for the request. | 231 | * for the request. |
@@ -336,7 +307,9 @@ isci_task_set_completion_status( | |||
336 | /* Fall through to the normal case... */ | 307 | /* Fall through to the normal case... */ |
337 | case isci_perform_normal_io_completion: | 308 | case isci_perform_normal_io_completion: |
338 | /* Normal notification (task_done) */ | 309 | /* Normal notification (task_done) */ |
339 | isci_set_task_doneflags(task); | 310 | task->task_state_flags |= SAS_TASK_STATE_DONE; |
311 | task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | | ||
312 | SAS_TASK_STATE_PENDING); | ||
340 | break; | 313 | break; |
341 | default: | 314 | default: |
342 | WARN_ONCE(1, "unknown task_notification_selection: %d\n", | 315 | WARN_ONCE(1, "unknown task_notification_selection: %d\n", |