aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2010-03-24 11:50:30 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-04-11 10:49:33 -0400
commit2f2eb58762b4dcddfe25c90800323765c1257eca (patch)
treef69788ac1afc0b7924a033cb82f33dbc55b6af1c /drivers
parent7794a5af67c672d44cfdbc7172a608b7542a66e3 (diff)
[SCSI] Allow FC LLD to fast-fail scsi eh by introducing new eh return
If the scsi eh is running and then a FC LLD calls fc_remote_port_delete, the SCSI commands sent from the eh will fail. To prevent this, a FC LLD can call fc_block_scsi_eh from the eh callback, blocking the eh thread until the dev_loss_tmo fires or the remote port is available again. If (e.g. for a multipathing setup) the dev_loss_tmo is set to a very large value, thus preventing the scsi device removal , the scsi eh can block for a long time. For multipathing, the fast_io_fail_tmo is then set to a low value to detect path problems sooner. This patch introduces a new return code FAST_IO_FAIL. The function fc_block_scsi_eh now returns FAST_IO_FAIL when the fast_io_fail_tmo fires. This indicates that the LLD terminated all pending I/O requests and there are no more pending SCSI commands for the scsi eh to wait for. This return code can be passed back to the scsi eh to stop the escalation and finish the recovery process for this device. Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/scsi_error.c15
-rw-r--r--drivers/scsi/scsi_transport_fc.c20
2 files changed, 25 insertions, 10 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 */
3204void fc_block_scsi_eh(struct scsi_cmnd *cmnd) 3208int 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}
3218EXPORT_SYMBOL(fc_block_scsi_eh); 3228EXPORT_SYMBOL(fc_block_scsi_eh);
3219 3229