aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/block/dasd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/block/dasd.c')
-rw-r--r--drivers/s390/block/dasd.c48
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)
502static void do_kick_device(struct work_struct *work) 502static 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)
539void dasd_set_target_state(struct dasd_device *device, int target) 541void 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)
2170static int dasd_open(struct block_device *bdev, fmode_t mode) 2180static 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}