linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / s390 / block / dasd_eckd.c
index b7a7fac..822e2a2 100644 (file)
@@ -1,7 +1,7 @@
-/*
+/* 
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 Horst Hummel <Horst.Hummel@de.ibm.com>
+ *                 Horst Hummel <Horst.Hummel@de.ibm.com> 
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
@@ -9,6 +9,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -23,7 +24,6 @@
 #include <asm/io.h>
 #include <asm/todclk.h>
 #include <asm/uaccess.h>
-#include <asm/cio.h>
 #include <asm/ccwdev.h>
 
 #include "dasd_int.h"
@@ -65,16 +65,16 @@ struct dasd_eckd_private {
 /* The ccw bus type uses this table to find devices that it sends to
  * dasd_eckd_probe */
 static struct ccw_device_id dasd_eckd_ids[] = {
-       { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1},
-       { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2},
-       { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3},
-       { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4},
-       { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5},
-       { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6},
-       { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), .driver_info = 0x7},
-       { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), .driver_info = 0x8},
-       { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), .driver_info = 0x9},
-       { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), .driver_info = 0xa},
+       { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), driver_info: 0x1},
+       { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), driver_info: 0x2},
+       { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), driver_info: 0x3},
+       { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4},
+       { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5},
+       { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6},
+       { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7},
+       { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8},
+       { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9},
+       { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa},
        { /* end of list */ },
 };
 
