aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/scsi_error.c9
-rw-r--r--drivers/scsi/scsi_transport_fc.c37
-rw-r--r--include/scsi/scsi_host.h14
-rw-r--r--include/scsi/scsi_transport.h11
4 files changed, 51 insertions, 20 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 5cc97b721661..9cf020622134 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -29,6 +29,7 @@
29#include <scsi/scsi_dbg.h> 29#include <scsi/scsi_dbg.h>
30#include <scsi/scsi_device.h> 30#include <scsi/scsi_device.h>
31#include <scsi/scsi_eh.h> 31#include <scsi/scsi_eh.h>
32#include <scsi/scsi_transport.h>
32#include <scsi/scsi_host.h> 33#include <scsi/scsi_host.h>
33#include <scsi/scsi_ioctl.h> 34#include <scsi/scsi_ioctl.h>
34#include <scsi/scsi_request.h> 35#include <scsi/scsi_request.h>
@@ -163,16 +164,12 @@ void scsi_times_out(struct scsi_cmnd *scmd)
163{ 164{
164 scsi_log_completion(scmd, TIMEOUT_ERROR); 165 scsi_log_completion(scmd, TIMEOUT_ERROR);
165 166
166 if (scmd->device->host->hostt->eh_timed_out) 167 if (scmd->device->host->transportt->eh_timed_out)
167 switch (scmd->device->host->hostt->eh_timed_out(scmd)) { 168 switch (scmd->device->host->transportt->eh_timed_out(scmd)) {
168 case EH_HANDLED: 169 case EH_HANDLED:
169 __scsi_done(scmd); 170 __scsi_done(scmd);
170 return; 171 return;
171 case EH_RESET_TIMER: 172 case EH_RESET_TIMER:
172 /* This allows a single retry even of a command
173 * with allowed == 0 */
174 if (scmd->retries++ > scmd->allowed)
175 break;
176 scsi_add_timer(scmd, scmd->timeout_per_command, 173 scsi_add_timer(scmd, scmd->timeout_per_command,
177 scsi_times_out); 174 scsi_times_out);
178 return; 175 return;
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 56012b2694d2..3c3baa9f5f28 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -31,6 +31,7 @@
31#include <scsi/scsi_host.h> 31#include <scsi/scsi_host.h>
32#include <scsi/scsi_transport.h> 32#include <scsi/scsi_transport.h>
33#include <scsi/scsi_transport_fc.h> 33#include <scsi/scsi_transport_fc.h>
34#include <scsi/scsi_cmnd.h>
34#include "scsi_priv.h" 35#include "scsi_priv.h"
35 36
36/* 37/*
@@ -1090,6 +1091,40 @@ static int fc_rport_match(struct attribute_container *cont,
1090} 1091}
1091 1092
1092 1093
1094/**
1095 * fc_timed_out - FC Transport I/O timeout intercept handler
1096 *
1097 * @scmd: The SCSI command which timed out
1098 *
1099 * This routine protects against error handlers getting invoked while a
1100 * rport is in a blocked state, typically due to a temporarily loss of
1101 * connectivity. If the error handlers are allowed to proceed, requests
1102 * to abort i/o, reset the target, etc will likely fail as there is no way
1103 * to communicate with the device to perform the requested function. These
1104 * failures may result in the midlayer taking the device offline, requiring
1105 * manual intervention to restore operation.
1106 *
1107 * This routine, called whenever an i/o times out, validates the state of
1108 * the underlying rport. If the rport is blocked, it returns
1109 * EH_RESET_TIMER, which will continue to reschedule the timeout.
1110 * Eventually, either the device will return, or devloss_tmo will fire,
1111 * and when the timeout then fires, it will be handled normally.
1112 * If the rport is not blocked, normal error handling continues.
1113 *
1114 * Notes:
1115 * This routine assumes no locks are held on entry.
1116 **/
1117static enum scsi_eh_timer_return
1118fc_timed_out(struct scsi_cmnd *scmd)
1119{
1120 struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
1121
1122 if (rport->port_state == FC_PORTSTATE_BLOCKED)
1123 return EH_RESET_TIMER;
1124
1125 return EH_NOT_HANDLED;
1126}
1127
1093/* 1128/*
1094 * Must be called with shost->host_lock held 1129 * Must be called with shost->host_lock held
1095 */ 1130 */
@@ -1146,6 +1181,8 @@ fc_attach_transport(struct fc_function_template *ft)
1146 /* Transport uses the shost workq for scsi scanning */ 1181 /* Transport uses the shost workq for scsi scanning */
1147 i->t.create_work_queue = 1; 1182 i->t.create_work_queue = 1;
1148 1183
1184 i->t.eh_timed_out = fc_timed_out;
1185
1149 i->t.user_scan = fc_user_scan; 1186 i->t.user_scan = fc_user_scan;
1150 1187
1151 /* 1188 /*
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 827992949c4b..a6cf3e535c0b 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -147,20 +147,6 @@ struct scsi_host_template {
147 int (* eh_host_reset_handler)(struct scsi_cmnd *); 147 int (* eh_host_reset_handler)(struct scsi_cmnd *);
148 148
149 /* 149 /*
150 * This is an optional routine to notify the host that the scsi
151 * timer just fired. The returns tell the timer routine what to
152 * do about this:
153 *
154 * EH_HANDLED: I fixed the error, please complete the command
155 * EH_RESET_TIMER: I need more time, reset the timer and
156 * begin counting again
157 * EH_NOT_HANDLED Begin normal error recovery
158 *
159 * Status: OPTIONAL
160 */
161 enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
162
163 /*
164 * Before the mid layer attempts to scan for a new device where none 150 * Before the mid layer attempts to scan for a new device where none
165 * currently exists, it will call this entry in your driver. Should 151 * currently exists, it will call this entry in your driver. Should
166 * your driver need to allocate any structs or perform any other init 152 * your driver need to allocate any structs or perform any other init
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index e7b1054adf86..b3657f111937 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -48,6 +48,17 @@ struct scsi_transport_template {
48 * True if the transport wants to use a host-based work-queue 48 * True if the transport wants to use a host-based work-queue
49 */ 49 */
50 unsigned int create_work_queue : 1; 50 unsigned int create_work_queue : 1;
51
52 /*
53 * This is an optional routine that allows the transport to become
54 * involved when a scsi io timer fires. The return value tells the
55 * timer routine how to finish the io timeout handling:
56 * EH_HANDLED: I fixed the error, please complete the command
57 * EH_RESET_TIMER: I need more time, reset the timer and
58 * begin counting again
59 * EH_NOT_HANDLED Begin normal error recovery
60 */
61 enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
51}; 62};
52 63
53#define transport_class_to_shost(tc) \ 64#define transport_class_to_shost(tc) \