diff options
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r-- | drivers/scsi/scsi_error.c | 87 |
1 files changed, 67 insertions, 20 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index abea2cf05c2e..a4b9cdbaaa0b 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -50,6 +50,8 @@ | |||
50 | #define BUS_RESET_SETTLE_TIME (10) | 50 | #define BUS_RESET_SETTLE_TIME (10) |
51 | #define HOST_RESET_SETTLE_TIME (10) | 51 | #define HOST_RESET_SETTLE_TIME (10) |
52 | 52 | ||
53 | static int scsi_eh_try_stu(struct scsi_cmnd *scmd); | ||
54 | |||
53 | /* called with shost->host_lock held */ | 55 | /* called with shost->host_lock held */ |
54 | void scsi_eh_wakeup(struct Scsi_Host *shost) | 56 | void scsi_eh_wakeup(struct Scsi_Host *shost) |
55 | { | 57 | { |
@@ -947,6 +949,48 @@ retry_tur: | |||
947 | } | 949 | } |
948 | 950 | ||
949 | /** | 951 | /** |
952 | * scsi_eh_test_devices - check if devices are responding from error recovery. | ||
953 | * @cmd_list: scsi commands in error recovery. | ||
954 | * @work_q: queue for commands which still need more error recovery | ||
955 | * @done_q: queue for commands which are finished | ||
956 | * @try_stu: boolean on if a STU command should be tried in addition to TUR. | ||
957 | * | ||
958 | * Decription: | ||
959 | * Tests if devices are in a working state. Commands to devices now in | ||
960 | * a working state are sent to the done_q while commands to devices which | ||
961 | * are still failing to respond are returned to the work_q for more | ||
962 | * processing. | ||
963 | **/ | ||
964 | static int scsi_eh_test_devices(struct list_head *cmd_list, | ||
965 | struct list_head *work_q, | ||
966 | struct list_head *done_q, int try_stu) | ||
967 | { | ||
968 | struct scsi_cmnd *scmd, *next; | ||
969 | struct scsi_device *sdev; | ||
970 | int finish_cmds; | ||
971 | |||
972 | while (!list_empty(cmd_list)) { | ||
973 | scmd = list_entry(cmd_list->next, struct scsi_cmnd, eh_entry); | ||
974 | sdev = scmd->device; | ||
975 | |||
976 | finish_cmds = !scsi_device_online(scmd->device) || | ||
977 | (try_stu && !scsi_eh_try_stu(scmd) && | ||
978 | !scsi_eh_tur(scmd)) || | ||
979 | !scsi_eh_tur(scmd); | ||
980 | |||
981 | list_for_each_entry_safe(scmd, next, cmd_list, eh_entry) | ||
982 | if (scmd->device == sdev) { | ||
983 | if (finish_cmds) | ||
984 | scsi_eh_finish_cmd(scmd, done_q); | ||
985 | else | ||
986 | list_move_tail(&scmd->eh_entry, work_q); | ||
987 | } | ||
988 | } | ||
989 | return list_empty(work_q); | ||
990 | } | ||
991 | |||
992 | |||
993 | /** | ||
950 | * scsi_eh_abort_cmds - abort pending commands. | 994 | * scsi_eh_abort_cmds - abort pending commands. |
951 | * @work_q: &list_head for pending commands. | 995 | * @work_q: &list_head for pending commands. |
952 | * @done_q: &list_head for processed commands. | 996 | * @done_q: &list_head for processed commands. |
@@ -962,6 +1006,7 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, | |||
962 | struct list_head *done_q) | 1006 | struct list_head *done_q) |
963 | { | 1007 | { |
964 | struct scsi_cmnd *scmd, *next; | 1008 | struct scsi_cmnd *scmd, *next; |
1009 | LIST_HEAD(check_list); | ||
965 | int rtn; | 1010 | int rtn; |
966 | 1011 | ||
967 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { | 1012 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { |
@@ -973,11 +1018,10 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, | |||
973 | rtn = scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd); | 1018 | rtn = scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd); |
974 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { | 1019 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { |
975 | scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD; | 1020 | scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD; |
976 | if (!scsi_device_online(scmd->device) || | 1021 | if (rtn == FAST_IO_FAIL) |
977 | rtn == FAST_IO_FAIL || | ||
978 | !scsi_eh_tur(scmd)) { | ||
979 | scsi_eh_finish_cmd(scmd, done_q); | 1022 | scsi_eh_finish_cmd(scmd, done_q); |
980 | } | 1023 | else |
1024 | list_move_tail(&scmd->eh_entry, &check_list); | ||
981 | } else | 1025 | } else |
982 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting" | 1026 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting" |
983 | " cmd failed:" | 1027 | " cmd failed:" |
@@ -986,7 +1030,7 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, | |||
986 | scmd)); | 1030 | scmd)); |
987 | } | 1031 | } |
988 | 1032 | ||
989 | return list_empty(work_q); | 1033 | return scsi_eh_test_devices(&check_list, work_q, done_q, 0); |
990 | } | 1034 | } |
991 | 1035 | ||
992 | /** | 1036 | /** |
@@ -1137,6 +1181,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, | |||
1137 | struct list_head *done_q) | 1181 | struct list_head *done_q) |
1138 | { | 1182 | { |
1139 | LIST_HEAD(tmp_list); | 1183 | LIST_HEAD(tmp_list); |
1184 | LIST_HEAD(check_list); | ||
1140 | 1185 | ||
1141 | list_splice_init(work_q, &tmp_list); | 1186 | list_splice_init(work_q, &tmp_list); |
1142 | 1187 | ||
@@ -1161,9 +1206,9 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, | |||
1161 | if (scmd_id(scmd) != id) | 1206 | if (scmd_id(scmd) != id) |
1162 | continue; | 1207 | continue; |
1163 | 1208 | ||
1164 | if ((rtn == SUCCESS || rtn == FAST_IO_FAIL) | 1209 | if (rtn == SUCCESS) |
1165 | && (!scsi_device_online(scmd->device) || | 1210 | list_move_tail(&scmd->eh_entry, &check_list); |
1166 | rtn == FAST_IO_FAIL || !scsi_eh_tur(scmd))) | 1211 | else if (rtn == FAST_IO_FAIL) |
1167 | scsi_eh_finish_cmd(scmd, done_q); | 1212 | scsi_eh_finish_cmd(scmd, done_q); |
1168 | else | 1213 | else |
1169 | /* push back on work queue for further processing */ | 1214 | /* push back on work queue for further processing */ |
@@ -1171,7 +1216,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, | |||
1171 | } | 1216 | } |
1172 | } | 1217 | } |
1173 | 1218 | ||
1174 | return list_empty(work_q); | 1219 | return scsi_eh_test_devices(&check_list, work_q, done_q, 0); |
1175 | } | 1220 | } |
1176 | 1221 | ||
1177 | /** | 1222 | /** |
@@ -1185,6 +1230,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, | |||
1185 | struct list_head *done_q) | 1230 | struct list_head *done_q) |
1186 | { | 1231 | { |
1187 | struct scsi_cmnd *scmd, *chan_scmd, *next; | 1232 | struct scsi_cmnd *scmd, *chan_scmd, *next; |
1233 | LIST_HEAD(check_list); | ||
1188 | unsigned int channel; | 1234 | unsigned int channel; |
1189 | int rtn; | 1235 | int rtn; |
1190 | 1236 | ||
@@ -1216,12 +1262,14 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, | |||
1216 | rtn = scsi_try_bus_reset(chan_scmd); | 1262 | rtn = scsi_try_bus_reset(chan_scmd); |
1217 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { | 1263 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { |
1218 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { | 1264 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { |
1219 | if (channel == scmd_channel(scmd)) | 1265 | if (channel == scmd_channel(scmd)) { |
1220 | if (!scsi_device_online(scmd->device) || | 1266 | if (rtn == FAST_IO_FAIL) |
1221 | rtn == FAST_IO_FAIL || | ||
1222 | !scsi_eh_tur(scmd)) | ||
1223 | scsi_eh_finish_cmd(scmd, | 1267 | scsi_eh_finish_cmd(scmd, |
1224 | done_q); | 1268 | done_q); |
1269 | else | ||
1270 | list_move_tail(&scmd->eh_entry, | ||
1271 | &check_list); | ||
1272 | } | ||
1225 | } | 1273 | } |
1226 | } else { | 1274 | } else { |
1227 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST" | 1275 | SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST" |
@@ -1230,7 +1278,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, | |||
1230 | channel)); | 1278 | channel)); |
1231 | } | 1279 | } |
1232 | } | 1280 | } |
1233 | return list_empty(work_q); | 1281 | return scsi_eh_test_devices(&check_list, work_q, done_q, 0); |
1234 | } | 1282 | } |
1235 | 1283 | ||
1236 | /** | 1284 | /** |
@@ -1242,6 +1290,7 @@ static int scsi_eh_host_reset(struct list_head *work_q, | |||
1242 | struct list_head *done_q) | 1290 | struct list_head *done_q) |
1243 | { | 1291 | { |
1244 | struct scsi_cmnd *scmd, *next; | 1292 | struct scsi_cmnd *scmd, *next; |
1293 | LIST_HEAD(check_list); | ||
1245 | int rtn; | 1294 | int rtn; |
1246 | 1295 | ||
1247 | if (!list_empty(work_q)) { | 1296 | if (!list_empty(work_q)) { |
@@ -1252,12 +1301,10 @@ static int scsi_eh_host_reset(struct list_head *work_q, | |||
1252 | , current->comm)); | 1301 | , current->comm)); |
1253 | 1302 | ||
1254 | rtn = scsi_try_host_reset(scmd); | 1303 | rtn = scsi_try_host_reset(scmd); |
1255 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { | 1304 | if (rtn == SUCCESS) { |
1305 | list_splice_init(work_q, &check_list); | ||
1306 | } else if (rtn == FAST_IO_FAIL) { | ||
1256 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { | 1307 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { |
1257 | if (!scsi_device_online(scmd->device) || | ||
1258 | rtn == FAST_IO_FAIL || | ||
1259 | (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) || | ||
1260 | !scsi_eh_tur(scmd)) | ||
1261 | scsi_eh_finish_cmd(scmd, done_q); | 1308 | scsi_eh_finish_cmd(scmd, done_q); |
1262 | } | 1309 | } |
1263 | } else { | 1310 | } else { |
@@ -1266,7 +1313,7 @@ static int scsi_eh_host_reset(struct list_head *work_q, | |||
1266 | current->comm)); | 1313 | current->comm)); |
1267 | } | 1314 | } |
1268 | } | 1315 | } |
1269 | return list_empty(work_q); | 1316 | return scsi_eh_test_devices(&check_list, work_q, done_q, 1); |
1270 | } | 1317 | } |
1271 | 1318 | ||
1272 | /** | 1319 | /** |