@@ -89,22 +89,17 @@ dasd_eckd_probe (struct ccw_device *cdev)
 {
        int ret;
 
-       /* set ECKD specific ccw-device options */
-       ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
-       if (ret) {
-               printk(KERN_WARNING
-                      "dasd_eckd_probe: could not set ccw-device options "
-                      "for %s\n", cdev->dev.bus_id);
+       ret = dasd_generic_probe (cdev, &dasd_eckd_discipline);
+       if (ret)
                return ret;
-       }
-       ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
-       return ret;
+       ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE);
+       return 0;
 }
 
 static int
 dasd_eckd_set_online(struct ccw_device *cdev)
 {
-       return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
+       return dasd_generic_set_online (cdev, &dasd_eckd_discipline);
 }
 
 static struct ccw_driver dasd_eckd_driver = {
@@ -215,14 +210,14 @@ check_XRC (struct ccw1         *de_ccw,
 
         /* switch on System Time Stamp - needed for XRC Support */
         if (private->rdc_data.facilities.XRC_supported) {
-
+                
                 data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
                 data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-
+                
                 data->ep_sys_time = get_clock ();
-
+                
                 de_ccw->count = sizeof (struct DE_eckd_data);
-               de_ccw->flags |= CCW_FLAG_SLI;
+                de_ccw->flags |= CCW_FLAG_SLI;  
         }
 
         return;
@@ -301,8 +296,8 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        /* check for sequential prestage - enhance cylinder range */
        if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
            data->attributes.operation == DASD_SEQ_ACCESS) {
-
-               if (end.cyl + private->attrib.nr_cyl < geo.cyl)
+               
+               if (end.cyl + private->attrib.nr_cyl < geo.cyl) 
                        end.cyl += private->attrib.nr_cyl;
                else
                        end.cyl = (geo.cyl - 1);
@@ -322,7 +317,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
        struct dasd_eckd_private *private;
        int sector;
        int dn, d;
-
+                               
        private = (struct dasd_eckd_private *) device->private;
 
        DBF_DEV_EVENT(DBF_INFO, device,
@@ -451,39 +446,6 @@ dasd_eckd_cdl_reclen(int recid)
        return LABEL_SIZE;
 }
 
-/*
- * Generate device unique id that specifies the physical device.
- */
-static int
-dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
-{
-       struct dasd_eckd_private *private;
-       struct dasd_eckd_confdata *confdata;
-
-       private = (struct dasd_eckd_private *) device->private;
-       if (!private)
-               return -ENODEV;
-       confdata = &private->conf_data;
-       if (!confdata)
-               return -ENODEV;
-
-       memset(uid, 0, sizeof(struct dasd_uid));
-       memcpy(uid->vendor, confdata->ned1.HDA_manufacturer,
-              sizeof(uid->vendor) - 1);
-       EBCASC(uid->vendor, sizeof(uid->vendor) - 1);
-       memcpy(uid->serial, confdata->ned1.HDA_location,
-              sizeof(uid->serial) - 1);
-       EBCASC(uid->serial, sizeof(uid->serial) - 1);
-       uid->ssid = confdata->neq.subsystemID;
-       if (confdata->ned2.sneq.flags == 0x40) {
-               uid->alias = 1;
-               uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
-       } else
-               uid->unit_addr = confdata->ned1.unit_addr;
-
-       return 0;
-}
-
 static int
 dasd_eckd_read_conf(struct dasd_device *device)
 {
@@ -545,101 +507,17 @@ dasd_eckd_read_conf(struct dasd_device *device)
        return 0;
 }
 
-/*
- * Build CP for Perform Subsystem Function - SSC.
- */
-struct dasd_ccw_req *
-dasd_eckd_build_psf_ssc(struct dasd_device *device)
-{
-       struct dasd_ccw_req *cqr;
-       struct dasd_psf_ssc_data *psf_ssc_data;
-       struct ccw1 *ccw;
-
-       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
-                                 sizeof(struct dasd_psf_ssc_data),
-                                 device);
-
-       if (IS_ERR(cqr)) {
-              DEV_MESSAGE(KERN_WARNING, device, "%s",
-                          "Could not allocate PSF-SSC request");
-              return cqr;
-       }
-       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
-       psf_ssc_data->order = PSF_ORDER_SSC;
-       psf_ssc_data->suborder = 0x08;
-
-       ccw = cqr->cpaddr;
-       ccw->cmd_code = DASD_ECKD_CCW_PSF;
-       ccw->cda = (__u32)(addr_t)psf_ssc_data;
-       ccw->count = 66;
-
-       cqr->device = device;
-       cqr->expires = 10*HZ;
-       cqr->buildclk = get_clock();
-       cqr->status = DASD_CQR_FILLED;
-       return cqr;
-}
-
-/*
- * Perform Subsystem Function.
- * It is necessary to trigger CIO for channel revalidation since this
- * call might change behaviour of DASD devices.
- */
-static int
-dasd_eckd_psf_ssc(struct dasd_device *device)
-{
-       struct dasd_ccw_req *cqr;
-       int rc;
-
-       cqr = dasd_eckd_build_psf_ssc(device);
-       if (IS_ERR(cqr))
-              return PTR_ERR(cqr);
-
-       rc = dasd_sleep_on(cqr);
-       if (!rc)
-              /* trigger CIO to reprobe devices */
-              css_schedule_reprobe();
-       dasd_sfree_request(cqr, cqr->device);
-       return rc;
-}
-
-/*
- * Valide storage server of current device.
- */
-static int
-dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
-{
-       int rc;
-
-       /* Currently PAV is the only reason to 'validate' server on LPAR */
-       if (dasd_nopav || MACHINE_IS_VM)
-               return 0;
 
-       rc = dasd_eckd_psf_ssc(device);
-       /* may be requested feature is not available on server,
-        * therefore just report error and go ahead */
-       DEV_MESSAGE(KERN_INFO, device,
-                   "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d",
-                   uid->vendor, uid->serial, uid->ssid, rc);
-       /* RE-Read Configuration Data */
-       return dasd_eckd_read_conf(device);
-}
-
-/*
- * Check device characteristics.
- * If the device is accessible using ECKD discipline, the device is enabled.
- */
 static int
 dasd_eckd_check_characteristics(struct dasd_device *device)
 {
        struct dasd_eckd_private *private;
-       struct dasd_uid uid;
        void *rdc_data;
        int rc;
 
        private = (struct dasd_eckd_private *) device->private;
        if (private == NULL) {
-               private = kzalloc(sizeof(struct dasd_eckd_private),
+               private = kmalloc(sizeof(struct dasd_eckd_private),
                                  GFP_KERNEL | GFP_DMA);
                if (private == NULL) {
                        DEV_MESSAGE(KERN_WARNING, device, "%s",
@@ -647,6 +525,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                                    "data");
                        return -ENOMEM;
                }
+               memset(private, 0, sizeof(struct dasd_eckd_private));
                device->private = (void *) private;
        }
        /* Invalidate status of initial analysis. */
@@ -655,29 +534,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
        private->attrib.operation = DASD_NORMAL_CACHE;
        private->attrib.nr_cyl = 0;
 
-       /* Read Configuration Data */
-       rc = dasd_eckd_read_conf(device);
-       if (rc)
-               return rc;
-
-       /* Generate device unique id and register in devmap */
-       rc = dasd_eckd_generate_uid(device, &uid);
-       if (rc)
-               return rc;
-       rc = dasd_set_uid(device->cdev, &uid);
-       if (rc == 1)    /* new server found */
-               rc = dasd_eckd_validate_server(device, &uid);
-       if (rc)
-               return rc;
-
        /* Read Device Characteristics */
        rdc_data = (void *) &(private->rdc_data);
-       memset(rdc_data, 0, sizeof(rdc_data));
        rc = read_dev_chars(device->cdev, &rdc_data, 64);
-       if (rc)
+       if (rc) {
                DEV_MESSAGE(KERN_WARNING, device,
-                           "Read device characteristics returned "
-                           "rc=%d", rc);
+                           "Read device characteristics returned error %d",
+                           rc);
+               return rc;
+       }
 
        DEV_MESSAGE(KERN_INFO, device,
                    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
@@ -688,7 +553,11 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
                    private->rdc_data.no_cyl,
                    private->rdc_data.trk_per_cyl,
                    private->rdc_data.sec_per_trk);
+
+       /* Read Configuration Data */
+       rc = dasd_eckd_read_conf (device);
        return rc;
+
 }
 
 static struct dasd_ccw_req *
@@ -857,7 +726,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
                    ((private->rdc_data.no_cyl *
                      private->rdc_data.trk_per_cyl *
                      blk_per_trk * (device->bp_block >> 9)) >> 1),
-                   ((blk_per_trk * device->bp_block) >> 10),
+                   ((blk_per_trk * device->bp_block) >> 10), 
                    private->uses_cdl ?
                    "compatible disk layout" : "linux disk layout");
 
