aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/scsi/zfcp_scsi.c
diff options
context:
space:
mode:
authorChristof Schmitt <christof.schmitt@de.ibm.com>2009-03-02 07:09:00 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-03-12 13:58:19 -0400
commit63caf367e1c92e0667a344d9b687c04e6ef054b5 (patch)
treea6697048cb7f82b23648a5b2631c052d540ad709 /drivers/s390/scsi/zfcp_scsi.c
parent92cab0d93a1107ad7f6d827fde62d1aa4db15e86 (diff)
[SCSI] zfcp: Improve reliability of SCSI eh handlers in zfcp
When the SCSI midlayer is running error recovery, the low-level error recovery in zfcp could be running and preventing the SCSI midlayer to issue error recovery requests. To avoid unnecessary error recovery escalation, wait for the zfcp erp to finish and retry if necessary. While reworking the SCSI eh handlers, alsa cleanup the code and simplify the interface from zfcp_scsi to the fsf layer. Acked-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/s390/scsi/zfcp_scsi.c')
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c124
1 files changed, 60 insertions, 64 deletions
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 7829c72d83d0..c17505f767a9 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -87,8 +87,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
87 return 0;; 87 return 0;;
88 } 88 }
89 89
90 ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, 90 ret = zfcp_fsf_send_fcp_command_task(unit, scpnt);
91 ZFCP_REQ_AUTO_CLEANUP);
92 if (unlikely(ret == -EBUSY)) 91 if (unlikely(ret == -EBUSY))
93 return SCSI_MLQUEUE_DEVICE_BUSY; 92 return SCSI_MLQUEUE_DEVICE_BUSY;
94 else if (unlikely(ret < 0)) 93 else if (unlikely(ret < 0))
@@ -145,79 +144,91 @@ out:
145 144
146static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) 145static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
147{ 146{
148 struct Scsi_Host *scsi_host; 147 struct Scsi_Host *scsi_host = scpnt->device->host;
149 struct zfcp_adapter *adapter; 148 struct zfcp_adapter *adapter =
150 struct zfcp_unit *unit; 149 (struct zfcp_adapter *) scsi_host->hostdata[0];
151 struct zfcp_fsf_req *fsf_req; 150 struct zfcp_unit *unit = scpnt->device->hostdata;
151 struct zfcp_fsf_req *old_req, *abrt_req;
152 unsigned long flags; 152 unsigned long flags;
153 unsigned long old_req_id = (unsigned long) scpnt->host_scribble; 153 unsigned long old_req_id = (unsigned long) scpnt->host_scribble;
154 int retval = SUCCESS; 154 int retval = SUCCESS;
155 155 int retry = 3;
156 scsi_host = scpnt->device->host;
157 adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
158 unit = scpnt->device->hostdata;
159 156
160 /* avoid race condition between late normal completion and abort */ 157 /* avoid race condition between late normal completion and abort */
161 write_lock_irqsave(&adapter->abort_lock, flags); 158 write_lock_irqsave(&adapter->abort_lock, flags);
162 159
163 /* Check whether corresponding fsf_req is still pending */
164 spin_lock(&adapter->req_list_lock); 160 spin_lock(&adapter->req_list_lock);
165 fsf_req = zfcp_reqlist_find(adapter, old_req_id); 161 old_req = zfcp_reqlist_find(adapter, old_req_id);
166 spin_unlock(&adapter->req_list_lock); 162 spin_unlock(&adapter->req_list_lock);
167 if (!fsf_req) { 163 if (!old_req) {
168 write_unlock_irqrestore(&adapter->abort_lock, flags); 164 write_unlock_irqrestore(&adapter->abort_lock, flags);
169 zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0); 165 zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL,
170 return retval; 166 old_req_id);
167 return SUCCESS;
171 } 168 }
172 fsf_req->data = NULL; 169 old_req->data = NULL;
173 170
174 /* don't access old fsf_req after releasing the abort_lock */ 171 /* don't access old fsf_req after releasing the abort_lock */
175 write_unlock_irqrestore(&adapter->abort_lock, flags); 172 write_unlock_irqrestore(&adapter->abort_lock, flags);
176 173
177 fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0); 174 while (retry--) {
178 if (!fsf_req) { 175 abrt_req = zfcp_fsf_abort_fcp_command(old_req_id, unit);
179 zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL, 176 if (abrt_req)
180 old_req_id); 177 break;
181 retval = FAILED; 178
182 return retval; 179 zfcp_erp_wait(adapter);
180 if (!(atomic_read(&adapter->status) &
181 ZFCP_STATUS_COMMON_RUNNING)) {
182 zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
183 old_req_id);
184 return SUCCESS;
185 }
183 } 186 }
187 if (!abrt_req)
188 return FAILED;
184 189
185 __wait_event(fsf_req->completion_wq, 190 wait_event(abrt_req->completion_wq,
186 fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); 191 abrt_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
187 192
188 if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { 193 if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED)
189 zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0); 194 zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, abrt_req, 0);
190 } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { 195 else if (abrt_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED)
191 zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0); 196 zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, abrt_req, 0);
192 } else { 197 else {
193 zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0); 198 zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, abrt_req, 0);
194 retval = FAILED; 199 retval = FAILED;
195 } 200 }
196 zfcp_fsf_req_free(fsf_req); 201 zfcp_fsf_req_free(abrt_req);
197
198 return retval; 202 return retval;
199} 203}
200 204
201static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, 205static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags)
202 struct scsi_cmnd *scpnt)
203{ 206{
207 struct zfcp_unit *unit = scpnt->device->hostdata;
204 struct zfcp_adapter *adapter = unit->port->adapter; 208 struct zfcp_adapter *adapter = unit->port->adapter;
205 struct zfcp_fsf_req *fsf_req; 209 struct zfcp_fsf_req *fsf_req;
206 int retval = SUCCESS; 210 int retval = SUCCESS;
207 211 int retry = 3;
208 /* issue task management function */ 212
209 fsf_req = zfcp_fsf_send_fcp_ctm(adapter, unit, tm_flags, 0); 213 while (retry--) {
210 if (!fsf_req) { 214 fsf_req = zfcp_fsf_send_fcp_ctm(unit, tm_flags);
211 zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); 215 if (fsf_req)
212 return FAILED; 216 break;
217
218 zfcp_erp_wait(adapter);
219 if (!(atomic_read(&adapter->status) &
220 ZFCP_STATUS_COMMON_RUNNING)) {
221 zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit,
222 scpnt);
223 return SUCCESS;
224 }
213 } 225 }
226 if (!fsf_req)
227 return FAILED;
214 228
215 __wait_event(fsf_req->completion_wq, 229 wait_event(fsf_req->completion_wq,
216 fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); 230 fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
217 231
218 /*
219 * check completion status of task management function
220 */
221 if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { 232 if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) {
222 zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); 233 zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt);
223 retval = FAILED; 234 retval = FAILED;
@@ -228,39 +239,24 @@ static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags,
228 zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); 239 zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt);
229 240
230 zfcp_fsf_req_free(fsf_req); 241 zfcp_fsf_req_free(fsf_req);
231
232 return retval; 242 return retval;
233} 243}
234 244
235static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) 245static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
236{ 246{
237 struct zfcp_unit *unit = scpnt->device->hostdata; 247 return zfcp_task_mgmt_function(scpnt, FCP_LOGICAL_UNIT_RESET);
238
239 if (!unit) {
240 WARN_ON(1);
241 return SUCCESS;
242 }
243 return zfcp_task_mgmt_function(unit, FCP_LOGICAL_UNIT_RESET, scpnt);
244} 248}
245 249
246static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) 250static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt)
247{ 251{
248 struct zfcp_unit *unit = scpnt->device->hostdata; 252 return zfcp_task_mgmt_function(scpnt, FCP_TARGET_RESET);
249
250 if (!unit) {
251 WARN_ON(1);
252 return SUCCESS;
253 }
254 return zfcp_task_mgmt_function(unit, FCP_TARGET_RESET, scpnt);
255} 253}
256 254
257static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) 255static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
258{ 256{
259 struct zfcp_unit *unit; 257 struct zfcp_unit *unit = scpnt->device->hostdata;
260 struct zfcp_adapter *adapter; 258 struct zfcp_adapter *adapter = unit->port->adapter;
261 259
262 unit = scpnt->device->hostdata;
263 adapter = unit->port->adapter;
264 zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt); 260 zfcp_erp_adapter_reopen(adapter, 0, 141, scpnt);
265 zfcp_erp_wait(adapter); 261 zfcp_erp_wait(adapter);
266 262