]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] s390: DASD device driver.
authorAndrew Morton <akpm@osdl.org>
Thu, 26 Feb 2004 00:19:49 +0000 (16:19 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 26 Feb 2004 00:19:49 +0000 (16:19 -0800)
From: Martin Schwidefsky <schwidefsky@de.ibm.com>

DASD driver fixes:
 - Fix generic_set_online if diag discipline is not availab.e
 - Fix reserve on already reserved device.
 - Use default-erp for unit check without sence information.
 - Revert dasd naming scheme change from dasd<xyz> to dasd_<busid>_. This
   breaks too many user space packages.
 - Extend dasd naming scheme to four letters dasd<aaaa>-dasd<zzzz>.
 - Fix formatting of dasds.

drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_ioctl.c
drivers/s390/block/dasd_proc.c

index f9f8ac0e3b62b377bf425259b83cb630810173a3..3231be77f9a848f68f44e3505328d4f40251c069 100644 (file)
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.123 $
+ * $Revision: 1.129 $
  */
 
 #include <linux/config.h>
@@ -668,7 +668,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)
 
 /*
  * Terminate the current i/o and set the request to failed.
- * ccw_device_halt/ccw_device_clear can fail if the i/o subsystem 
+ * ccw_device_clear can fail if the i/o subsystem
  * is in a bad mood.
  */
 int
@@ -684,10 +684,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
        retries = 0;
        device = (struct dasd_device *) cqr->device;
        while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
-               if (retries < 2)
-                       rc = ccw_device_halt(device->cdev, (long) cqr);
-               else
-                       rc = ccw_device_clear(device->cdev, (long) cqr);
+               rc = ccw_device_clear(device->cdev, (long) cqr);
                switch (rc) {
                case 0: /* termination successful */
                        cqr->status = DASD_CQR_FAILED;
@@ -736,6 +733,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
                return rc;
        device = (struct dasd_device *) cqr->device;
        cqr->startclk = get_clock();
+       cqr->starttime = jiffies;
        rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr,
                              cqr->lpm, 0);
        switch (rc) {
@@ -788,14 +786,11 @@ dasd_timeout_device(unsigned long ptr)
 }
 
 /*
- * Setup timeout for a device.
+ * Setup timeout for a device in jiffies.
  */
 void
 dasd_set_timer(struct dasd_device *device, int expires)
 {
-       /* FIXME: timeouts are based on jiffies but the timeout
-        * comparision in __dasd_check_expire is based on the
-        * TOD clock. */
        if (expires == 0) {
                if (timer_pending(&device->timer))
                        del_timer(&device->timer);
@@ -1002,8 +997,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                                "no memory for dstat...ignoring");
 #ifdef ERP_DEBUG
                /* dump sense data */
-               if (device->discipline && device->discipline->dump_sense)
-                       device->discipline->dump_sense(device, cqr);
+               dasd_log_sense(cqr, irb);
 #endif
                switch (era) {
                case dasd_era_fatal:
@@ -1079,8 +1073,11 @@ restart:
                                cqr->status = DASD_CQR_FAILED;
                                cqr->stopclk = get_clock();
                        } else {
-                               erp_fn = device->discipline->erp_action(cqr);
-                               erp_fn(cqr);
+                               if (cqr->dstat->esw.esw0.erw.cons) {
+                                       erp_fn = device->discipline->erp_action(cqr);
+                                       erp_fn(cqr);
+                               } else
+                                       dasd_default_erp_action(cqr);
                        }
                        goto restart;
                }
@@ -1196,7 +1193,7 @@ __dasd_check_expire(struct dasd_device * device)
        cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
        if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) {
                now = get_clock();
-               if (cqr->expires * (TOD_SEC / HZ) + cqr->startclk < now) {
+               if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) {
                        if (device->discipline->term_IO(cqr) != 0)
                                /* Hmpf, try again in 1/100 sec */
                                dasd_set_timer(device, 1);
@@ -1476,6 +1473,7 @@ _dasd_term_running_cqr(struct dasd_device *device)
                /* termination successful */
                cqr->status = DASD_CQR_QUEUED;
                cqr->startclk = cqr->stopclk = 0;
+               cqr->starttime = 0;
        }
        return rc;
 }
