s390/dasd: Improve dasd format code
authorJan Höppner <hoeppner@linux.vnet.ibm.com>
Wed, 14 Oct 2015 15:01:04 +0000 (17:01 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 7 Mar 2016 12:11:56 +0000 (13:11 +0100)
- Make sure a calling function can rely on data in fdata by resetting to
  its initial values
- Move special treatment for track 0 and 1 to dasd_eckd_build_format
- Replace dangerous backward goto with a loop logic
- Add define for number that specifies the maximum amount of CCWs per
  request and is used for format_step calculation
- Remove unused variable

Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_int.h

index 9083247f55a817cc2592d6b874cf624e09d82cf5..8181d67249425eb5a9e138f4dd331ea7f2286097 100644 (file)
@@ -2349,14 +2349,14 @@ dasd_eckd_build_format(struct dasd_device *base,
                                 * when formatting CDL
                                 */
                                if ((intensity & 0x08) &&
-                                   fdata->start_unit == 0) {
+                                   address.cyl == 0 && address.head == 0) {
                                        if (i < 3) {
                                                ect->kl = 4;
                                                ect->dl = sizes_trk0[i] - 4;
                                        }
                                }
                                if ((intensity & 0x08) &&
-                                   fdata->start_unit == 1) {
+                                   address.cyl == 0 && address.head == 1) {
                                        ect->kl = 44;
                                        ect->dl = LABEL_SIZE - 44;
                                }
@@ -2392,14 +2392,13 @@ dasd_eckd_format_device(struct dasd_device *base,
                        int enable_pav)
 {
        struct dasd_ccw_req *cqr, *n;
-       struct dasd_block *block;
        struct dasd_eckd_private *private;
        struct list_head format_queue;
        struct dasd_device *device;
-       int old_stop, format_step;
-       int step, rc = 0, sleep_rc;
+       int old_start, old_stop, format_step;
+       int step, retry;
+       int rc = 0;
 
-       block = base->block;
        private = (struct dasd_eckd_private *) base->private;
 
        /* Sanity checks. */
@@ -2432,68 +2431,63 @@ dasd_eckd_format_device(struct dasd_device *base,
 
        INIT_LIST_HEAD(&format_queue);
 
+       old_start = fdata->start_unit;
        old_stop = fdata->stop_unit;
-       while (fdata->start_unit <= 1) {
-               fdata->stop_unit = fdata->start_unit;
-               cqr = dasd_eckd_build_format(base, fdata, enable_pav);
-               list_add(&cqr->blocklist, &format_queue);
-
-               fdata->stop_unit = old_stop;
-               fdata->start_unit++;
 
-               if (fdata->start_unit > fdata->stop_unit)
-                       goto sleep;
-       }
+       format_step = DASD_CQR_MAX_CCW / recs_per_track(&private->rdc_data, 0,
+                                                       fdata->blksize);
+       do {
+               retry = 0;
+               while (fdata->start_unit <= old_stop) {
+                       step = fdata->stop_unit - fdata->start_unit + 1;
+                       if (step > format_step) {
+                               fdata->stop_unit =
+                                       fdata->start_unit + format_step - 1;
+                       }
 
-retry:
-       format_step = 255 / recs_per_track(&private->rdc_data, 0,
-                                          fdata->blksize);
-       while (fdata->start_unit <= old_stop) {
-               step = fdata->stop_unit - fdata->start_unit + 1;
-               if (step > format_step)
-                       fdata->stop_unit = fdata->start_unit + format_step - 1;
+                       cqr = dasd_eckd_build_format(base, fdata, enable_pav);
+                       if (IS_ERR(cqr)) {
+                               rc = PTR_ERR(cqr);
+                               if (rc == -ENOMEM) {
+                                       if (list_empty(&format_queue))
+                                               goto out;
+                                       /*
+                                        * not enough memory available, start
+                                        * requests retry after first requests
+                                        * were finished
+                                        */
+                                       retry = 1;
+                                       break;
+                               }
+                               goto out_err;
+                       }
+                       list_add_tail(&cqr->blocklist, &format_queue);
 
-               cqr = dasd_eckd_build_format(base, fdata, enable_pav);
-               if (IS_ERR(cqr)) {
-                       if (PTR_ERR(cqr) == -ENOMEM) {
-                               /*
-                                * not enough memory available
-                                * go to out and start requests
-                                * retry after first requests were finished
-                                */
-                               fdata->stop_unit = old_stop;
-                               goto sleep;
-                       } else
-                               return PTR_ERR(cqr);
+                       fdata->start_unit = fdata->stop_unit + 1;
+                       fdata->stop_unit = old_stop;
                }
-               list_add(&cqr->blocklist, &format_queue);
 
-               fdata->start_unit = fdata->stop_unit + 1;
-               fdata->stop_unit = old_stop;
-       }
+               rc = dasd_sleep_on_queue(&format_queue);
 
-sleep:
-       sleep_rc = dasd_sleep_on_queue(&format_queue);
+out_err:
+               list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
+                       device = cqr->startdev;
+                       private = (struct dasd_eckd_private *) device->private;
+                       if (cqr->status == DASD_CQR_FAILED)
+                               rc = -EIO;
+                       list_del_init(&cqr->blocklist);
+                       dasd_sfree_request(cqr, device);
+                       private->count--;
+               }
 
-       list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
-               device = cqr->startdev;
-               private = (struct dasd_eckd_private *) device->private;
-               if (cqr->status == DASD_CQR_FAILED)
-                       rc = -EIO;
-               list_del_init(&cqr->blocklist);
-               dasd_sfree_request(cqr, device);
-               private->count--;
-       }
+               if (rc)
+                       goto out;
 
-       if (sleep_rc)
-               return sleep_rc;
+       } while (retry);
 
-       /*
-        * in case of ENOMEM we need to retry after
-        * first requests are finished
-        */
-       if (fdata->start_unit <= fdata->stop_unit)
-               goto retry;
+out:
+       fdata->start_unit = old_start;
+       fdata->stop_unit = old_stop;
 
        return rc;
 }
index 4aed5ed708363b0a30be9c1b20201c478f5a7377..ffd77230dce928a1d4b451f50a09bcd4513fa7ea 100644 (file)
@@ -240,6 +240,13 @@ struct dasd_ccw_req {
 /* Signature for error recovery functions. */
 typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
 
+/*
+ * A single CQR can only contain a maximum of 255 CCWs. It is limited by
+ * the locate record and locate record extended count value which can only hold
+ * 1 Byte max.
+ */
+#define DASD_CQR_MAX_CCW 255
+
 /*
  * Unique identifier for dasd device.
  */