s390/dasd: improve speed of dasdfmt
[deliverable/linux.git] / drivers / s390 / block / dasd.c
index f1b7fdc58a5f366ffe054576e8755851f60b2beb..4195cc05efeb3b7bd8354bccb1d2d81c39f5154c 100644 (file)
@@ -246,7 +246,7 @@ static struct dentry *dasd_debugfs_setup(const char *name,
 static int dasd_state_known_to_basic(struct dasd_device *device)
 {
        struct dasd_block *block = device->block;
-       int rc;
+       int rc = 0;
 
        /* Allocate and register gendisk structure. */
        if (block) {
@@ -273,7 +273,8 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
        DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
 
        device->state = DASD_STATE_BASIC;
-       return 0;
+
+       return rc;
 }
 
 /*
@@ -282,6 +283,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
 static int dasd_state_basic_to_known(struct dasd_device *device)
 {
        int rc;
+
        if (device->block) {
                dasd_profile_exit(&device->block->profile);
                if (device->block->debugfs_dentry)
@@ -332,8 +334,10 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
                if (block->base->discipline->do_analysis != NULL)
                        rc = block->base->discipline->do_analysis(block);
                if (rc) {
-                       if (rc != -EAGAIN)
+                       if (rc != -EAGAIN) {
                                device->state = DASD_STATE_UNFMT;
+                               goto out;
+                       }
                        return rc;
                }
                dasd_setup_queue(block);
@@ -341,11 +345,16 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
                             block->blocks << block->s2b_shift);
                device->state = DASD_STATE_READY;
                rc = dasd_scan_partitions(block);
-               if (rc)
+               if (rc) {
                        device->state = DASD_STATE_BASIC;
+                       return rc;
+               }
        } else {
                device->state = DASD_STATE_READY;
        }
+out:
+       if (device->discipline->basic_to_ready)
+               rc = device->discipline->basic_to_ready(device);
        return rc;
 }
 
@@ -368,6 +377,11 @@ static int dasd_state_ready_to_basic(struct dasd_device *device)
 {
        int rc;
 
+       if (device->discipline->ready_to_basic) {
+               rc = device->discipline->ready_to_basic(device);
+               if (rc)
+                       return rc;
+       }
        device->state = DASD_STATE_BASIC;
        if (device->block) {
                struct dasd_block *block = device->block;
@@ -402,16 +416,10 @@ static int dasd_state_unfmt_to_basic(struct dasd_device *device)
 static int
 dasd_state_ready_to_online(struct dasd_device * device)
 {
-       int rc;
        struct gendisk *disk;
        struct disk_part_iter piter;
        struct hd_struct *part;
 
-       if (device->discipline->ready_to_online) {
-               rc = device->discipline->ready_to_online(device);
-               if (rc)
-                       return rc;
-       }
        device->state = DASD_STATE_ONLINE;
        if (device->block) {
                dasd_schedule_block_bh(device->block);
@@ -444,6 +452,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
                if (rc)
                        return rc;
        }
+
        device->state = DASD_STATE_READY;
        if (device->block && !(device->features & DASD_FEATURE_USERAW)) {
                disk = device->block->bdev->bd_disk;
@@ -2223,6 +2232,77 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
        return rc;
 }
 
+static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
+{
+       struct dasd_ccw_req *cqr;
+
+       list_for_each_entry(cqr, ccw_queue, blocklist) {
+               if (cqr->callback_data != DASD_SLEEPON_END_TAG)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
+{
+       struct dasd_device *device;
+       int rc;
+       struct dasd_ccw_req *cqr, *n;
+
+retry:
+       list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
+               device = cqr->startdev;
+               if (cqr->status != DASD_CQR_FILLED) /*could be failed*/
+                       continue;
+
+               if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
+                   !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+                       cqr->status = DASD_CQR_FAILED;
+                       cqr->intrc = -EPERM;
+                       continue;
+               }
+               /*Non-temporary stop condition will trigger fail fast*/
+               if (device->stopped & ~DASD_STOPPED_PENDING &&
+                   test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+                   !dasd_eer_enabled(device)) {
+                       cqr->status = DASD_CQR_FAILED;
+                       cqr->intrc = -EAGAIN;
+                       continue;
+               }
+
+               /*Don't try to start requests if device is stopped*/
+               if (interruptible) {
+                       rc = wait_event_interruptible(
+                               generic_waitq, !device->stopped);
+                       if (rc == -ERESTARTSYS) {
+                               cqr->status = DASD_CQR_FAILED;
+                               cqr->intrc = rc;
+                               continue;
+                       }
+               } else
+                       wait_event(generic_waitq, !(device->stopped));
+
+               if (!cqr->callback)
+                       cqr->callback = dasd_wakeup_cb;
+               cqr->callback_data = DASD_SLEEPON_START_TAG;
+               dasd_add_request_tail(cqr);
+       }
+
+       wait_event(generic_waitq, _wait_for_wakeup_queue(ccw_queue));
+
+       rc = 0;
+       list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
+               if (__dasd_sleep_on_erp(cqr))
+                       rc = 1;
+       }
+       if (rc)
+               goto retry;
+
+
+       return 0;
+}
+
 /*
  * Queue a request to the tail of the device ccw_queue and wait for
  * it's completion.
@@ -2232,6 +2312,15 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
        return _dasd_sleep_on(cqr, 0);
 }
 
+/*
+ * Start requests from a ccw_queue and wait for their completion.
+ */
+int dasd_sleep_on_queue(struct list_head *ccw_queue)
+{
+       return _dasd_sleep_on_queue(ccw_queue, 0);
+}
+EXPORT_SYMBOL(dasd_sleep_on_queue);
+
 /*
  * Queue a request to the tail of the device ccw_queue and wait
  * interruptible for it's completion.
This page took 0.040758 seconds and 5 git commands to generate.