@@ -1054,7 +923,7 @@ dasd_eckd_format_device(struct dasd_device * device,
                                if (i < 3) {
                                        ect->kl = 4;
                                        ect->dl = sizes_trk0[i] - 4;
-                               }
+                               } 
                        }
                        if ((fdata->intensity & 0x08) &&
                            fdata->start_unit == 1) {
@@ -1354,18 +1223,23 @@ dasd_eckd_fill_info(struct dasd_device * device,
 
 /*
  * Release device ioctl.
- * Buils a channel programm to releases a prior reserved
+ * Buils a channel programm to releases a prior reserved 
  * (see dasd_eckd_reserve) device.
  */
 static int
-dasd_eckd_release(struct dasd_device *device)
+dasd_eckd_release(struct block_device *bdev, int no, long args)
 {
+       struct dasd_device *device;
        struct dasd_ccw_req *cqr;
        int rc;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
+       device = bdev->bd_disk->private_data;
+       if (device == NULL)
+               return -ENODEV;
+
        cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
                                   1, 32, device);
        if (IS_ERR(cqr)) {
@@ -1394,18 +1268,23 @@ dasd_eckd_release(struct dasd_device *device)
 /*
  * Reserve device ioctl.
  * Options are set to 'synchronous wait for interrupt' and
- * 'timeout the request'. This leads to a terminate IO if
- * the interrupt is outstanding for a certain time.
+ * 'timeout the request'. This leads to a terminate IO if 
+ * the interrupt is outstanding for a certain time. 
  */
 static int
-dasd_eckd_reserve(struct dasd_device *device)
+dasd_eckd_reserve(struct block_device *bdev, int no, long args)
 {
+       struct dasd_device *device;
        struct dasd_ccw_req *cqr;
        int rc;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
+       device = bdev->bd_disk->private_data;
+       if (device == NULL)
+               return -ENODEV;
+
        cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
                                   1, 32, device);
        if (IS_ERR(cqr)) {
@@ -1433,18 +1312,23 @@ dasd_eckd_reserve(struct dasd_device *device)
 
 /*
  * Steal lock ioctl - unconditional reserve device.
- * Buils a channel programm to break a device's reservation.
+ * Buils a channel programm to break a device's reservation. 
  * (unconditional reserve)
  */
 static int
-dasd_eckd_steal_lock(struct dasd_device *device)
+dasd_eckd_steal_lock(struct block_device *bdev, int no, long args)
 {
+       struct dasd_device *device;
        struct dasd_ccw_req *cqr;
        int rc;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
+       device = bdev->bd_disk->private_data;
+       if (device == NULL)
+               return -ENODEV;
+
        cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
                                   1, 32, device);
        if (IS_ERR(cqr)) {
@@ -1474,14 +1358,19 @@ dasd_eckd_steal_lock(struct dasd_device *device)
  * Read performance statistics
  */
 static int
-dasd_eckd_performance(struct dasd_device *device, void __user *argp)
+dasd_eckd_performance(struct block_device *bdev, int no, long args)
 {
+       struct dasd_device *device;
        struct dasd_psf_prssd_data *prssdp;
        struct dasd_rssd_perf_stats_t *stats;
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
        int rc;
 
+       device = bdev->bd_disk->private_data;
+       if (device == NULL)
+               return -ENODEV;
+
        cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
                                   1 /* PSF */  + 1 /* RSSD */ ,
                                   (sizeof (struct dasd_psf_prssd_data) +
@@ -1525,9 +1414,8 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
                /* Prepare for Read Subsystem Data */
                prssdp = (struct dasd_psf_prssd_data *) cqr->data;
                stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
-               if (copy_to_user(argp, stats,
-                                sizeof(struct dasd_rssd_perf_stats_t)))
-                       rc = -EFAULT;
+               rc = copy_to_user((long __user *) args, (long *) stats,
+                                 sizeof(struct dasd_rssd_perf_stats_t));
        }
        dasd_sfree_request(cqr, cqr->device);
        return rc;
@@ -1538,22 +1426,27 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
  * Returnes the cache attributes used in Define Extend (DE).
  */
 static int
-dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
+dasd_eckd_get_attrib (struct block_device *bdev, int no, long args)
 {
-       struct dasd_eckd_private *private =
-               (struct dasd_eckd_private *)device->private;
-       struct attrib_data_t attrib = private->attrib;
+       struct dasd_device *device;
+        struct dasd_eckd_private *private;
+        struct attrib_data_t attrib;
        int rc;
 
         if (!capable(CAP_SYS_ADMIN))
                 return -EACCES;
-       if (!argp)
+        if (!args)
                 return -EINVAL;
 
-       rc = 0;
-       if (copy_to_user(argp, (long *) &attrib,
-                        sizeof (struct attrib_data_t)))
-               rc = -EFAULT;
+        device = bdev->bd_disk->private_data;
+        if (device == NULL)
+                return -ENODEV;
+
+        private = (struct dasd_eckd_private *) device->private;
+        attrib = private->attrib;
+
+        rc = copy_to_user((long __user *) args, (long *) &attrib,
+                         sizeof (struct attrib_data_t));
 
        return rc;
 }
@@ -1563,19 +1456,26 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
  * Stores the attributes for cache operation to be used in Define Extend (DE).
  */
 static int
-dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
+dasd_eckd_set_attrib(struct block_device *bdev, int no, long args)
 {
-       struct dasd_eckd_private *private =
-               (struct dasd_eckd_private *)device->private;
+       struct dasd_device *device;
+       struct dasd_eckd_private *private;
        struct attrib_data_t attrib;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
-       if (!argp)
+       if (!args)
                return -EINVAL;
 
-       if (copy_from_user(&attrib, argp, sizeof(struct attrib_data_t)))
+       device = bdev->bd_disk->private_data;
+       if (device == NULL)
+               return -ENODEV;
+
+       if (copy_from_user(&attrib, (void __user *) args,
+                          sizeof (struct attrib_data_t))) {
                return -EFAULT;
+       }
+       private = (struct dasd_eckd_private *) device->private;
        private->attrib = attrib;
 
        DEV_MESSAGE(KERN_INFO, device,
@@ -1584,61 +1484,6 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
        return 0;
 }
 
-static int
-dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
-{
-       switch (cmd) {
-       case BIODASDGATTR:
-               return dasd_eckd_get_attrib(device, argp);
-       case BIODASDSATTR:
-               return dasd_eckd_set_attrib(device, argp);
-       case BIODASDPSRD:
-               return dasd_eckd_performance(device, argp);
-       case BIODASDRLSE:
-               return dasd_eckd_release(device);
-       case BIODASDRSRV:
-               return dasd_eckd_reserve(device);
-       case BIODASDSLCK:
-               return dasd_eckd_steal_lock(device);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-/*
- * Dump the range of CCWs into 'page' buffer
- * and return number of printed chars.
- */
-static inline int
-dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
-{
-       int len, count;
-       char *datap;
-
-       len = 0;
-       while (from <= to) {
-               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
-                              " CCW %p: %08X %08X DAT:",
-                              from, ((int *) from)[0], ((int *) from)[1]);
-
-               /* get pointer to data (consider IDALs) */
-               if (from->flags & CCW_FLAG_IDA)
-                       datap = (char *) *((addr_t *) (addr_t) from->cda);
-               else
-                       datap = (char *) ((addr_t) from->cda);
-
-               /* dump data (max 32 bytes) */
-               for (count = 0; count < from->count && count < 32; count++) {
-                       if (count % 8 == 0) len += sprintf(page + len, " ");
-                       if (count % 4 == 0) len += sprintf(page + len, " ");
-                       len += sprintf(page + len, "%02x", datap[count]);
-               }
-               len += sprintf(page + len, "\n");
-               from++;
-       }
-       return len;
-}
-
 /*
  * Print sense data and related channel program.
  * Parts are printed because printk buffer is only 1024 bytes.
@@ -1648,8 +1493,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                     struct irb *irb)
 {
        char *page;
-       struct ccw1 *first, *last, *fail, *from, *to;
-       int len, sl, sct;
+       struct ccw1 *act, *end, *last;
+       int len, sl, sct, count;
 
        page = (char *) get_zeroed_page(GFP_ATOMIC);
        if (page == NULL) {
@@ -1657,8 +1502,7 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                            "No memory to dump sense data");
                return;
        }
-       /* dump the sense data */
-       len = sprintf(page,  KERN_ERR PRINTK_HEADER
+       len = sprintf(page, KERN_ERR PRINTK_HEADER
                      " I/O status report for device %s:\n",
                      device->cdev->dev.bus_id);
        len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -1683,55 +1527,87 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 
                if (irb->ecw[27] & DASD_SENSE_BIT_0) {
                        /* 24 Byte Sense Data */
-                       sprintf(page + len, KERN_ERR PRINTK_HEADER
-                               " 24 Byte: %x MSG %x, "
-                               "%s MSGb to SYSOP\n",
-                               irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
-                               irb->ecw[1] & 0x10 ? "" : "no");
+                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                                      " 24 Byte: %x MSG %x, "
+                                      "%s MSGb to SYSOP\n",
+                                      irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
+                                      irb->ecw[1] & 0x10 ? "" : "no");
                } else {
                        /* 32 Byte Sense Data */
-                       sprintf(page + len, KERN_ERR PRINTK_HEADER
-                               " 32 Byte: Format: %x "
-                               "Exception class %x\n",
-                               irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
+                       len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                                      " 32 Byte: Format: %x "
+                                      "Exception class %x\n",
+                                      irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
                }
        } else {
-               sprintf(page + len, KERN_ERR PRINTK_HEADER
-                       " SORRY - NO VALID SENSE AVAILABLE\n");
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              " SORRY - NO VALID SENSE AVAILABLE\n");
        }
-       printk("%s", page);
-
-       /* dump the Channel Program (max 140 Bytes per line) */
-       /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
-       first = req->cpaddr;
-       for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-       to = min(first + 6, last);
-       len = sprintf(page,  KERN_ERR PRINTK_HEADER
+       MESSAGE_LOG(KERN_ERR, "%s",
+                   page + sizeof(KERN_ERR PRINTK_HEADER));
+
+       /* dump the Channel Program */
+       /* print first CCWs (maximum 8) */
+       act = req->cpaddr;
+        for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+       end = min(act + 8, last);
+       len = sprintf(page, KERN_ERR PRINTK_HEADER
                      " Related CP in req: %p\n", req);
-       dasd_eckd_dump_ccw_range(first, to, page + len);
-       printk("%s", page);
+       while (act <= end) {
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              " CCW %p: %08X %08X DAT:",
+                              act, ((int *) act)[0], ((int *) act)[1]);
+               for (count = 0; count < 32 && count < act->count;
+                    count += sizeof(int))
+                       len += sprintf(page + len, " %08X",
+                                      ((int *) (addr_t) act->cda)
+                                      [(count>>2)]);
+               len += sprintf(page + len, "\n");
+               act++;
+       }
+       MESSAGE_LOG(KERN_ERR, "%s",
+                   page + sizeof(KERN_ERR PRINTK_HEADER));
 
-       /* print failing CCW area (maximum 4) */
-       /* scsw->cda is either valid or zero  */
+       /* print failing CCW area */
        len = 0;
-       from = ++to;
-       fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
-       if (from <  fail - 2) {
-               from = fail - 2;     /* there is a gap - print header */
-               len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
+       if (act <  ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) {
+               act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2;
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
+       }
+       end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last);
+       while (act <= end) {
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              " CCW %p: %08X %08X DAT:",
+                              act, ((int *) act)[0], ((int *) act)[1]);
+               for (count = 0; count < 32 && count < act->count;
+                    count += sizeof(int))
+                       len += sprintf(page + len, " %08X",
+                                      ((int *) (addr_t) act->cda)
+                                      [(count>>2)]);
+               len += sprintf(page + len, "\n");
+               act++;
        }
-       to = min(fail + 1, last);
-       len += dasd_eckd_dump_ccw_range(from, to, page + len);
 
-       /* print last CCWs (maximum 2) */
-       from = max(from, ++to);
-       if (from < last - 1) {
-               from = last - 1;     /* there is a gap - print header */
+       /* print last CCWs */
+       if (act <  last - 2) {
+               act = last - 2;
                len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
        }
-       len += dasd_eckd_dump_ccw_range(from, last, page + len);
+       while (act <= last) {
+               len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+                              " CCW %p: %08X %08X DAT:",
+                              act, ((int *) act)[0], ((int *) act)[1]);
+               for (count = 0; count < 32 && count < act->count;
+                    count += sizeof(int))
+                       len += sprintf(page + len, " %08X",
+                                      ((int *) (addr_t) act->cda)
+                                      [(count>>2)]);
+               len += sprintf(page + len, "\n");
+               act++;
+       }
        if (len > 0)
-               printk("%s", page);
+               MESSAGE_LOG(KERN_ERR, "%s",
+                           page + sizeof(KERN_ERR PRINTK_HEADER));
        free_page((unsigned long) page);
 }
 
@@ -1766,21 +1642,86 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .free_cp = dasd_eckd_free_cp,
        .dump_sense = dasd_eckd_dump_sense,
        .fill_info = dasd_eckd_fill_info,
-       .ioctl = dasd_eckd_ioctl,
 };
 
 static int __init
 dasd_eckd_init(void)
 {
+       int ret;
+
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDGATTR,
+                              dasd_eckd_get_attrib);
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR,
+                              dasd_eckd_set_attrib);
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD,
+                              dasd_eckd_performance);
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDRLSE,
+                              dasd_eckd_release);
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDRSRV,
+                              dasd_eckd_reserve);
+       dasd_ioctl_no_register(THIS_MODULE, BIODASDSLCK,
+                              dasd_eckd_steal_lock);
+
        ASCEBC(dasd_eckd_discipline.ebcname, 4);
