]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | Subject: ibmvfc oops while processing async events |
2 | From: Brian King <brking@us.ibm.com> | |
3 | Date: Thu Nov 20 13:43:45 2008 +0100: | |
4 | References: bnc#445541 | |
5 | ||
6 | While running error injection (port disable/enable loop) during | |
7 | I/O stress, the following oops occurred: | |
8 | ||
9 | cpu 0x0: Vector: 300 (Data Access) at [c00000000f4cbb10] | |
10 | pc: d0000000000c5c44: .ibmvfc_interrupt+0x1a4/0x1f8 [ibmvfc] | |
11 | lr: d0000000000c5c44: .ibmvfc_interrupt+0x1a4/0x1f8 [ibmvfc] | |
12 | sp: c00000000f4cbd90 | |
13 | msr: 8000000000009032 | |
14 | dar: 0 | |
15 | dsisr: 42000000 | |
16 | current = 0xc00000001dee77a0 | |
17 | paca = 0xc000000000a92c80 | |
18 | ||
19 | There is a window in the ibmvfc interrupt handler. If, while | |
20 | processing an interrupt, after processing both the regular crq | |
21 | and the async crq, an async event is added to the async crq, we | |
22 | will oops when we process the async queue a second time, due to | |
23 | an obvious bug in the code. | |
24 | ||
25 | Signed-off-by: Brian King <brking@us.ibm.com> | |
26 | Acked-by: Hannes Reinecke <hare@suse.de> | |
27 | ||
28 | --- | |
29 | drivers/scsi/ibmvscsi/ibmvfc.c | 266 +++++++++++++++++++++++++++-------------- | |
30 | drivers/scsi/ibmvscsi/ibmvfc.h | 26 ++-- | |
31 | 2 files changed, 191 insertions(+), 101 deletions(-) | |
32 | ||
33 | --- a/drivers/scsi/ibmvscsi/ibmvfc.c | |
34 | +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |
35 | @@ -121,6 +121,7 @@ static const struct { | |
36 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, | |
37 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, | |
38 | { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, | |
39 | + { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, | |
40 | { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, | |
41 | ||
42 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, | |
43 | @@ -278,13 +279,6 @@ static int ibmvfc_get_err_result(struct | |
44 | rsp->data.info.rsp_code)) | |
45 | return DID_ERROR << 16; | |
46 | ||
47 | - if (!vfc_cmd->status) { | |
48 | - if (rsp->flags & FCP_RESID_OVER) | |
49 | - return rsp->scsi_status | (DID_ERROR << 16); | |
50 | - else | |
51 | - return rsp->scsi_status | (DID_OK << 16); | |
52 | - } | |
53 | - | |
54 | err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); | |
55 | if (err >= 0) | |
56 | return rsp->scsi_status | (cmd_status[err].result << 16); | |
57 | @@ -503,6 +497,7 @@ static void ibmvfc_set_host_action(struc | |
58 | case IBMVFC_HOST_ACTION_INIT: | |
59 | case IBMVFC_HOST_ACTION_TGT_DEL: | |
60 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | |
61 | + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: | |
62 | case IBMVFC_HOST_ACTION_TGT_ADD: | |
63 | case IBMVFC_HOST_ACTION_NONE: | |
64 | default: | |
65 | @@ -765,6 +760,9 @@ static void ibmvfc_scsi_eh_done(struct i | |
66 | cmnd->scsi_done(cmnd); | |
67 | } | |
68 | ||
69 | + if (evt->eh_comp) | |
70 | + complete(evt->eh_comp); | |
71 | + | |
72 | ibmvfc_free_event(evt); | |
73 | } | |
74 | ||
75 | @@ -1253,6 +1251,7 @@ static void ibmvfc_init_event(struct ibm | |
76 | evt->sync_iu = NULL; | |
77 | evt->crq.format = format; | |
78 | evt->done = done; | |
79 | + evt->eh_comp = NULL; | |
80 | } | |
81 | ||
82 | /** | |
83 | @@ -1478,6 +1477,11 @@ static void ibmvfc_scsi_done(struct ibmv | |
84 | sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; | |
85 | if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) | |
86 | memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); | |
87 | + if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) | |
88 | + ibmvfc_reinit_host(evt->vhost); | |
89 | + | |
90 | + if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER))) | |
91 | + cmnd->result = (DID_ERROR << 16); | |
92 | ||
93 | ibmvfc_log_error(evt); | |
94 | } | |
95 | @@ -1490,6 +1494,9 @@ static void ibmvfc_scsi_done(struct ibmv | |
96 | cmnd->scsi_done(cmnd); | |
97 | } | |
98 | ||
99 | + if (evt->eh_comp) | |
100 | + complete(evt->eh_comp); | |
101 | + | |
102 | ibmvfc_free_event(evt); | |
103 | } | |
104 | ||
105 | @@ -1628,7 +1635,7 @@ static int ibmvfc_reset_device(struct sc | |
106 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | |
107 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | |
108 | struct ibmvfc_cmd *tmf; | |
109 | - struct ibmvfc_event *evt; | |
110 | + struct ibmvfc_event *evt = NULL; | |
111 | union ibmvfc_iu rsp_iu; | |
112 | struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; | |
113 | int rsp_rc = -EBUSY; | |
114 | @@ -1790,7 +1797,8 @@ static int ibmvfc_abort_task_set(struct | |
115 | static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) | |
116 | { | |
117 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | |
118 | - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | |
119 | + struct scsi_target *starget = scsi_target(sdev); | |
120 | + struct fc_rport *rport = starget_to_rport(starget); | |
121 | struct ibmvfc_tmf *tmf; | |
122 | struct ibmvfc_event *evt, *found_evt; | |
123 | union ibmvfc_iu rsp; | |
124 | @@ -1828,7 +1836,7 @@ static int ibmvfc_cancel_all(struct scsi | |
125 | int_to_scsilun(sdev->lun, &tmf->lun); | |
126 | tmf->flags = (type | IBMVFC_TMF_LUA_VALID); | |
127 | tmf->cancel_key = (unsigned long)sdev->hostdata; | |
128 | - tmf->my_cancel_key = (IBMVFC_TMF_CANCEL_KEY | (unsigned long)sdev->hostdata); | |
129 | + tmf->my_cancel_key = (unsigned long)starget->hostdata; | |
130 | ||
131 | evt->sync_iu = &rsp; | |
132 | init_completion(&evt->comp); | |
133 | @@ -1860,6 +1868,91 @@ static int ibmvfc_cancel_all(struct scsi | |
134 | } | |
135 | ||
136 | /** | |
137 | + * ibmvfc_match_target - Match function for specified target | |
138 | + * @evt: ibmvfc event struct | |
139 | + * @device: device to match (starget) | |
140 | + * | |
141 | + * Returns: | |
142 | + * 1 if event matches starget / 0 if event does not match starget | |
143 | + **/ | |
144 | +static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) | |
145 | +{ | |
146 | + if (evt->cmnd && scsi_target(evt->cmnd->device) == device) | |
147 | + return 1; | |
148 | + return 0; | |
149 | +} | |
150 | + | |
151 | +/** | |
152 | + * ibmvfc_match_lun - Match function for specified LUN | |
153 | + * @evt: ibmvfc event struct | |
154 | + * @device: device to match (sdev) | |
155 | + * | |
156 | + * Returns: | |
157 | + * 1 if event matches sdev / 0 if event does not match sdev | |
158 | + **/ | |
159 | +static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) | |
160 | +{ | |
161 | + if (evt->cmnd && evt->cmnd->device == device) | |
162 | + return 1; | |
163 | + return 0; | |
164 | +} | |
165 | + | |
166 | +/** | |
167 | + * ibmvfc_wait_for_ops - Wait for ops to complete | |
168 | + * @vhost: ibmvfc host struct | |
169 | + * @device: device to match (starget or sdev) | |
170 | + * @match: match function | |
171 | + * | |
172 | + * Returns: | |
173 | + * SUCCESS / FAILED | |
174 | + **/ | |
175 | +static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, | |
176 | + int (*match) (struct ibmvfc_event *, void *)) | |
177 | +{ | |
178 | + struct ibmvfc_event *evt; | |
179 | + DECLARE_COMPLETION_ONSTACK(comp); | |
180 | + int wait; | |
181 | + unsigned long flags; | |
182 | + signed long timeout = init_timeout * HZ; | |
183 | + | |
184 | + ENTER; | |
185 | + do { | |
186 | + wait = 0; | |
187 | + spin_lock_irqsave(vhost->host->host_lock, flags); | |
188 | + list_for_each_entry(evt, &vhost->sent, queue) { | |
189 | + if (match(evt, device)) { | |
190 | + evt->eh_comp = ∁ | |
191 | + wait++; | |
192 | + } | |
193 | + } | |
194 | + spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
195 | + | |
196 | + if (wait) { | |
197 | + timeout = wait_for_completion_timeout(&comp, timeout); | |
198 | + | |
199 | + if (!timeout) { | |
200 | + wait = 0; | |
201 | + spin_lock_irqsave(vhost->host->host_lock, flags); | |
202 | + list_for_each_entry(evt, &vhost->sent, queue) { | |
203 | + if (match(evt, device)) { | |
204 | + evt->eh_comp = NULL; | |
205 | + wait++; | |
206 | + } | |
207 | + } | |
208 | + spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
209 | + if (wait) | |
210 | + dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); | |
211 | + LEAVE; | |
212 | + return wait ? FAILED : SUCCESS; | |
213 | + } | |
214 | + } | |
215 | + } while (wait); | |
216 | + | |
217 | + LEAVE; | |
218 | + return SUCCESS; | |
219 | +} | |
220 | + | |
221 | +/** | |
222 | * ibmvfc_eh_abort_handler - Abort a command | |
223 | * @cmd: scsi command to abort | |
224 | * | |
225 | @@ -1868,29 +1961,21 @@ static int ibmvfc_cancel_all(struct scsi | |
226 | **/ | |
227 | static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) | |
228 | { | |
229 | - struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | |
230 | - struct ibmvfc_event *evt, *pos; | |
231 | + struct scsi_device *sdev = cmd->device; | |
232 | + struct ibmvfc_host *vhost = shost_priv(sdev->host); | |
233 | int cancel_rc, abort_rc; | |
234 | - unsigned long flags; | |
235 | + int rc = FAILED; | |
236 | ||
237 | ENTER; | |
238 | ibmvfc_wait_while_resetting(vhost); | |
239 | - cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_ABORT_TASK_SET); | |
240 | - abort_rc = ibmvfc_abort_task_set(cmd->device); | |
241 | + cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); | |
242 | + abort_rc = ibmvfc_abort_task_set(sdev); | |
243 | ||
244 | - if (!cancel_rc && !abort_rc) { | |
245 | - spin_lock_irqsave(vhost->host->host_lock, flags); | |
246 | - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | |
247 | - if (evt->cmnd && evt->cmnd->device == cmd->device) | |
248 | - ibmvfc_fail_request(evt, DID_ABORT); | |
249 | - } | |
250 | - spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
251 | - LEAVE; | |
252 | - return SUCCESS; | |
253 | - } | |
254 | + if (!cancel_rc && !abort_rc) | |
255 | + rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); | |
256 | ||
257 | LEAVE; | |
258 | - return FAILED; | |
259 | + return rc; | |
260 | } | |
261 | ||
262 | /** | |
263 | @@ -1902,29 +1987,21 @@ static int ibmvfc_eh_abort_handler(struc | |
264 | **/ | |
265 | static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) | |
266 | { | |
267 | - struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | |
268 | - struct ibmvfc_event *evt, *pos; | |
269 | + struct scsi_device *sdev = cmd->device; | |
270 | + struct ibmvfc_host *vhost = shost_priv(sdev->host); | |
271 | int cancel_rc, reset_rc; | |
272 | - unsigned long flags; | |
273 | + int rc = FAILED; | |
274 | ||
275 | ENTER; | |
276 | ibmvfc_wait_while_resetting(vhost); | |
277 | - cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_LUN_RESET); | |
278 | - reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_LUN_RESET, "LUN"); | |
279 | + cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET); | |
280 | + reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN"); | |
281 | ||
282 | - if (!cancel_rc && !reset_rc) { | |
283 | - spin_lock_irqsave(vhost->host->host_lock, flags); | |
284 | - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | |
285 | - if (evt->cmnd && evt->cmnd->device == cmd->device) | |
286 | - ibmvfc_fail_request(evt, DID_ABORT); | |
287 | - } | |
288 | - spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
289 | - LEAVE; | |
290 | - return SUCCESS; | |
291 | - } | |
292 | + if (!cancel_rc && !reset_rc) | |
293 | + rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); | |
294 | ||
295 | LEAVE; | |
296 | - return FAILED; | |
297 | + return rc; | |
298 | } | |
299 | ||
300 | /** | |
301 | @@ -1960,31 +2037,23 @@ static void ibmvfc_dev_abort_all(struct | |
302 | **/ | |
303 | static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) | |
304 | { | |
305 | - struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | |
306 | - struct scsi_target *starget = scsi_target(cmd->device); | |
307 | - struct ibmvfc_event *evt, *pos; | |
308 | + struct scsi_device *sdev = cmd->device; | |
309 | + struct ibmvfc_host *vhost = shost_priv(sdev->host); | |
310 | + struct scsi_target *starget = scsi_target(sdev); | |
311 | int reset_rc; | |
312 | + int rc = FAILED; | |
313 | unsigned long cancel_rc = 0; | |
314 | - unsigned long flags; | |
315 | ||
316 | ENTER; | |
317 | ibmvfc_wait_while_resetting(vhost); | |
318 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | |
319 | - reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_TARGET_RESET, "target"); | |
320 | + reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); | |
321 | ||
322 | - if (!cancel_rc && !reset_rc) { | |
323 | - spin_lock_irqsave(vhost->host->host_lock, flags); | |
324 | - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | |
325 | - if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | |
326 | - ibmvfc_fail_request(evt, DID_ABORT); | |
327 | - } | |
328 | - spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
329 | - LEAVE; | |
330 | - return SUCCESS; | |
331 | - } | |
332 | + if (!cancel_rc && !reset_rc) | |
333 | + rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); | |
334 | ||
335 | LEAVE; | |
336 | - return FAILED; | |
337 | + return rc; | |
338 | } | |
339 | ||
340 | /** | |
341 | @@ -2014,23 +2083,18 @@ static void ibmvfc_terminate_rport_io(st | |
342 | struct scsi_target *starget = to_scsi_target(&rport->dev); | |
343 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | |
344 | struct ibmvfc_host *vhost = shost_priv(shost); | |
345 | - struct ibmvfc_event *evt, *pos; | |
346 | unsigned long cancel_rc = 0; | |
347 | unsigned long abort_rc = 0; | |
348 | - unsigned long flags; | |
349 | + int rc = FAILED; | |
350 | ||
351 | ENTER; | |
352 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | |
353 | starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); | |
354 | ||
355 | - if (!cancel_rc && !abort_rc) { | |
356 | - spin_lock_irqsave(shost->host_lock, flags); | |
357 | - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | |
358 | - if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | |
359 | - ibmvfc_fail_request(evt, DID_ABORT); | |
360 | - } | |
361 | - spin_unlock_irqrestore(shost->host_lock, flags); | |
362 | - } else | |
363 | + if (!cancel_rc && !abort_rc) | |
364 | + rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); | |
365 | + | |
366 | + if (rc == FAILED) | |
367 | ibmvfc_issue_fc_host_lip(shost); | |
368 | LEAVE; | |
369 | } | |
370 | @@ -2266,6 +2330,28 @@ static int ibmvfc_slave_alloc(struct scs | |
371 | } | |
372 | ||
373 | /** | |
374 | + * ibmvfc_target_alloc - Setup the target's task set value | |
375 | + * @starget: struct scsi_target | |
376 | + * | |
377 | + * Set the target's task set value so that error handling works as | |
378 | + * expected. | |
379 | + * | |
380 | + * Returns: | |
381 | + * 0 on success / -ENXIO if device does not exist | |
382 | + **/ | |
383 | +static int ibmvfc_target_alloc(struct scsi_target *starget) | |
384 | +{ | |
385 | + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | |
386 | + struct ibmvfc_host *vhost = shost_priv(shost); | |
387 | + unsigned long flags = 0; | |
388 | + | |
389 | + spin_lock_irqsave(shost->host_lock, flags); | |
390 | + starget->hostdata = (void *)(unsigned long)vhost->task_set++; | |
391 | + spin_unlock_irqrestore(shost->host_lock, flags); | |
392 | + return 0; | |
393 | +} | |
394 | + | |
395 | +/** | |
396 | * ibmvfc_slave_configure - Configure the device | |
397 | * @sdev: struct scsi_device device to configure | |
398 | * | |
399 | @@ -2544,6 +2630,7 @@ static struct scsi_host_template driver_ | |
400 | .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, | |
401 | .slave_alloc = ibmvfc_slave_alloc, | |
402 | .slave_configure = ibmvfc_slave_configure, | |
403 | + .target_alloc = ibmvfc_target_alloc, | |
404 | .scan_finished = ibmvfc_scan_finished, | |
405 | .change_queue_depth = ibmvfc_change_queue_depth, | |
406 | .change_queue_type = ibmvfc_change_queue_type, | |
407 | @@ -2640,7 +2727,7 @@ static irqreturn_t ibmvfc_interrupt(int | |
408 | } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { | |
409 | vio_disable_interrupts(vdev); | |
410 | ibmvfc_handle_async(async, vhost); | |
411 | - crq->valid = 0; | |
412 | + async->valid = 0; | |
413 | } else | |
414 | done = 1; | |
415 | } | |
416 | @@ -2711,6 +2798,8 @@ static void ibmvfc_tgt_prli_done(struct | |
417 | rsp->status, rsp->error, status); | |
418 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | |
419 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); | |
420 | + else | |
421 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | |
422 | break; | |
423 | }; | |
424 | ||
425 | @@ -2805,6 +2894,8 @@ static void ibmvfc_tgt_plogi_done(struct | |
426 | ||
427 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | |
428 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); | |
429 | + else | |
430 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | |
431 | break; | |
432 | }; | |
433 | ||
434 | @@ -3096,6 +3187,8 @@ static void ibmvfc_tgt_query_target_done | |
435 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | |
436 | else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | |
437 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); | |
438 | + else | |
439 | + ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | |
440 | break; | |
441 | }; | |
442 | ||
443 | @@ -3426,6 +3519,7 @@ static int __ibmvfc_work_to_do(struct ib | |
444 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | |
445 | case IBMVFC_HOST_ACTION_TGT_ADD: | |
446 | case IBMVFC_HOST_ACTION_TGT_DEL: | |
447 | + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: | |
448 | case IBMVFC_HOST_ACTION_QUERY: | |
449 | default: | |
450 | break; | |
451 | @@ -3547,6 +3641,7 @@ static void ibmvfc_do_work(struct ibmvfc | |
452 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); | |
453 | break; | |
454 | case IBMVFC_HOST_ACTION_TGT_DEL: | |
455 | + case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: | |
456 | list_for_each_entry(tgt, &vhost->targets, queue) { | |
457 | if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | |
458 | tgt_dbg(tgt, "Deleting rport\n"); | |
459 | @@ -3562,8 +3657,17 @@ static void ibmvfc_do_work(struct ibmvfc | |
460 | } | |
461 | ||
462 | if (vhost->state == IBMVFC_INITIALIZING) { | |
463 | - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | |
464 | - vhost->job_step = ibmvfc_discover_targets; | |
465 | + if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { | |
466 | + ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); | |
467 | + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); | |
468 | + vhost->init_retries = 0; | |
469 | + spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
470 | + scsi_unblock_requests(vhost->host); | |
471 | + return; | |
472 | + } else { | |
473 | + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | |
474 | + vhost->job_step = ibmvfc_discover_targets; | |
475 | + } | |
476 | } else { | |
477 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | |
478 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
479 | @@ -3586,14 +3690,8 @@ static void ibmvfc_do_work(struct ibmvfc | |
480 | } | |
481 | } | |
482 | ||
483 | - if (!ibmvfc_dev_init_to_do(vhost)) { | |
484 | - ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); | |
485 | - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); | |
486 | - vhost->init_retries = 0; | |
487 | - spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
488 | - scsi_unblock_requests(vhost->host); | |
489 | - return; | |
490 | - } | |
491 | + if (!ibmvfc_dev_init_to_do(vhost)) | |
492 | + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); | |
493 | break; | |
494 | case IBMVFC_HOST_ACTION_TGT_ADD: | |
495 | list_for_each_entry(tgt, &vhost->targets, queue) { | |
496 | @@ -3601,16 +3699,6 @@ static void ibmvfc_do_work(struct ibmvfc | |
497 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
498 | ibmvfc_tgt_add_rport(tgt); | |
499 | return; | |
500 | - } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | |
501 | - tgt_dbg(tgt, "Deleting rport\n"); | |
502 | - rport = tgt->rport; | |
503 | - tgt->rport = NULL; | |
504 | - list_del(&tgt->queue); | |
505 | - spin_unlock_irqrestore(vhost->host->host_lock, flags); | |
506 | - if (rport) | |
507 | - fc_remote_port_delete(rport); | |
508 | - kref_put(&tgt->kref, ibmvfc_release_tgt); | |
509 | - return; | |
510 | } | |
511 | } | |
512 | ||
513 | --- a/drivers/scsi/ibmvscsi/ibmvfc.h | |
514 | +++ b/drivers/scsi/ibmvscsi/ibmvfc.h | |
515 | @@ -29,8 +29,8 @@ | |
516 | #include "viosrp.h" | |
517 | ||
518 | #define IBMVFC_NAME "ibmvfc" | |
519 | -#define IBMVFC_DRIVER_VERSION "1.0.2" | |
520 | -#define IBMVFC_DRIVER_DATE "(August 14, 2008)" | |
521 | +#define IBMVFC_DRIVER_VERSION "1.0.4" | |
522 | +#define IBMVFC_DRIVER_DATE "(November 14, 2008)" | |
523 | ||
524 | #define IBMVFC_DEFAULT_TIMEOUT 15 | |
525 | #define IBMVFC_INIT_TIMEOUT 120 | |
526 | @@ -110,6 +110,7 @@ enum ibmvfc_vios_errors { | |
527 | IBMVFC_TRANS_CANCELLED = 0x0006, | |
528 | IBMVFC_TRANS_CANCELLED_IMPLICIT = 0x0007, | |
529 | IBMVFC_INSUFFICIENT_RESOURCE = 0x0008, | |
530 | + IBMVFC_PLOGI_REQUIRED = 0x0010, | |
531 | IBMVFC_COMMAND_FAILED = 0x8000, | |
532 | }; | |
533 | ||
534 | @@ -338,7 +339,6 @@ struct ibmvfc_tmf { | |
535 | #define IBMVFC_TMF_LUA_VALID 0x40 | |
536 | u32 cancel_key; | |
537 | u32 my_cancel_key; | |
538 | -#define IBMVFC_TMF_CANCEL_KEY 0x80000000 | |
539 | u32 pad; | |
540 | u64 reserved[2]; | |
541 | }__attribute__((packed, aligned (8))); | |
542 | @@ -525,10 +525,10 @@ enum ibmvfc_async_event { | |
543 | }; | |
544 | ||
545 | struct ibmvfc_crq { | |
546 | - u8 valid; | |
547 | - u8 format; | |
548 | + volatile u8 valid; | |
549 | + volatile u8 format; | |
550 | u8 reserved[6]; | |
551 | - u64 ioba; | |
552 | + volatile u64 ioba; | |
553 | }__attribute__((packed, aligned (8))); | |
554 | ||
555 | struct ibmvfc_crq_queue { | |
556 | @@ -538,13 +538,13 @@ struct ibmvfc_crq_queue { | |
557 | }; | |
558 | ||
559 | struct ibmvfc_async_crq { | |
560 | - u8 valid; | |
561 | + volatile u8 valid; | |
562 | u8 pad[3]; | |
563 | u32 pad2; | |
564 | - u64 event; | |
565 | - u64 scsi_id; | |
566 | - u64 wwpn; | |
567 | - u64 node_name; | |
568 | + volatile u64 event; | |
569 | + volatile u64 scsi_id; | |
570 | + volatile u64 wwpn; | |
571 | + volatile u64 node_name; | |
572 | u64 reserved; | |
573 | }__attribute__((packed, aligned (8))); | |
574 | ||
575 | @@ -607,6 +607,7 @@ struct ibmvfc_event { | |
576 | struct srp_direct_buf *ext_list; | |
577 | dma_addr_t ext_list_token; | |
578 | struct completion comp; | |
579 | + struct completion *eh_comp; | |
580 | struct timer_list timer; | |
581 | }; | |
582 | ||
583 | @@ -627,6 +628,7 @@ enum ibmvfc_host_action { | |
584 | IBMVFC_HOST_ACTION_TGT_DEL, | |
585 | IBMVFC_HOST_ACTION_ALLOC_TGTS, | |
586 | IBMVFC_HOST_ACTION_TGT_INIT, | |
587 | + IBMVFC_HOST_ACTION_TGT_DEL_FAILED, | |
588 | IBMVFC_HOST_ACTION_TGT_ADD, | |
589 | }; | |
590 | ||
591 | @@ -702,7 +704,7 @@ struct ibmvfc_host { | |
592 | ||
593 | #define ibmvfc_log(vhost, level, ...) \ | |
594 | do { \ | |
595 | - if (level >= (vhost)->log_level) \ | |
596 | + if ((vhost)->log_level >= level) \ | |
597 | dev_err((vhost)->dev, ##__VA_ARGS__); \ | |
598 | } while (0) | |
599 |