diff options
-rw-r--r-- | drivers/s390/block/dasd.c | 32 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 1 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 1 |
3 files changed, 34 insertions, 0 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f3509120a507..2678a8347729 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -82,6 +82,7 @@ static void dasd_profile_exit(struct dasd_profile *); | |||
82 | static wait_queue_head_t dasd_init_waitq; | 82 | static wait_queue_head_t dasd_init_waitq; |
83 | static wait_queue_head_t dasd_flush_wq; | 83 | static wait_queue_head_t dasd_flush_wq; |
84 | static wait_queue_head_t generic_waitq; | 84 | static wait_queue_head_t generic_waitq; |
85 | static wait_queue_head_t shutdown_waitq; | ||
85 | 86 | ||
86 | /* | 87 | /* |
87 | * Allocate memory for a new device structure. | 88 | * Allocate memory for a new device structure. |
@@ -1994,6 +1995,8 @@ static void dasd_device_tasklet(struct dasd_device *device) | |||
1994 | /* Now check if the head of the ccw queue needs to be started. */ | 1995 | /* Now check if the head of the ccw queue needs to be started. */ |
1995 | __dasd_device_start_head(device); | 1996 | __dasd_device_start_head(device); |
1996 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | 1997 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); |
1998 | if (waitqueue_active(&shutdown_waitq)) | ||
1999 | wake_up(&shutdown_waitq); | ||
1997 | dasd_put_device(device); | 2000 | dasd_put_device(device); |
1998 | } | 2001 | } |
1999 | 2002 | ||
@@ -2632,6 +2635,8 @@ static void dasd_block_tasklet(struct dasd_block *block) | |||
2632 | __dasd_block_start_head(block); | 2635 | __dasd_block_start_head(block); |
2633 | spin_unlock(&block->queue_lock); | 2636 | spin_unlock(&block->queue_lock); |
2634 | spin_unlock_irq(&block->request_queue_lock); | 2637 | spin_unlock_irq(&block->request_queue_lock); |
2638 | if (waitqueue_active(&shutdown_waitq)) | ||
2639 | wake_up(&shutdown_waitq); | ||
2635 | dasd_put_device(block->base); | 2640 | dasd_put_device(block->base); |
2636 | } | 2641 | } |
2637 | 2642 | ||
@@ -3474,6 +3479,32 @@ char *dasd_get_sense(struct irb *irb) | |||
3474 | } | 3479 | } |
3475 | EXPORT_SYMBOL_GPL(dasd_get_sense); | 3480 | EXPORT_SYMBOL_GPL(dasd_get_sense); |
3476 | 3481 | ||
3482 | static inline int _wait_for_empty_queues(struct dasd_device *device) | ||
3483 | { | ||
3484 | if (device->block) | ||
3485 | return list_empty(&device->ccw_queue) && | ||
3486 | list_empty(&device->block->ccw_queue); | ||
3487 | else | ||
3488 | return list_empty(&device->ccw_queue); | ||
3489 | } | ||
3490 | |||
3491 | void dasd_generic_shutdown(struct ccw_device *cdev) | ||
3492 | { | ||
3493 | struct dasd_device *device; | ||
3494 | |||
3495 | device = dasd_device_from_cdev(cdev); | ||
3496 | if (IS_ERR(device)) | ||
3497 | return; | ||
3498 | |||
3499 | if (device->block) | ||
3500 | dasd_schedule_block_bh(device->block); | ||
3501 | |||
3502 | dasd_schedule_device_bh(device); | ||
3503 | |||
3504 | wait_event(shutdown_waitq, _wait_for_empty_queues(device)); | ||
3505 | } | ||
3506 | EXPORT_SYMBOL_GPL(dasd_generic_shutdown); | ||
3507 | |||
3477 | static int __init dasd_init(void) | 3508 | static int __init dasd_init(void) |
3478 | { | 3509 | { |
3479 | int rc; | 3510 | int rc; |
@@ -3481,6 +3512,7 @@ static int __init dasd_init(void) | |||
3481 | init_waitqueue_head(&dasd_init_waitq); | 3512 | init_waitqueue_head(&dasd_init_waitq); |
3482 | init_waitqueue_head(&dasd_flush_wq); | 3513 | init_waitqueue_head(&dasd_flush_wq); |
3483 | init_waitqueue_head(&generic_waitq); | 3514 | init_waitqueue_head(&generic_waitq); |
3515 | init_waitqueue_head(&shutdown_waitq); | ||
3484 | 3516 | ||
3485 | /* register 'common' DASD debug area, used for all DBF_XXX calls */ | 3517 | /* register 'common' DASD debug area, used for all DBF_XXX calls */ |
3486 | dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long)); | 3518 | dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long)); |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index bc2e8a7c265b..fc0fe30b2ab5 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -4247,6 +4247,7 @@ static struct ccw_driver dasd_eckd_driver = { | |||
4247 | .set_online = dasd_eckd_set_online, | 4247 | .set_online = dasd_eckd_set_online, |
4248 | .notify = dasd_generic_notify, | 4248 | .notify = dasd_generic_notify, |
4249 | .path_event = dasd_generic_path_event, | 4249 | .path_event = dasd_generic_path_event, |
4250 | .shutdown = dasd_generic_shutdown, | ||
4250 | .freeze = dasd_generic_pm_freeze, | 4251 | .freeze = dasd_generic_pm_freeze, |
4251 | .thaw = dasd_generic_restore_device, | 4252 | .thaw = dasd_generic_restore_device, |
4252 | .restore = dasd_generic_restore_device, | 4253 | .restore = dasd_generic_restore_device, |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index c05da00583f0..297ac3b8c8ec 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -686,6 +686,7 @@ int dasd_generic_set_offline (struct ccw_device *cdev); | |||
686 | int dasd_generic_notify(struct ccw_device *, int); | 686 | int dasd_generic_notify(struct ccw_device *, int); |
687 | int dasd_generic_last_path_gone(struct dasd_device *); | 687 | int dasd_generic_last_path_gone(struct dasd_device *); |
688 | int dasd_generic_path_operational(struct dasd_device *); | 688 | int dasd_generic_path_operational(struct dasd_device *); |
689 | void dasd_generic_shutdown(struct ccw_device *); | ||
689 | 690 | ||
690 | void dasd_generic_handle_state_change(struct dasd_device *); | 691 | void dasd_generic_handle_state_change(struct dasd_device *); |
691 | int dasd_generic_pm_freeze(struct ccw_device *); | 692 | int dasd_generic_pm_freeze(struct ccw_device *); |