diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2010-09-08 08:39:54 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-09-16 22:54:16 -0400 |
commit | fdbd1c5e27dabfa950d4b0f52a20069aeaf67b9d (patch) | |
tree | 402ea45cf57a2fdcef7a6011a1c64bc7d43cc66e /drivers/s390/scsi | |
parent | e4b9857fe628b453983cac89473a11a76a1f5786 (diff) |
[SCSI] zfcp: Allow running unit/LUN shutdown without acquiring reference
With the change for the LUN data to be part of the scsi_device, the
slave_destroy callback will be the final call to the
zfcp_erp_unit_shutdown function. The erp tries to acquire a reference
to run the action asynchronously and fail, if it cannot get the
reference. But calling scsi_device_get from slave_destroy will fail,
because the scsi_device is already in the state SDEV_DEL.
Introduce a new call into the zfcp erp to solve this: The function
zfcp_erp_unit_shutdown_wait will close the LUN and wait for the erp to
finish without acquiring an additional reference. The wait allows to
omit the reference; the caller waiting for the erp to finish already
has a reference that holds the struct in place.
Reviewed-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/s390/scsi')
-rw-r--r-- | drivers/s390/scsi/zfcp_erp.c | 98 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 |
2 files changed, 63 insertions, 36 deletions
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 160b432c907f..50514b4c8732 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c | |||
@@ -21,6 +21,7 @@ enum zfcp_erp_act_flags { | |||
21 | ZFCP_STATUS_ERP_DISMISSING = 0x00100000, | 21 | ZFCP_STATUS_ERP_DISMISSING = 0x00100000, |
22 | ZFCP_STATUS_ERP_DISMISSED = 0x00200000, | 22 | ZFCP_STATUS_ERP_DISMISSED = 0x00200000, |
23 | ZFCP_STATUS_ERP_LOWMEM = 0x00400000, | 23 | ZFCP_STATUS_ERP_LOWMEM = 0x00400000, |
24 | ZFCP_STATUS_ERP_NO_REF = 0x00800000, | ||
24 | }; | 25 | }; |
25 | 26 | ||
26 | enum zfcp_erp_steps { | 27 | enum zfcp_erp_steps { |
@@ -169,22 +170,22 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, | |||
169 | return need; | 170 | return need; |
170 | } | 171 | } |
171 | 172 | ||
172 | static struct zfcp_erp_action *zfcp_erp_setup_act(int need, | 173 | static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, |
173 | struct zfcp_adapter *adapter, | 174 | struct zfcp_adapter *adapter, |
174 | struct zfcp_port *port, | 175 | struct zfcp_port *port, |
175 | struct zfcp_unit *unit) | 176 | struct zfcp_unit *unit) |
176 | { | 177 | { |
177 | struct zfcp_erp_action *erp_action; | 178 | struct zfcp_erp_action *erp_action; |
178 | u32 status = 0; | ||
179 | 179 | ||
180 | switch (need) { | 180 | switch (need) { |
181 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 181 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
182 | if (!get_device(&unit->dev)) | 182 | if (!(act_status & ZFCP_STATUS_ERP_NO_REF)) |
183 | return NULL; | 183 | if (!get_device(&unit->dev)) |
184 | return NULL; | ||
184 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); | 185 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status); |
185 | erp_action = &unit->erp_action; | 186 | erp_action = &unit->erp_action; |
186 | if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) | 187 | if (!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_RUNNING)) |
187 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | 188 | act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; |
188 | break; | 189 | break; |
189 | 190 | ||
190 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 191 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
@@ -195,7 +196,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, | |||
195 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); | 196 | atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); |
196 | erp_action = &port->erp_action; | 197 | erp_action = &port->erp_action; |
197 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) | 198 | if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_RUNNING)) |
198 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | 199 | act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; |
199 | break; | 200 | break; |
200 | 201 | ||
201 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: | 202 | case ZFCP_ERP_ACTION_REOPEN_ADAPTER: |
@@ -205,7 +206,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, | |||
205 | erp_action = &adapter->erp_action; | 206 | erp_action = &adapter->erp_action; |
206 | if (!(atomic_read(&adapter->status) & | 207 | if (!(atomic_read(&adapter->status) & |
207 | ZFCP_STATUS_COMMON_RUNNING)) | 208 | ZFCP_STATUS_COMMON_RUNNING)) |
208 | status = ZFCP_STATUS_ERP_CLOSE_ONLY; | 209 | act_status |= ZFCP_STATUS_ERP_CLOSE_ONLY; |
209 | break; | 210 | break; |
210 | 211 | ||
211 | default: | 212 | default: |
@@ -217,14 +218,15 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, | |||
217 | erp_action->port = port; | 218 | erp_action->port = port; |
218 | erp_action->unit = unit; | 219 | erp_action->unit = unit; |
219 | erp_action->action = need; | 220 | erp_action->action = need; |
220 | erp_action->status = status; | 221 | erp_action->status = act_status; |
221 | 222 | ||
222 | return erp_action; | 223 | return erp_action; |
223 | } | 224 | } |
224 | 225 | ||
225 | static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, | 226 | static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, |
226 | struct zfcp_port *port, | 227 | struct zfcp_port *port, |
227 | struct zfcp_unit *unit, char *id, void *ref) | 228 | struct zfcp_unit *unit, char *id, void *ref, |
229 | u32 act_status) | ||
228 | { | 230 | { |
229 | int retval = 1, need; | 231 | int retval = 1, need; |
230 | struct zfcp_erp_action *act = NULL; | 232 | struct zfcp_erp_action *act = NULL; |
@@ -236,10 +238,10 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, | |||
236 | if (!need) | 238 | if (!need) |
237 | goto out; | 239 | goto out; |
238 | 240 | ||
239 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); | 241 | act = zfcp_erp_setup_act(need, act_status, adapter, port, unit); |
240 | act = zfcp_erp_setup_act(need, adapter, port, unit); | ||
241 | if (!act) | 242 | if (!act) |
242 | goto out; | 243 | goto out; |
244 | atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); | ||
243 | ++adapter->erp_total_count; | 245 | ++adapter->erp_total_count; |
244 | list_add_tail(&act->list, &adapter->erp_ready_head); | 246 | list_add_tail(&act->list, &adapter->erp_ready_head); |
245 | wake_up(&adapter->erp_ready_wq); | 247 | wake_up(&adapter->erp_ready_wq); |
@@ -262,7 +264,7 @@ static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, | |||
262 | return -EIO; | 264 | return -EIO; |
263 | } | 265 | } |
264 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, | 266 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, |
265 | adapter, NULL, NULL, id, ref); | 267 | adapter, NULL, NULL, id, ref, 0); |
266 | } | 268 | } |
267 | 269 | ||
268 | /** | 270 | /** |
@@ -285,7 +287,7 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, | |||
285 | zfcp_erp_adapter_failed(adapter, "erareo1", NULL); | 287 | zfcp_erp_adapter_failed(adapter, "erareo1", NULL); |
286 | else | 288 | else |
287 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, | 289 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, |
288 | NULL, NULL, id, ref); | 290 | NULL, NULL, id, ref, 0); |
289 | write_unlock_irqrestore(&adapter->erp_lock, flags); | 291 | write_unlock_irqrestore(&adapter->erp_lock, flags); |
290 | } | 292 | } |
291 | 293 | ||
@@ -317,20 +319,6 @@ void zfcp_erp_port_shutdown(struct zfcp_port *port, int clear, char *id, | |||
317 | zfcp_erp_port_reopen(port, clear | flags, id, ref); | 319 | zfcp_erp_port_reopen(port, clear | flags, id, ref); |
318 | } | 320 | } |
319 | 321 | ||
320 | /** | ||
321 | * zfcp_erp_unit_shutdown - Shutdown unit | ||
322 | * @unit: Unit to shut down. | ||
323 | * @clear: Status flags to clear. | ||
324 | * @id: Id for debug trace event. | ||
325 | * @ref: Reference for debug trace event. | ||
326 | */ | ||
327 | void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id, | ||
328 | void *ref) | ||
329 | { | ||
330 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | ||
331 | zfcp_erp_unit_reopen(unit, clear | flags, id, ref); | ||
332 | } | ||
333 | |||
334 | static void zfcp_erp_port_block(struct zfcp_port *port, int clear) | 322 | static void zfcp_erp_port_block(struct zfcp_port *port, int clear) |
335 | { | 323 | { |
336 | zfcp_erp_modify_port_status(port, "erpblk1", NULL, | 324 | zfcp_erp_modify_port_status(port, "erpblk1", NULL, |
@@ -348,7 +336,7 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, | |||
348 | return; | 336 | return; |
349 | 337 | ||
350 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, | 338 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, |
351 | port->adapter, port, NULL, id, ref); | 339 | port->adapter, port, NULL, id, ref, 0); |
352 | } | 340 | } |
353 | 341 | ||
354 | /** | 342 | /** |
@@ -381,7 +369,7 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id, | |||
381 | } | 369 | } |
382 | 370 | ||
383 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, | 371 | return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, |
384 | port->adapter, port, NULL, id, ref); | 372 | port->adapter, port, NULL, id, ref, 0); |
385 | } | 373 | } |
386 | 374 | ||
387 | /** | 375 | /** |
@@ -412,7 +400,7 @@ static void zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask) | |||
412 | } | 400 | } |
413 | 401 | ||
414 | static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, | 402 | static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, |
415 | void *ref) | 403 | void *ref, u32 act_status) |
416 | { | 404 | { |
417 | struct zfcp_adapter *adapter = unit->port->adapter; | 405 | struct zfcp_adapter *adapter = unit->port->adapter; |
418 | 406 | ||
@@ -422,7 +410,7 @@ static void _zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, | |||
422 | return; | 410 | return; |
423 | 411 | ||
424 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, | 412 | zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_UNIT, |
425 | adapter, unit->port, unit, id, ref); | 413 | adapter, unit->port, unit, id, ref, act_status); |
426 | } | 414 | } |
427 | 415 | ||
428 | /** | 416 | /** |
@@ -439,8 +427,45 @@ void zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear, char *id, | |||
439 | struct zfcp_adapter *adapter = port->adapter; | 427 | struct zfcp_adapter *adapter = port->adapter; |
440 | 428 | ||
441 | write_lock_irqsave(&adapter->erp_lock, flags); | 429 | write_lock_irqsave(&adapter->erp_lock, flags); |
442 | _zfcp_erp_unit_reopen(unit, clear, id, ref); | 430 | _zfcp_erp_unit_reopen(unit, clear, id, ref, 0); |
431 | write_unlock_irqrestore(&adapter->erp_lock, flags); | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * zfcp_erp_unit_shutdown - Shutdown unit | ||
436 | * @unit: Unit to shut down. | ||
437 | * @clear: Status flags to clear. | ||
438 | * @id: Id for debug trace event. | ||
439 | * @ref: Reference for debug trace event. | ||
440 | */ | ||
441 | void zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear, char *id, | ||
442 | void *ref) | ||
443 | { | ||
444 | int flags = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | ||
445 | zfcp_erp_unit_reopen(unit, clear | flags, id, ref); | ||
446 | } | ||
447 | |||
448 | /** | ||
449 | * zfcp_erp_unit_shutdown_wait - Shutdown unit and wait for erp completion | ||
450 | * @unit: Unit to shut down. | ||
451 | * @id: Id for debug trace event. | ||
452 | * | ||
453 | * Do not acquire a reference for the unit when creating the ERP | ||
454 | * action. It is safe, because this function waits for the ERP to | ||
455 | * complete first. | ||
456 | */ | ||
457 | void zfcp_erp_unit_shutdown_wait(struct zfcp_unit *unit, char *id) | ||
458 | { | ||
459 | unsigned long flags; | ||
460 | struct zfcp_port *port = unit->port; | ||
461 | struct zfcp_adapter *adapter = port->adapter; | ||
462 | int clear = ZFCP_STATUS_COMMON_RUNNING | ZFCP_STATUS_COMMON_ERP_FAILED; | ||
463 | |||
464 | write_lock_irqsave(&adapter->erp_lock, flags); | ||
465 | _zfcp_erp_unit_reopen(unit, clear, id, NULL, ZFCP_STATUS_ERP_NO_REF); | ||
443 | write_unlock_irqrestore(&adapter->erp_lock, flags); | 466 | write_unlock_irqrestore(&adapter->erp_lock, flags); |
467 | |||
468 | zfcp_erp_wait(adapter); | ||
444 | } | 469 | } |
445 | 470 | ||
446 | static int status_change_set(unsigned long mask, atomic_t *status) | 471 | static int status_change_set(unsigned long mask, atomic_t *status) |
@@ -566,7 +591,7 @@ static void _zfcp_erp_unit_reopen_all(struct zfcp_port *port, int clear, | |||
566 | 591 | ||
567 | read_lock(&port->unit_list_lock); | 592 | read_lock(&port->unit_list_lock); |
568 | list_for_each_entry(unit, &port->unit_list, list) | 593 | list_for_each_entry(unit, &port->unit_list, list) |
569 | _zfcp_erp_unit_reopen(unit, clear, id, ref); | 594 | _zfcp_erp_unit_reopen(unit, clear, id, ref, 0); |
570 | read_unlock(&port->unit_list_lock); | 595 | read_unlock(&port->unit_list_lock); |
571 | } | 596 | } |
572 | 597 | ||
@@ -583,7 +608,7 @@ static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) | |||
583 | _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); | 608 | _zfcp_erp_port_reopen(act->port, 0, "ersff_3", NULL); |
584 | break; | 609 | break; |
585 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 610 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
586 | _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL); | 611 | _zfcp_erp_unit_reopen(act->unit, 0, "ersff_4", NULL, 0); |
587 | break; | 612 | break; |
588 | } | 613 | } |
589 | } | 614 | } |
@@ -1143,7 +1168,7 @@ static int zfcp_erp_strategy_statechange(struct zfcp_erp_action *act, int ret) | |||
1143 | if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { | 1168 | if (zfcp_erp_strat_change_det(&unit->status, erp_status)) { |
1144 | _zfcp_erp_unit_reopen(unit, | 1169 | _zfcp_erp_unit_reopen(unit, |
1145 | ZFCP_STATUS_COMMON_ERP_FAILED, | 1170 | ZFCP_STATUS_COMMON_ERP_FAILED, |
1146 | "ersscg3", NULL); | 1171 | "ersscg3", NULL, 0); |
1147 | return ZFCP_ERP_EXIT; | 1172 | return ZFCP_ERP_EXIT; |
1148 | } | 1173 | } |
1149 | break; | 1174 | break; |
@@ -1191,7 +1216,8 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) | |||
1191 | 1216 | ||
1192 | switch (act->action) { | 1217 | switch (act->action) { |
1193 | case ZFCP_ERP_ACTION_REOPEN_UNIT: | 1218 | case ZFCP_ERP_ACTION_REOPEN_UNIT: |
1194 | put_device(&unit->dev); | 1219 | if (!(act->status & ZFCP_STATUS_ERP_NO_REF)) |
1220 | put_device(&unit->dev); | ||
1195 | break; | 1221 | break; |
1196 | 1222 | ||
1197 | case ZFCP_ERP_ACTION_REOPEN_PORT: | 1223 | case ZFCP_ERP_ACTION_REOPEN_PORT: |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 5c3966eaca51..3c90604076e0 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -80,6 +80,7 @@ extern void zfcp_erp_modify_unit_status(struct zfcp_unit *, char *, void *, u32, | |||
80 | int); | 80 | int); |
81 | extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *); | 81 | extern void zfcp_erp_unit_reopen(struct zfcp_unit *, int, char *, void *); |
82 | extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *); | 82 | extern void zfcp_erp_unit_shutdown(struct zfcp_unit *, int, char *, void *); |
83 | extern void zfcp_erp_unit_shutdown_wait(struct zfcp_unit *, char *); | ||
83 | extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *); | 84 | extern void zfcp_erp_unit_failed(struct zfcp_unit *, char *, void *); |
84 | extern int zfcp_erp_thread_setup(struct zfcp_adapter *); | 85 | extern int zfcp_erp_thread_setup(struct zfcp_adapter *); |
85 | extern void zfcp_erp_thread_kill(struct zfcp_adapter *); | 86 | extern void zfcp_erp_thread_kill(struct zfcp_adapter *); |