diff options
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r-- | drivers/s390/block/dasd.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 5905936c7c60..9ab1ae40565f 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/buffer_head.h> | 20 | #include <linux/buffer_head.h> |
21 | #include <linux/hdreg.h> | 21 | #include <linux/hdreg.h> |
22 | #include <linux/async.h> | 22 | #include <linux/async.h> |
23 | #include <linux/mutex.h> | ||
23 | 24 | ||
24 | #include <asm/ccwdev.h> | 25 | #include <asm/ccwdev.h> |
25 | #include <asm/ebcdic.h> | 26 | #include <asm/ebcdic.h> |
@@ -112,6 +113,7 @@ struct dasd_device *dasd_alloc_device(void) | |||
112 | INIT_WORK(&device->restore_device, do_restore_device); | 113 | INIT_WORK(&device->restore_device, do_restore_device); |
113 | device->state = DASD_STATE_NEW; | 114 | device->state = DASD_STATE_NEW; |
114 | device->target = DASD_STATE_NEW; | 115 | device->target = DASD_STATE_NEW; |
116 | mutex_init(&device->state_mutex); | ||
115 | 117 | ||
116 | return device; | 118 | return device; |
117 | } | 119 | } |
@@ -321,8 +323,8 @@ static int dasd_state_ready_to_basic(struct dasd_device *device) | |||
321 | device->state = DASD_STATE_READY; | 323 | device->state = DASD_STATE_READY; |
322 | return rc; | 324 | return rc; |
323 | } | 325 | } |
324 | dasd_destroy_partitions(block); | ||
325 | dasd_flush_request_queue(block); | 326 | dasd_flush_request_queue(block); |
327 | dasd_destroy_partitions(block); | ||
326 | block->blocks = 0; | 328 | block->blocks = 0; |
327 | block->bp_block = 0; | 329 | block->bp_block = 0; |
328 | block->s2b_shift = 0; | 330 | block->s2b_shift = 0; |
@@ -484,10 +486,8 @@ static void dasd_change_state(struct dasd_device *device) | |||
484 | if (rc) | 486 | if (rc) |
485 | device->target = device->state; | 487 | device->target = device->state; |
486 | 488 | ||
487 | if (device->state == device->target) { | 489 | if (device->state == device->target) |
488 | wake_up(&dasd_init_waitq); | 490 | wake_up(&dasd_init_waitq); |
489 | dasd_put_device(device); | ||
490 | } | ||
491 | 491 | ||
492 | /* let user-space know that the device status changed */ | 492 | /* let user-space know that the device status changed */ |
493 | kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); | 493 | kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE); |
@@ -502,7 +502,9 @@ static void dasd_change_state(struct dasd_device *device) | |||
502 | static void do_kick_device(struct work_struct *work) | 502 | static void do_kick_device(struct work_struct *work) |
503 | { | 503 | { |
504 | struct dasd_device *device = container_of(work, struct dasd_device, kick_work); | 504 | struct dasd_device *device = container_of(work, struct dasd_device, kick_work); |
505 | mutex_lock(&device->state_mutex); | ||
505 | dasd_change_state(device); | 506 | dasd_change_state(device); |
507 | mutex_unlock(&device->state_mutex); | ||
506 | dasd_schedule_device_bh(device); | 508 | dasd_schedule_device_bh(device); |
507 | dasd_put_device(device); | 509 | dasd_put_device(device); |
508 | } | 510 | } |
@@ -539,18 +541,19 @@ void dasd_restore_device(struct dasd_device *device) | |||
539 | void dasd_set_target_state(struct dasd_device *device, int target) | 541 | void dasd_set_target_state(struct dasd_device *device, int target) |
540 | { | 542 | { |
541 | dasd_get_device(device); | 543 | dasd_get_device(device); |
544 | mutex_lock(&device->state_mutex); | ||
542 | /* If we are in probeonly mode stop at DASD_STATE_READY. */ | 545 | /* If we are in probeonly mode stop at DASD_STATE_READY. */ |
543 | if (dasd_probeonly && target > DASD_STATE_READY) | 546 | if (dasd_probeonly && target > DASD_STATE_READY) |
544 | target = DASD_STATE_READY; | 547 | target = DASD_STATE_READY; |
545 | if (device->target != target) { | 548 | if (device->target != target) { |
546 | if (device->state == target) { | 549 | if (device->state == target) |
547 | wake_up(&dasd_init_waitq); | 550 | wake_up(&dasd_init_waitq); |
548 | dasd_put_device(device); | ||
549 | } | ||
550 | device->target = target; | 551 | device->target = target; |
551 | } | 552 | } |
552 | if (device->state != device->target) | 553 | if (device->state != device->target) |
553 | dasd_change_state(device); | 554 | dasd_change_state(device); |
555 | mutex_unlock(&device->state_mutex); | ||
556 | dasd_put_device(device); | ||
554 | } | 557 | } |
555 | 558 | ||
556 | /* | 559 | /* |
@@ -1000,12 +1003,20 @@ static void dasd_handle_killed_request(struct ccw_device *cdev, | |||
1000 | return; | 1003 | return; |
1001 | } | 1004 | } |
1002 | 1005 | ||
1003 | device = (struct dasd_device *) cqr->startdev; | 1006 | device = dasd_device_from_cdev_locked(cdev); |
1004 | if (device == NULL || | 1007 | if (IS_ERR(device)) { |
1005 | device != dasd_device_from_cdev_locked(cdev) || | 1008 | DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s", |
1006 | strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { | 1009 | "unable to get device from cdev"); |
1010 | return; | ||
1011 | } | ||
1012 | |||
1013 | if (!cqr->startdev || | ||
1014 | device != cqr->startdev || | ||
1015 | strncmp(cqr->startdev->discipline->ebcname, | ||
1016 | (char *) &cqr->magic, 4)) { | ||
1007 | DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s", | 1017 | DBF_EVENT_DEVID(DBF_DEBUG, cdev, "%s", |
1008 | "invalid device in request"); | 1018 | "invalid device in request"); |
1019 | dasd_put_device(device); | ||
1009 | return; | 1020 | return; |
1010 | } | 1021 | } |
1011 | 1022 | ||
@@ -1692,7 +1703,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr) | |||
1692 | cqr, rc); | 1703 | cqr, rc); |
1693 | } else { | 1704 | } else { |
1694 | cqr->stopclk = get_clock(); | 1705 | cqr->stopclk = get_clock(); |
1695 | rc = 1; | ||
1696 | } | 1706 | } |
1697 | break; | 1707 | break; |
1698 | default: /* already finished or clear pending - do nothing */ | 1708 | default: /* already finished or clear pending - do nothing */ |
@@ -2170,9 +2180,13 @@ static void dasd_flush_request_queue(struct dasd_block *block) | |||
2170 | static int dasd_open(struct block_device *bdev, fmode_t mode) | 2180 | static int dasd_open(struct block_device *bdev, fmode_t mode) |
2171 | { | 2181 | { |
2172 | struct dasd_block *block = bdev->bd_disk->private_data; | 2182 | struct dasd_block *block = bdev->bd_disk->private_data; |
2173 | struct dasd_device *base = block->base; | 2183 | struct dasd_device *base; |
2174 | int rc; | 2184 | int rc; |
2175 | 2185 | ||
2186 | if (!block) | ||
2187 | return -ENODEV; | ||
2188 | |||
2189 | base = block->base; | ||
2176 | atomic_inc(&block->open_count); | 2190 | atomic_inc(&block->open_count); |
2177 | if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { | 2191 | if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { |
2178 | rc = -ENODEV; | 2192 | rc = -ENODEV; |
@@ -2285,11 +2299,6 @@ static void dasd_generic_auto_online(void *data, async_cookie_t cookie) | |||
2285 | if (ret) | 2299 | if (ret) |
2286 | pr_warning("%s: Setting the DASD online failed with rc=%d\n", | 2300 | pr_warning("%s: Setting the DASD online failed with rc=%d\n", |
2287 | dev_name(&cdev->dev), ret); | 2301 | dev_name(&cdev->dev), ret); |
2288 | else { | ||
2289 | struct dasd_device *device = dasd_device_from_cdev(cdev); | ||
2290 | wait_event(dasd_init_waitq, _wait_for_device(device)); | ||
2291 | dasd_put_device(device); | ||
2292 | } | ||
2293 | } | 2302 | } |
2294 | 2303 | ||
2295 | /* | 2304 | /* |
@@ -2424,6 +2433,9 @@ int dasd_generic_set_online(struct ccw_device *cdev, | |||
2424 | } else | 2433 | } else |
2425 | pr_debug("dasd_generic device %s found\n", | 2434 | pr_debug("dasd_generic device %s found\n", |
2426 | dev_name(&cdev->dev)); | 2435 | dev_name(&cdev->dev)); |
2436 | |||
2437 | wait_event(dasd_init_waitq, _wait_for_device(device)); | ||
2438 | |||
2427 | dasd_put_device(device); | 2439 | dasd_put_device(device); |
2428 | return rc; | 2440 | return rc; |
2429 | } | 2441 | } |