diff options
-rw-r--r-- | drivers/scsi/scsi_error.c | 15 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 20 | ||||
-rw-r--r-- | include/scsi/scsi.h | 1 | ||||
-rw-r--r-- | include/scsi/scsi_transport_fc.h | 2 |
4 files changed, 27 insertions, 11 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index d45c69ca5737..33175974b55a 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -957,9 +957,10 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, | |||
957 | "0x%p\n", current->comm, | 957 | "0x%p\n", current->comm, |
958 | scmd)); | 958 | scmd)); |
959 | rtn = scsi_try_to_abort_cmd(scmd); | 959 | rtn = scsi_try_to_abort_cmd(scmd); |
960 | if (rtn == SUCCESS) { | 960 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { |
961 | scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD; | 961 | scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD; |
962 | if (!scsi_device_online(scmd->device) || | 962 | if (!scsi_device_online(scmd->device) || |
963 | rtn == FAST_IO_FAIL || | ||
963 | !scsi_eh_tur(scmd)) { | 964 | !scsi_eh_tur(scmd)) { |
964 | scsi_eh_finish_cmd(scmd, done_q); | 965 | scsi_eh_finish_cmd(scmd, done_q); |
965 | } | 966 | } |
@@ -1086,8 +1087,9 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, | |||
1086 | " 0x%p\n", current->comm, | 1087 | " 0x%p\n", current->comm, |
1087 | sdev)); | 1088 | sdev)); |
1088 | rtn = scsi_try_bus_device_reset(bdr_scmd); | 1089 | rtn = scsi_try_bus_device_reset(bdr_scmd); |
1089 | if (rtn == SUCCESS) { | 1090 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { |
1090 | if (!scsi_device_online(sdev) || | 1091 | if (!scsi_device_online(sdev) || |
1092 | rtn == FAST_IO_FAIL || | ||
1091 | !scsi_eh_tur(bdr_scmd)) { | 1093 | !scsi_eh_tur(bdr_scmd)) { |
1092 | list_for_each_entry_safe(scmd, next, | 1094 | list_for_each_entry_safe(scmd, next, |
1093 | work_q, eh_entry) { | 1095 | work_q, eh_entry) { |
@@ -1150,10 +1152,11 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, | |||
1150 | "to target %d\n", | 1152 | "to target %d\n", |
1151 | current->comm, id)); | 1153 | current->comm, id)); |
1152 | rtn = scsi_try_target_reset(tgtr_scmd); | 1154 | rtn = scsi_try_target_reset(tgtr_scmd); |
1153 | if (rtn == SUCCESS) { | 1155 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { |
1154 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { | 1156 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { |
1155 | if (id == scmd_id(scmd)) | 1157 | if (id == scmd_id(scmd)) |
1156 | if (!scsi_device_online(scmd->device) || | 1158 | if (!scsi_device_online(scmd->device) || |
1159 | rtn == FAST_IO_FAIL || | ||
1157 | !scsi_eh_tur(tgtr_scmd)) | 1160 | !scsi_eh_tur(tgtr_scmd)) |
1158 | scsi_eh_finish_cmd(scmd, | 1161 | scsi_eh_finish_cmd(scmd, |
1159 | done_q); | 1162 | done_q); |
@@ -1209,10 +1212,11 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, | |||
1209 | " %d\n", current->comm, | 1212 | " %d\n", current->comm, |
1210 | channel)); | 1213 | channel)); |
1211 | rtn = scsi_try_bus_reset(chan_scmd); | 1214 | rtn = scsi_try_bus_reset(chan_scmd); |
1212 | if (rtn == SUCCESS) { | 1215 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { |
1213 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { | 1216 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { |
1214 | if (channel == scmd_channel(scmd)) | 1217 | if (channel == scmd_channel(scmd)) |
1215 | if (!scsi_device_online(scmd->device) || | 1218 | if (!scsi_device_online(scmd->device) || |
1219 | rtn == FAST_IO_FAIL || | ||
1216 | !scsi_eh_tur(scmd)) | 1220 | !scsi_eh_tur(scmd)) |
1217 | scsi_eh_finish_cmd(scmd, | 1221 | scsi_eh_finish_cmd(scmd, |
1218 | done_q); | 1222 | done_q); |
@@ -1246,9 +1250,10 @@ static int scsi_eh_host_reset(struct list_head *work_q, | |||
1246 | , current->comm)); | 1250 | , current->comm)); |
1247 | 1251 | ||
1248 | rtn = scsi_try_host_reset(scmd); | 1252 | rtn = scsi_try_host_reset(scmd); |
1249 | if (rtn == SUCCESS) { | 1253 | if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { |
1250 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { | 1254 | list_for_each_entry_safe(scmd, next, work_q, eh_entry) { |
1251 | if (!scsi_device_online(scmd->device) || | 1255 | if (!scsi_device_online(scmd->device) || |
1256 | rtn == FAST_IO_FAIL || | ||
1252 | (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) || | 1257 | (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) || |
1253 | !scsi_eh_tur(scmd)) | 1258 | !scsi_eh_tur(scmd)) |
1254 | scsi_eh_finish_cmd(scmd, done_q); | 1259 | scsi_eh_finish_cmd(scmd, done_q); |
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 55fe730a8606..06813789145c 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -3197,23 +3197,33 @@ fc_scsi_scan_rport(struct work_struct *work) | |||
3197 | * | 3197 | * |
3198 | * This routine can be called from a FC LLD scsi_eh callback. It | 3198 | * This routine can be called from a FC LLD scsi_eh callback. It |
3199 | * blocks the scsi_eh thread until the fc_rport leaves the | 3199 | * blocks the scsi_eh thread until the fc_rport leaves the |
3200 | * FC_PORTSTATE_BLOCKED. This is necessary to avoid the scsi_eh | 3200 | * FC_PORTSTATE_BLOCKED, or the fast_io_fail_tmo fires. This is |
3201 | * failing recovery actions for blocked rports which would lead to | 3201 | * necessary to avoid the scsi_eh failing recovery actions for blocked |
3202 | * offlined SCSI devices. | 3202 | * rports which would lead to offlined SCSI devices. |
3203 | * | ||
3204 | * Returns: 0 if the fc_rport left the state FC_PORTSTATE_BLOCKED. | ||
3205 | * FAST_IO_FAIL if the fast_io_fail_tmo fired, this should be | ||
3206 | * passed back to scsi_eh. | ||
3203 | */ | 3207 | */ |
3204 | void fc_block_scsi_eh(struct scsi_cmnd *cmnd) | 3208 | int fc_block_scsi_eh(struct scsi_cmnd *cmnd) |
3205 | { | 3209 | { |
3206 | struct Scsi_Host *shost = cmnd->device->host; | 3210 | struct Scsi_Host *shost = cmnd->device->host; |
3207 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); | 3211 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); |
3208 | unsigned long flags; | 3212 | unsigned long flags; |
3209 | 3213 | ||
3210 | spin_lock_irqsave(shost->host_lock, flags); | 3214 | spin_lock_irqsave(shost->host_lock, flags); |
3211 | while (rport->port_state == FC_PORTSTATE_BLOCKED) { | 3215 | while (rport->port_state == FC_PORTSTATE_BLOCKED && |
3216 | !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) { | ||
3212 | spin_unlock_irqrestore(shost->host_lock, flags); | 3217 | spin_unlock_irqrestore(shost->host_lock, flags); |
3213 | msleep(1000); | 3218 | msleep(1000); |
3214 | spin_lock_irqsave(shost->host_lock, flags); | 3219 | spin_lock_irqsave(shost->host_lock, flags); |
3215 | } | 3220 | } |
3216 | spin_unlock_irqrestore(shost->host_lock, flags); | 3221 | spin_unlock_irqrestore(shost->host_lock, flags); |
3222 | |||
3223 | if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) | ||
3224 | return FAST_IO_FAIL; | ||
3225 | |||
3226 | return 0; | ||
3217 | } | 3227 | } |
3218 | EXPORT_SYMBOL(fc_block_scsi_eh); | 3228 | EXPORT_SYMBOL(fc_block_scsi_eh); |
3219 | 3229 | ||
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 8b4deca996ad..832f41f37385 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h | |||
@@ -423,6 +423,7 @@ static inline int scsi_is_wlun(unsigned int lun) | |||
423 | #define ADD_TO_MLQUEUE 0x2006 | 423 | #define ADD_TO_MLQUEUE 0x2006 |
424 | #define TIMEOUT_ERROR 0x2007 | 424 | #define TIMEOUT_ERROR 0x2007 |
425 | #define SCSI_RETURN_NOT_HANDLED 0x2008 | 425 | #define SCSI_RETURN_NOT_HANDLED 0x2008 |
426 | #define FAST_IO_FAIL 0x2009 | ||
426 | 427 | ||
427 | /* | 428 | /* |
428 | * Midlevel queue return values. | 429 | * Midlevel queue return values. |
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 8e86a94faf06..87d81b3ce564 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h | |||
@@ -807,6 +807,6 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, | |||
807 | struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel, | 807 | struct fc_vport *fc_vport_create(struct Scsi_Host *shost, int channel, |
808 | struct fc_vport_identifiers *); | 808 | struct fc_vport_identifiers *); |
809 | int fc_vport_terminate(struct fc_vport *vport); | 809 | int fc_vport_terminate(struct fc_vport *vport); |
810 | void fc_block_scsi_eh(struct scsi_cmnd *cmnd); | 810 | int fc_block_scsi_eh(struct scsi_cmnd *cmnd); |
811 | 811 | ||
812 | #endif /* SCSI_TRANSPORT_FC_H */ | 812 | #endif /* SCSI_TRANSPORT_FC_H */ |