-       return ccw_driver_register(&dasd_eckd_driver);
+
+       ret = ccw_driver_register(&dasd_eckd_driver);
+       if (ret) {
+               dasd_ioctl_no_unregister(THIS_MODULE, BIODASDGATTR,
+                                        dasd_eckd_get_attrib);
+               dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR,
+                                        dasd_eckd_set_attrib);
+               dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD,
+                                        dasd_eckd_performance);
+               dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRLSE,
+                                        dasd_eckd_release);
+               dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRSRV,
+                                        dasd_eckd_reserve);
+               dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSLCK,
+                                        dasd_eckd_steal_lock);
+               return ret;
+       }
+
+       dasd_generic_auto_online(&dasd_eckd_driver);
+       return 0;
 }
 
 static void __exit
 dasd_eckd_cleanup(void)
 {
        ccw_driver_unregister(&dasd_eckd_driver);
+
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDGATTR,
+                                dasd_eckd_get_attrib);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR,
+                                dasd_eckd_set_attrib);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD,
+                                dasd_eckd_performance);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRLSE,
+                                dasd_eckd_release);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRSRV,
+                                dasd_eckd_reserve);
+       dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSLCK,
+                                dasd_eckd_steal_lock);
 }
 
 module_init(dasd_eckd_init);
 module_exit(dasd_eckd_cleanup);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: 1
+ * tab-width: 8
+ * End:
+ */