@@ -1782,9 +1780,19 @@ dasd_generic_set_online (struct ccw_device *cdev,
        if (IS_ERR(device))
                return PTR_ERR(device);
 
-       if (device->use_diag_flag)
+       if (device->use_diag_flag) {
+               if (!dasd_diag_discipline_pointer) {
+                       printk (KERN_WARNING
+                               "dasd_generic couldn't online device %s "
+                               "- discipline DIAG not available\n",
+                               cdev->dev.bus_id);
+                       dasd_delete_device(device);
+                       return -ENODEV;
+               }
                discipline = dasd_diag_discipline_pointer;
+       }
        device->discipline = discipline;
+
        rc = discipline->check_device(device);
        if (rc) {
                printk (KERN_WARNING
@@ -1980,6 +1988,7 @@ EXPORT_SYMBOL(dasd_term_IO);
 
 EXPORT_SYMBOL_GPL(dasd_generic_probe);
 EXPORT_SYMBOL_GPL(dasd_generic_remove);
+EXPORT_SYMBOL_GPL(dasd_generic_notify);
 EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
 EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
index d82f9b4a732efbf4e13886aa8e609b8540cc9494..711f1c17207ecf5bcd94f1d0550d21923d2c7012 100644 (file)
@@ -5,7 +5,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
  *
- * $Revision: 1.26 $
+ * $Revision: 1.27 $
  */
 
 #include <linux/timer.h>
@@ -2129,13 +2129,10 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
                /* single program action codes (byte25 bit 0 == '0') */
                switch (sense[25]) {
 
-               case 0x00:      /* success */
-                       DEV_MESSAGE(KERN_DEBUG, device,
-                                   "ERP called for successful request %p"
-                                   " - NO ERP necessary", erp);
-
-                       erp = dasd_3990_erp_cleanup(erp, DASD_CQR_DONE);
-
+               case 0x00:      /* success - use default ERP for retries */
+                       DEV_MESSAGE(KERN_DEBUG, device, "%s",
+                                   "ERP called for successful request"
+                                   " - just retry");
                        break;
 
                case 0x01:      /* fatal error */
index 5d1bb98b6a0a34d5e8d69393a2337570e9657a43..2e42a21d8a0283177f353ad50afa99001d816bed 100644 (file)
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.49 $
+ * $Revision: 1.50 $
  */
 
 #include <linux/config.h>
@@ -1420,6 +1420,9 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                                       "Exception class %x\n",
                                       irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
                }
+       } else {
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              "SORRY - NO VALID SENSE AVAILABLE\n");
        }
 
        MESSAGE(KERN_ERR, "Sense data:\n%s", page);
index cefc8713d8a8a72c16c828c1adff2dc182818a75..62099f5bf582b32ebf8df340aef6dff4431070b7 100644 (file)
@@ -9,7 +9,7 @@
  *
  * gendisk related functions for the dasd driver.
  *
- * $Revision: 1.42 $
+ * $Revision: 1.44 $
  */
 
 #include <linux/config.h>
@@ -31,6 +31,7 @@ int
 dasd_gendisk_alloc(struct dasd_device *device)
 {
        struct gendisk *gdp;
+       int len;
 
        /* Make sure the minor for this device exists. */
        if (device->devindex >= DASD_PER_MAJOR)
@@ -46,8 +47,28 @@ dasd_gendisk_alloc(struct dasd_device *device)
        gdp->fops = &dasd_device_operations;
        gdp->driverfs_dev = &device->cdev->dev;
 
-       /* Set device name */
-       sprintf(gdp->disk_name, "dasd_%s_", device->cdev->dev.bus_id);
+       /*
+        * Set device name.
+        *   dasda - dasdz : 26 devices
+        *   dasdaa - dasdzz : 676 devices, added up = 702
+        *   dasdaaa - dasdzzz : 17576 devices, added up = 18278
+        *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
+        */
+       len = sprintf(gdp->disk_name, "dasd");
+       if (device->devindex > 25) {
+               if (device->devindex > 701) {
+                       if (device->devindex > 18277)
+                               len += sprintf(gdp->disk_name + len, "%c",
+                                              'a'+(((device->devindex-18278)
+                                                    /17576)%26));
+                       len += sprintf(gdp->disk_name + len, "%c",
+                                      'a'+(((device->devindex-702)/676)%26));
+               }
+               len += sprintf(gdp->disk_name + len, "%c",
+                              'a'+(((device->devindex-26)/26)%26));
+       }
+       len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
+
        sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
 
        if (device->ro_flag)
index 72855e135815376ff53d55cbea6a3f1defe1104c..a16438139405909e3ae59ae9e778b6c86f59ff72 100644 (file)
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.52 $
+ * $Revision: 1.54 $
  */
 
 #ifndef DASD_INT_H
 
 #ifdef __KERNEL__
 
+/* erp debugging in dasd.c and dasd_3990_erp.c */
+#define ERP_DEBUG
+
+
 /* we keep old device allocation scheme; IOW, minors are still in 0..255 */
 #define DASD_PER_MAJOR (1U << (MINORBITS - DASD_PARTN_BITS))
 #define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
@@ -157,6 +161,7 @@ struct dasd_ccw_req {
        short retries;                  /* A retry counter */
 
        /* ... and how */
+       unsigned long starttime;        /* jiffies time of request start */
        int expires;                    /* expiration period in jiffies */
        char lpm;                       /* logical path mask */
        void *data;                     /* pointer to data area */
@@ -166,6 +171,7 @@ struct dasd_ccw_req {
        struct dasd_ccw_req *refers;    /* ERP-chain queueing. */
        void *function;                 /* originating ERP action */
 
+       /* these are for statistics only */
        unsigned long long buildclk;    /* TOD-clock of request generation */
        unsigned long long startclk;    /* TOD-clock of request start */
        unsigned long long stopclk;     /* TOD-clock of request interrupt */
index fe47dbeffd87bcc1c0ecd81d037b9dab18a9b1b7..753bb94839e17a187db02bf7a64879b295781a9a 100644 (file)
@@ -147,6 +147,7 @@ dasd_ioctl_enable(struct block_device *bdev, int no, long args)
 
 /*
  * Disable device.
+ * Used by dasdfmt. Disable I/O operations but allow ioctls.
  */
 static int
 dasd_ioctl_disable(struct block_device *bdev, int no, long args)
@@ -167,6 +168,13 @@ dasd_ioctl_disable(struct block_device *bdev, int no, long args)
         * device is DASD_STATE_BASIC that allows to do basic i/o.
         */
        dasd_set_target_state(device, DASD_STATE_BASIC);
+       /*
+        * Set i_size to zero, since read, write, etc. check against this
+        * value.
+        */
+       down(&bdev->bd_sem);
+       i_size_write(bdev->bd_inode, 0);
+       up(&bdev->bd_sem);
        return 0;
 }
 
@@ -237,9 +245,9 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
        if (device->discipline->format_device == NULL)
                return -EPERM;
 
-       if (atomic_read(&device->open_count) > 1) {
+       if (device->state != DASD_STATE_BASIC) {
                DEV_MESSAGE(KERN_WARNING, device, "%s",
-                           "dasd_format: device is open! ");
+                           "dasd_format: device is not disabled! ");
                return -EBUSY;
        }
 
@@ -248,6 +256,16 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
                      fdata->start_unit,
                      fdata->stop_unit, fdata->blksize, fdata->intensity);
 
+       /* Since dasdfmt keeps the device open after it was disabled,
+        * there still exists an inode for this device. We must update i_blkbits,
+        * otherwise we might get errors when enabling the device later.
+        */
+       if (fdata->start_unit == 0) {
+               struct block_device *bdev = bdget_disk(device->gdp, 0);
+               bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
+               bdput(bdev);
+       }
+
        while (fdata->start_unit <= fdata->stop_unit) {
                cqr = device->discipline->format_device(device, fdata);
                if (IS_ERR(cqr))
index 2ea32dafa91576676c0dd6dd5a21e6c7bd499d00..386379bdc3bf624040f1996f169d65e5de6b57ae 100644 (file)
@@ -9,7 +9,7 @@
  *
  * /proc interface for the dasd driver.
  *
- * $Revision: 1.24 $
+ * $Revision: 1.26 $
  */
 
 #include <linux/config.h>
@@ -67,10 +67,15 @@ dasd_devices_show(struct seq_file *m, void *v)
                seq_printf(m, "(none)");
        /* Print kdev. */
        if (device->gdp)
-               seq_printf(m, " at (%3d:%7d)",
+               seq_printf(m, " at (%3d:%6d)",
                           device->gdp->major, device->gdp->first_minor);
        else
-               seq_printf(m, "  at (???:???????)");
+               seq_printf(m, "  at (???:??????)");
+       /* Print device name. */
+       if (device->gdp)
+               seq_printf(m, " is %-8s", device->gdp->disk_name);
+       else
+               seq_printf(m, " is ????????");
        /* Print devices features. */
        substr = device->ro_flag ? "(ro)" : " ";
        seq_printf(m, "%4s: ", substr);