diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2009-03-02 07:09:00 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-03-12 13:58:19 -0400 |
commit | 63caf367e1c92e0667a344d9b687c04e6ef054b5 (patch) | |
tree | a6697048cb7f82b23648a5b2631c052d540ad709 /drivers/s390/scsi/zfcp_scsi.c | |
parent | 92cab0d93a1107ad7f6d827fde62d1aa4db15e86 (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.c | 124 |
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 | ||
146 | static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) | 145 | static 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 | ||
201 | static int zfcp_task_mgmt_function(struct zfcp_unit *unit, u8 tm_flags, | 205 | static 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 | ||
235 | static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) | 245 | static 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 | ||
246 | static int zfcp_scsi_eh_target_reset_handler(struct scsi_cmnd *scpnt) | 250 | static 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 | ||
257 | static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) | 255 | static 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 | ||