Commit 4679e893 authored by Stefan Haberland's avatar Stefan Haberland Committed by Heiko Carstens

s390/dasd: add shutdown action

Add a mechanism to wait for outstanding IO during shutdown.
Schedule the block_bh and device_bh and wait until our request queues
are empty.
Signed-off-by: default avatarStefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent a7df7a94
...@@ -82,6 +82,7 @@ static void dasd_profile_exit(struct dasd_profile *); ...@@ -82,6 +82,7 @@ static void dasd_profile_exit(struct dasd_profile *);
static wait_queue_head_t dasd_init_waitq; static wait_queue_head_t dasd_init_waitq;
static wait_queue_head_t dasd_flush_wq; static wait_queue_head_t dasd_flush_wq;
static wait_queue_head_t generic_waitq; static wait_queue_head_t generic_waitq;
static wait_queue_head_t shutdown_waitq;
/* /*
* Allocate memory for a new device structure. * Allocate memory for a new device structure.
...@@ -1994,6 +1995,8 @@ static void dasd_device_tasklet(struct dasd_device *device) ...@@ -1994,6 +1995,8 @@ static void dasd_device_tasklet(struct dasd_device *device)
/* Now check if the head of the ccw queue needs to be started. */ /* Now check if the head of the ccw queue needs to be started. */
__dasd_device_start_head(device); __dasd_device_start_head(device);
spin_unlock_irq(get_ccwdev_lock(device->cdev)); spin_unlock_irq(get_ccwdev_lock(device->cdev));
if (waitqueue_active(&shutdown_waitq))
wake_up(&shutdown_waitq);
dasd_put_device(device); dasd_put_device(device);
} }
...@@ -2632,6 +2635,8 @@ static void dasd_block_tasklet(struct dasd_block *block) ...@@ -2632,6 +2635,8 @@ static void dasd_block_tasklet(struct dasd_block *block)
__dasd_block_start_head(block); __dasd_block_start_head(block);
spin_unlock(&block->queue_lock); spin_unlock(&block->queue_lock);
spin_unlock_irq(&block->request_queue_lock); spin_unlock_irq(&block->request_queue_lock);
if (waitqueue_active(&shutdown_waitq))
wake_up(&shutdown_waitq);
dasd_put_device(block->base); dasd_put_device(block->base);
} }
...@@ -3474,6 +3479,32 @@ char *dasd_get_sense(struct irb *irb) ...@@ -3474,6 +3479,32 @@ char *dasd_get_sense(struct irb *irb)
} }
EXPORT_SYMBOL_GPL(dasd_get_sense); EXPORT_SYMBOL_GPL(dasd_get_sense);
static inline int _wait_for_empty_queues(struct dasd_device *device)
{
if (device->block)
return list_empty(&device->ccw_queue) &&
list_empty(&device->block->ccw_queue);
else
return list_empty(&device->ccw_queue);
}
void dasd_generic_shutdown(struct ccw_device *cdev)
{
struct dasd_device *device;
device = dasd_device_from_cdev(cdev);
if (IS_ERR(device))
return;
if (device->block)
dasd_schedule_block_bh(device->block);
dasd_schedule_device_bh(device);
wait_event(shutdown_waitq, _wait_for_empty_queues(device));
}
EXPORT_SYMBOL_GPL(dasd_generic_shutdown);
static int __init dasd_init(void) static int __init dasd_init(void)
{ {
int rc; int rc;
...@@ -3481,6 +3512,7 @@ static int __init dasd_init(void) ...@@ -3481,6 +3512,7 @@ static int __init dasd_init(void)
init_waitqueue_head(&dasd_init_waitq); init_waitqueue_head(&dasd_init_waitq);
init_waitqueue_head(&dasd_flush_wq); init_waitqueue_head(&dasd_flush_wq);
init_waitqueue_head(&generic_waitq); init_waitqueue_head(&generic_waitq);
init_waitqueue_head(&shutdown_waitq);
/* register 'common' DASD debug area, used for all DBF_XXX calls */ /* register 'common' DASD debug area, used for all DBF_XXX calls */
dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long)); dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
......
...@@ -4247,6 +4247,7 @@ static struct ccw_driver dasd_eckd_driver = { ...@@ -4247,6 +4247,7 @@ static struct ccw_driver dasd_eckd_driver = {
.set_online = dasd_eckd_set_online, .set_online = dasd_eckd_set_online,
.notify = dasd_generic_notify, .notify = dasd_generic_notify,
.path_event = dasd_generic_path_event, .path_event = dasd_generic_path_event,
.shutdown = dasd_generic_shutdown,
.freeze = dasd_generic_pm_freeze, .freeze = dasd_generic_pm_freeze,
.thaw = dasd_generic_restore_device, .thaw = dasd_generic_restore_device,
.restore = dasd_generic_restore_device, .restore = dasd_generic_restore_device,
......
...@@ -686,6 +686,7 @@ int dasd_generic_set_offline (struct ccw_device *cdev); ...@@ -686,6 +686,7 @@ int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int); int dasd_generic_notify(struct ccw_device *, int);
int dasd_generic_last_path_gone(struct dasd_device *); int dasd_generic_last_path_gone(struct dasd_device *);
int dasd_generic_path_operational(struct dasd_device *); int dasd_generic_path_operational(struct dasd_device *);
void dasd_generic_shutdown(struct ccw_device *);
void dasd_generic_handle_state_change(struct dasd_device *); void dasd_generic_handle_state_change(struct dasd_device *);
int dasd_generic_pm_freeze(struct ccw_device *); int dasd_generic_pm_freeze(struct ccw_device *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment