block: implement and enforce request peek/start/fetch
[safe/jmp/linux-2.6] / drivers / s390 / block / dasd.c
index ccf46c9..e64f62d 100644 (file)
@@ -9,6 +9,9 @@
  *
  */
 
+#define KMSG_COMPONENT "dasd"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
 #include <linux/hdreg.h>
+#include <linux/async.h>
 
 #include <asm/ccwdev.h>
 #include <asm/ebcdic.h>
 #include <asm/idals.h>
 #include <asm/todclk.h>
+#include <asm/itcw.h>
 
 /* This is ugly... */
 #define PRINTK_HEADER "dasd:"
@@ -57,12 +62,15 @@ static void dasd_device_tasklet(struct dasd_device *);
 static void dasd_block_tasklet(struct dasd_block *);
 static void do_kick_device(struct work_struct *);
 static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
+static void dasd_device_timeout(unsigned long);
+static void dasd_block_timeout(unsigned long);
 
 /*
  * SECTION: Operations on the device structure.
  */
 static wait_queue_head_t dasd_init_waitq;
 static wait_queue_head_t dasd_flush_wq;
+static wait_queue_head_t generic_waitq;
 
 /*
  * Allocate memory for a new device structure.
@@ -98,6 +106,8 @@ struct dasd_device *dasd_alloc_device(void)
                     (unsigned long) device);
        INIT_LIST_HEAD(&device->ccw_queue);
        init_timer(&device->timer);
+       device->timer.function = dasd_device_timeout;
+       device->timer.data = (unsigned long) device;
        INIT_WORK(&device->kick_work, do_kick_device);
        device->state = DASD_STATE_NEW;
        device->target = DASD_STATE_NEW;
@@ -137,6 +147,8 @@ struct dasd_block *dasd_alloc_block(void)
        INIT_LIST_HEAD(&block->ccw_queue);
        spin_lock_init(&block->queue_lock);
        init_timer(&block->timer);
+       block->timer.function = dasd_block_timeout;
+       block->timer.data = (unsigned long) block;
 
        return block;
 }
@@ -214,7 +226,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
                        return rc;
        }
        /* register 'device' debug area, used for all DBF_DEV_XXX calls */
-       device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
+       device->debug_area = debug_register(dev_name(&device->cdev->dev), 4, 1,
                                            8 * sizeof(long));
        debug_register_view(device->debug_area, &debug_sprintf_view);
        debug_set_level(device->debug_area, DBF_WARNING);
@@ -335,6 +347,9 @@ 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);
@@ -342,8 +357,14 @@ dasd_state_ready_to_online(struct dasd_device * device)
                        return rc;
        }
        device->state = DASD_STATE_ONLINE;
-       if (device->block)
+       if (device->block) {
                dasd_schedule_block_bh(device->block);
+               disk = device->block->bdev->bd_disk;
+               disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+               while ((part = disk_part_iter_next(&piter)))
+                       kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE);
+               disk_part_iter_exit(&piter);
+       }
        return 0;
 }
 
@@ -353,6 +374,9 @@ dasd_state_ready_to_online(struct dasd_device * device)
 static int dasd_state_online_to_ready(struct dasd_device *device)
 {
        int rc;
+       struct gendisk *disk;
+       struct disk_part_iter piter;
+       struct hd_struct *part;
 
        if (device->discipline->online_to_ready) {
                rc = device->discipline->online_to_ready(device);
@@ -360,6 +384,13 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
                        return rc;
        }
        device->state = DASD_STATE_READY;
+       if (device->block) {
+               disk = device->block->bdev->bd_disk;
+               disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+               while ((part = disk_part_iter_next(&piter)))
+                       kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE);
+               disk_part_iter_exit(&piter);
+       }
        return 0;
 }
 
@@ -450,8 +481,10 @@ static void dasd_change_state(struct dasd_device *device)
         if (rc && rc != -EAGAIN)
                 device->target = device->state;
 
-       if (device->state == device->target)
+       if (device->state == device->target) {
                wake_up(&dasd_init_waitq);
+               dasd_put_device(device);
+       }
 
        /* let user-space know that the device status changed */
        kobject_uevent(&device->cdev->dev.kobj, KOBJ_CHANGE);
@@ -483,12 +516,15 @@ void dasd_kick_device(struct dasd_device *device)
  */
 void dasd_set_target_state(struct dasd_device *device, int target)
 {
+       dasd_get_device(device);
        /* If we are in probeonly mode stop at DASD_STATE_READY. */
        if (dasd_probeonly && target > DASD_STATE_READY)
                target = DASD_STATE_READY;
        if (device->target != target) {
-                if (device->state == target)
+               if (device->state == target) {
                        wake_up(&dasd_init_waitq);
+                       dasd_put_device(device);
+               }
                device->target = target;
        }
        if (device->state != device->target)
@@ -567,7 +603,7 @@ static void dasd_profile_end(struct dasd_block *block,
        if (dasd_profile_level != DASD_PROFILE_ON)
                return;
 
-       sectors = req->nr_sectors;
+       sectors = blk_rq_sectors(req);
        if (!cqr->buildclk || !cqr->startclk ||
            !cqr->stopclk || !cqr->endclk ||
            !sectors)
@@ -736,7 +772,7 @@ static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)
                return -EINVAL;
        device = cqr->startdev;
        if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
-               DEV_MESSAGE(KERN_WARNING, device,
+               DBF_DEV_EVENT(DBF_WARNING, device,
                            " dasd_ccw_req 0x%08x magic doesn't match"
                            " discipline 0x%08x",
                            cqr->magic,
@@ -756,6 +792,7 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        int retries, rc;
+       char errorstring[ERRORLENGTH];
 
        /* Check the cqr */
        rc = dasd_check_cqr(cqr);
@@ -789,10 +826,10 @@ int dasd_term_IO(struct dasd_ccw_req *cqr)
                                      "device busy, retry later");
                        break;
                default:
-                       DEV_MESSAGE(KERN_ERR, device,
-                                   "line %d unknown RC=%d, please "
-                                   "report to linux390@de.ibm.com",
-                                   __LINE__, rc);
+                       /* internal error 10 - unknown rc*/
+                       snprintf(errorstring, ERRORLENGTH, "10 %d", rc);
+                       dev_err(&device->cdev->dev, "An error occurred in the "
+                               "DASD device driver, reason=%s\n", errorstring);
                        BUG();
                        break;
                }
@@ -810,6 +847,7 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
 {
        struct dasd_device *device;
        int rc;
+       char errorstring[ERRORLENGTH];
 
        /* Check the cqr */
        rc = dasd_check_cqr(cqr);
@@ -817,17 +855,23 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                return rc;
        device = (struct dasd_device *) cqr->startdev;
        if (cqr->retries < 0) {
-               DEV_MESSAGE(KERN_DEBUG, device,
-                           "start_IO: request %p (%02x/%i) - no retry left.",
-                           cqr, cqr->status, cqr->retries);
+               /* internal error 14 - start_IO run out of retries */
+               sprintf(errorstring, "14 %p", cqr);
+               dev_err(&device->cdev->dev, "An error occurred in the DASD "
+                       "device driver, reason=%s\n", errorstring);
                cqr->status = DASD_CQR_ERROR;
                return -EIO;
        }
        cqr->startclk = get_clock();
        cqr->starttime = jiffies;
        cqr->retries--;
-       rc = ccw_device_start(device->cdev, cqr->cpaddr, (long) cqr,
-                             cqr->lpm, 0);
+       if (cqr->cpmode == 1) {
+               rc = ccw_device_tm_start(device->cdev, cqr->cpaddr,
+                                        (long) cqr, cqr->lpm);
+       } else {
+               rc = ccw_device_start(device->cdev, cqr->cpaddr,
+                                     (long) cqr, cqr->lpm, 0);
+       }
        switch (rc) {
        case 0:
                cqr->status = DASD_CQR_IN_IO;
@@ -836,11 +880,11 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                              cqr);
                break;
        case -EBUSY:
-               DBF_DEV_EVENT(DBF_ERR, device, "%s",
+               DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
                              "start_IO: device busy, retry later");
                break;
        case -ETIMEDOUT:
-               DBF_DEV_EVENT(DBF_ERR, device, "%s",
+               DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
                              "start_IO: request timeout, retry later");
                break;
        case -EACCES:
@@ -850,19 +894,24 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                 * Do a retry with all available pathes.
                 */
                cqr->lpm = LPM_ANYPATH;
-               DBF_DEV_EVENT(DBF_ERR, device, "%s",
+               DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
                              "start_IO: selected pathes gone,"
                              " retry on all pathes");
                break;
        case -ENODEV:
+               DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+                             "start_IO: -ENODEV device gone, retry");
+               break;
        case -EIO:
-               DBF_DEV_EVENT(DBF_ERR, device, "%s",
-                             "start_IO: device gone, retry");
+               DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+                             "start_IO: -EIO device gone, retry");
                break;
        default:
-               DEV_MESSAGE(KERN_ERR, device,
-                           "line %d unknown RC=%d, please report"
-                           " to linux390@de.ibm.com", __LINE__, rc);
+               /* internal error 11 - unknown rc */
+               snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
+               dev_err(&device->cdev->dev,
+                       "An error occurred in the DASD device driver, "
+                       "reason=%s\n", errorstring);
                BUG();
                break;
        }
@@ -895,19 +944,10 @@ static void dasd_device_timeout(unsigned long ptr)
  */
 void dasd_device_set_timer(struct dasd_device *device, int expires)
 {
-       if (expires == 0) {
-               if (timer_pending(&device->timer))
-                       del_timer(&device->timer);
-               return;
-       }
-       if (timer_pending(&device->timer)) {
-               if (mod_timer(&device->timer, jiffies + expires))
-                       return;
-       }
-       device->timer.function = dasd_device_timeout;
-       device->timer.data = (unsigned long) device;
-       device->timer.expires = jiffies + expires;
-       add_timer(&device->timer);
+       if (expires == 0)
+               del_timer(&device->timer);
+       else
+               mod_timer(&device->timer, jiffies + expires);
 }
 
 /*
@@ -915,8 +955,7 @@ void dasd_device_set_timer(struct dasd_device *device, int expires)
  */
 void dasd_device_clear_timer(struct dasd_device *device)
 {
-       if (timer_pending(&device->timer))
-               del_timer(&device->timer);
+       del_timer(&device->timer);
 }
 
 static void dasd_handle_killed_request(struct ccw_device *cdev,
@@ -925,12 +964,14 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
        struct dasd_ccw_req *cqr;
        struct dasd_device *device;
 
+       if (!intparm)
+               return;
        cqr = (struct dasd_ccw_req *) intparm;
        if (cqr->status != DASD_CQR_IN_IO) {
-               MESSAGE(KERN_DEBUG,
+               DBF_EVENT(DBF_DEBUG,
                        "invalid status in handle_killed_request: "
                        "bus_id %s, status %02x",
-                       cdev->dev.bus_id, cqr->status);
+                       dev_name(&cdev->dev), cqr->status);
                return;
        }
 
@@ -938,8 +979,8 @@ static void dasd_handle_killed_request(struct ccw_device *cdev,
        if (device == NULL ||
            device != dasd_device_from_cdev_locked(cdev) ||
            strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
-               MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
-                       cdev->dev.bus_id);
+               DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: "
+                             "bus_id %s", dev_name(&cdev->dev));
                return;
        }
 
@@ -976,31 +1017,26 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        if (IS_ERR(irb)) {
                switch (PTR_ERR(irb)) {
                case -EIO:
-                       dasd_handle_killed_request(cdev, intparm);
                        break;
                case -ETIMEDOUT:
-                       printk(KERN_WARNING"%s(%s): request timed out\n",
-                              __FUNCTION__, cdev->dev.bus_id);
-                       //FIXME - dasd uses own timeout interface...
+                       DBF_EVENT(DBF_WARNING, "%s(%s): request timed out\n",
+                              __func__, dev_name(&cdev->dev));
                        break;
                default:
-                       printk(KERN_WARNING"%s(%s): unknown error %ld\n",
-                              __FUNCTION__, cdev->dev.bus_id, PTR_ERR(irb));
+                       DBF_EVENT(DBF_WARNING, "%s(%s): unknown error %ld\n",
+                              __func__, dev_name(&cdev->dev), PTR_ERR(irb));
                }
+               dasd_handle_killed_request(cdev, intparm);
                return;
        }
 
        now = get_clock();
 
-       DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x",
-                 cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),
-                 (unsigned int) intparm);
-
        /* check for unsolicited interrupts */
        cqr = (struct dasd_ccw_req *) intparm;
-       if (!cqr || ((irb->scsw.cc == 1) &&
-                    (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
-                    (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) {
+       if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
+                    (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
+                    (scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))) {
                if (cqr && cqr->status == DASD_CQR_IN_IO)
                        cqr->status = DASD_CQR_QUEUED;
                device = dasd_device_from_cdev_locked(cdev);
@@ -1016,14 +1052,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
        device = (struct dasd_device *) cqr->startdev;
        if (!device ||
            strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
-               MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
-                       cdev->dev.bus_id);
+               DBF_DEV_EVENT(DBF_DEBUG, device, "invalid device in request: "
+                             "bus_id %s", dev_name(&cdev->dev));
                return;
        }
 
        /* Check for clear pending */
        if (cqr->status == DASD_CQR_CLEAR_PENDING &&
-           irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
+           scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) {
                cqr->status = DASD_CQR_CLEARED;
                dasd_device_clear_timer(device);
                wake_up(&dasd_flush_wq);
@@ -1031,19 +1067,17 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                return;
        }
 
-       /* check status - the request might have been killed by dyn detach */
+       /* check status - the request might have been killed by dyn detach */
        if (cqr->status != DASD_CQR_IN_IO) {
-               MESSAGE(KERN_DEBUG,
-                       "invalid status: bus_id %s, status %02x",
-                       cdev->dev.bus_id, cqr->status);
+               DBF_DEV_EVENT(DBF_DEBUG, device, "invalid status: bus_id %s, "
+                             "status %02x", dev_name(&cdev->dev), cqr->status);
                return;
        }
-       DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
-                     ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
+
        next = NULL;
        expires = 0;
-       if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
-           irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) {
+       if (scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+           scsw_cstat(&irb->scsw) == 0) {
                /* request was completed successfully */
                cqr->status = DASD_CQR_SUCCESS;
                cqr->stopclk = now;
@@ -1054,18 +1088,23 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                }
        } else {  /* error */
                memcpy(&cqr->irb, irb, sizeof(struct irb));
+               /* log sense for every failed I/O to s390 debugfeature */
+               dasd_log_sense_dbf(cqr, irb);
                if (device->features & DASD_FEATURE_ERPLOG) {
                        dasd_log_sense(cqr, irb);
                }
+
                /*
                 * If we don't want complex ERP for this request, then just
                 * reset this and retry it in the fastpath
                 */
                if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags) &&
                    cqr->retries > 0) {
-                       DEV_MESSAGE(KERN_DEBUG, device,
-                                   "default ERP in fastpath (%i retries left)",
-                                   cqr->retries);
+                       if (cqr->lpm == LPM_ANYPATH)
+                               DBF_DEV_EVENT(DBF_DEBUG, device,
+                                             "default ERP in fastpath "
+                                             "(%i retries left)",
+                                             cqr->retries);
                        cqr->lpm    = LPM_ANYPATH;
                        cqr->status = DASD_CQR_QUEUED;
                        next = cqr;
@@ -1076,10 +1115,6 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
            (!device->stopped)) {
                if (device->discipline->start_IO(next) == 0)
                        expires = next->expires;
-               else
-                       DEV_MESSAGE(KERN_DEBUG, device, "%s",
-                                   "Interrupt fastpath "
-                                   "failed!");
        }
        if (expires != 0)
                dasd_device_set_timer(device, expires);
@@ -1150,11 +1185,16 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
        struct list_head *l, *n;
        struct dasd_ccw_req *cqr;
        struct dasd_block *block;
+       void (*callback)(struct dasd_ccw_req *, void *data);
+       void *callback_data;
+       char errorstring[ERRORLENGTH];
 
        list_for_each_safe(l, n, final_queue) {
                cqr = list_entry(l, struct dasd_ccw_req, devlist);
                list_del_init(&cqr->devlist);
                block = cqr->block;
+               callback = cqr->callback;
+               callback_data = cqr->callback_data;
                if (block)
                        spin_lock_bh(&block->queue_lock);
                switch (cqr->status) {
@@ -1168,14 +1208,15 @@ static void __dasd_device_process_final_queue(struct dasd_device *device,
                        cqr->status = DASD_CQR_TERMINATED;
                        break;
                default:
-                       DEV_MESSAGE(KERN_ERR, device,
-                                   "wrong cqr status in __dasd_process_final_queue "
-                                   "for cqr %p, status %x",
-                                   cqr, cqr->status);
+                       /* internal error 12 - wrong cqr status*/
+                       snprintf(errorstring, ERRORLENGTH, "12 %p %x02", cqr, cqr->status);
+                       dev_err(&device->cdev->dev,
+                               "An error occurred in the DASD device driver, "
+                               "reason=%s\n", errorstring);
                        BUG();
                }
                if (cqr->callback != NULL)
-                       (cqr->callback)(cqr, cqr->callback_data);
+                       (callback)(cqr, callback_data);
                if (block)
                        spin_unlock_bh(&block->queue_lock);
        }
@@ -1196,18 +1237,17 @@ static void __dasd_device_check_expire(struct dasd_device *device)
            (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
                if (device->discipline->term_IO(cqr) != 0) {
                        /* Hmpf, try again in 5 sec */
-                       DEV_MESSAGE(KERN_ERR, device,
-                                   "internal error - timeout (%is) expired "
-                                   "for cqr %p, termination failed, "
-                                   "retrying in 5s",
-                                   (cqr->expires/HZ), cqr);
+                       dev_err(&device->cdev->dev,
+                               "cqr %p timed out (%is) but cannot be "
+                               "ended, retrying in 5 s\n",
+                               cqr, (cqr->expires/HZ));
                        cqr->expires += 5*HZ;
                        dasd_device_set_timer(device, 5*HZ);
                } else {
-                       DEV_MESSAGE(KERN_ERR, device,
-                                   "internal error - timeout (%is) expired "
-                                   "for cqr %p (%i retries left)",
-                                   (cqr->expires/HZ), cqr, cqr->retries);
+                       dev_err(&device->cdev->dev,
+                               "cqr %p timed out (%is), %i retries "
+                               "remaining\n", cqr, (cqr->expires/HZ),
+                               cqr->retries);
                }
        }
 }
@@ -1269,10 +1309,9 @@ int dasd_flush_device_queue(struct dasd_device *device)
                        rc = device->discipline->term_IO(cqr);
                        if (rc) {
                                /* unable to terminate requeust */
-                               DEV_MESSAGE(KERN_ERR, device,
-                                           "dasd flush ccw_queue is unable "
-                                           " to terminate request %p",
-                                           cqr);
+                               dev_err(&device->cdev->dev,
+                                       "Flushing the DASD request queue "
+                                       "failed for request %p\n", cqr);
                                /* stop flush processing */
                                goto finished;
                        }
@@ -1405,17 +1444,15 @@ static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
  */
 int dasd_sleep_on(struct dasd_ccw_req *cqr)
 {
-       wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
 
        device = cqr->startdev;
 
-       init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
-       cqr->callback_data = (void *) &wait_q;
+       cqr->callback_data = (void *) &generic_waitq;
        dasd_add_request_tail(cqr);
-       wait_event(wait_q, _wait_for_wakeup(cqr));
+       wait_event(generic_waitq, _wait_for_wakeup(cqr));
 
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
@@ -1428,20 +1465,18 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
  */
 int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
 {
-       wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
 
        device = cqr->startdev;
-       init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
-       cqr->callback_data = (void *) &wait_q;
+       cqr->callback_data = (void *) &generic_waitq;
        dasd_add_request_tail(cqr);
-       rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
+       rc = wait_event_interruptible(generic_waitq, _wait_for_wakeup(cqr));
        if (rc == -ERESTARTSYS) {
                dasd_cancel_req(cqr);
                /* wait (non-interruptible) for final status */
-               wait_event(wait_q, _wait_for_wakeup(cqr));
+               wait_event(generic_waitq, _wait_for_wakeup(cqr));
        }
        rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
        return rc;
@@ -1465,7 +1500,6 @@ static inline int _dasd_term_running_cqr(struct dasd_device *device)
 
 int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
 {
-       wait_queue_head_t wait_q;
        struct dasd_device *device;
        int rc;
 
@@ -1477,9 +1511,8 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
                return rc;
        }
 
-       init_waitqueue_head (&wait_q);
        cqr->callback = dasd_wakeup_cb;
-       cqr->callback_data = (void *) &wait_q;
+       cqr->callback_data = (void *) &generic_waitq;
        cqr->status = DASD_CQR_QUEUED;
        list_add(&cqr->devlist, &device->ccw_queue);
 
@@ -1488,7 +1521,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
 
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
-       wait_event(wait_q, _wait_for_wakeup(cqr));
+       wait_event(generic_waitq, _wait_for_wakeup(cqr));
 
        /* Request status is either done or failed. */
        rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
@@ -1522,10 +1555,9 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
                /* request in IO - terminate IO and release again */
                rc = device->discipline->term_IO(cqr);
                if (rc) {
-                       DEV_MESSAGE(KERN_ERR, device,
-                                   "dasd_cancel_req is unable "
-                                   " to terminate request %p, rc = %d",
-                                   cqr, rc);
+                       dev_err(&device->cdev->dev,
+                               "Cancelling request %p failed with rc=%d\n",
+                               cqr, rc);
                } else {
                        cqr->stopclk = get_clock();
                        rc = 1;
@@ -1567,19 +1599,10 @@ static void dasd_block_timeout(unsigned long ptr)
  */
 void dasd_block_set_timer(struct dasd_block *block, int expires)
 {
-       if (expires == 0) {
-               if (timer_pending(&block->timer))
-                       del_timer(&block->timer);
-               return;
-       }
-       if (timer_pending(&block->timer)) {
-               if (mod_timer(&block->timer, jiffies + expires))
-                       return;
-       }
-       block->timer.function = dasd_block_timeout;
-       block->timer.data = (unsigned long) block;
-       block->timer.expires = jiffies + expires;
-       add_timer(&block->timer);
+       if (expires == 0)
+               del_timer(&block->timer);
+       else
+               mod_timer(&block->timer, jiffies + expires);
 }
 
 /*
@@ -1587,17 +1610,7 @@ void dasd_block_set_timer(struct dasd_block *block, int expires)
  */
 void dasd_block_clear_timer(struct dasd_block *block)
 {
-       if (timer_pending(&block->timer))
-               del_timer(&block->timer);
-}
-
-/*
- * posts the buffer_cache about a finalized request
- */
-static inline void dasd_end_request(struct request *req, int error)
-{
-       if (__blk_end_request(req, error, blk_rq_bytes(req)))
-               BUG();
+       del_timer(&block->timer);
 }
 
 /*
@@ -1612,7 +1625,7 @@ static inline void __dasd_block_process_erp(struct dasd_block *block,
        if (cqr->status == DASD_CQR_DONE)
                DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
        else
-               DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
+               dev_err(&device->cdev->dev, "ERP failed for the DASD\n");
        erp_fn = device->discipline->erp_postaction(cqr);
        erp_fn(cqr);
 }
@@ -1643,18 +1656,14 @@ static void __dasd_process_request_queue(struct dasd_block *block)
        if (basedev->state < DASD_STATE_READY)
                return;
        /* Now we try to fetch requests from the request queue */
-       while (!blk_queue_plugged(queue) &&
-              elv_next_request(queue)) {
-
-               req = elv_next_request(queue);
-
+       while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) {
                if (basedev->features & DASD_FEATURE_READONLY &&
                    rq_data_dir(req) == WRITE) {
                        DBF_DEV_EVENT(DBF_ERR, basedev,
                                      "Rejecting write request %p",
                                      req);
-                       blkdev_dequeue_request(req);
-                       dasd_end_request(req, -EIO);
+                       blk_start_request(req);
+                       __blk_end_request_all(req, -EIO);
                        continue;
                }
                cqr = basedev->discipline->build_cp(basedev, block, req);
@@ -1682,8 +1691,8 @@ static void __dasd_process_request_queue(struct dasd_block *block)
                                      "CCW creation failed (rc=%ld) "
                                      "on request %p",
                                      PTR_ERR(cqr), req);
-                       blkdev_dequeue_request(req);
-                       dasd_end_request(req, -EIO);
+                       blk_start_request(req);
+                       __blk_end_request_all(req, -EIO);
                        continue;
                }
                /*
@@ -1692,7 +1701,7 @@ static void __dasd_process_request_queue(struct dasd_block *block)
                 */
                cqr->callback_data = (void *) req;
                cqr->status = DASD_CQR_FILLED;
-               blkdev_dequeue_request(req);
+               blk_start_request(req);
                list_add_tail(&cqr->blocklist, &block->ccw_queue);
                dasd_profile_start(block, cqr, req);
        }
@@ -1709,7 +1718,7 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
        status = cqr->block->base->discipline->free_cp(cqr, req);
        if (status <= 0)
                error = status ? status : -EIO;
-       dasd_end_request(req, error);
+       __blk_end_request_all(req, error);
 }
 
 /*
@@ -1746,6 +1755,11 @@ restart:
                        goto restart;
                }
 
+               /* log sense for fatal error */
+               if (cqr->status == DASD_CQR_FAILED) {
+                       dasd_log_sense(cqr, &cqr->irb);
+               }
+
                /* First of all call extended error reporting. */
                if (dasd_eer_enabled(base) &&
                    cqr->status == DASD_CQR_FAILED) {
@@ -1893,15 +1907,19 @@ restart_cb:
                wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED));
                /* Process finished ERP request. */
                if (cqr->refers) {
+                       spin_lock_bh(&block->queue_lock);
                        __dasd_block_process_erp(block, cqr);
+                       spin_unlock_bh(&block->queue_lock);
                        /* restart list_for_xx loop since dasd_process_erp
                         * might remove multiple elements */
                        goto restart_cb;
                }
                /* call the callback function */
+               spin_lock_irq(&block->request_queue_lock);
                cqr->endclk = get_clock();
                list_del_init(&cqr->blocklist);
                __dasd_cleanup_cqr(cqr);
+               spin_unlock_irq(&block->request_queue_lock);
        }
        return rc;
 }
@@ -1956,6 +1974,7 @@ static int dasd_alloc_queue(struct dasd_block *block)
        block->request_queue->queuedata = block;
 
        elevator_exit(block->request_queue->elevator);
+       block->request_queue->elevator = NULL;
        rc = elevator_init(block->request_queue, "deadline");
        if (rc) {
                blk_cleanup_queue(block->request_queue);
@@ -1976,8 +1995,11 @@ static void dasd_setup_queue(struct dasd_block *block)
        blk_queue_max_sectors(block->request_queue, max);
        blk_queue_max_phys_segments(block->request_queue, -1L);
        blk_queue_max_hw_segments(block->request_queue, -1L);
-       blk_queue_max_segment_size(block->request_queue, -1L);
-       blk_queue_segment_boundary(block->request_queue, -1L);
+       /* with page sized segments we can translate each segement into
+        * one idaw/tidaw
+        */
+       blk_queue_max_segment_size(block->request_queue, PAGE_SIZE);
+       blk_queue_segment_boundary(block->request_queue, PAGE_SIZE - 1);
        blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);
 }
 
@@ -2003,17 +2025,14 @@ static void dasd_flush_request_queue(struct dasd_block *block)
                return;
 
        spin_lock_irq(&block->request_queue_lock);
-       while ((req = elv_next_request(block->request_queue))) {
-               blkdev_dequeue_request(req);
-               dasd_end_request(req, -EIO);
-       }
+       while ((req = blk_fetch_request(block->request_queue)))
+               __blk_end_request_all(req, -EIO);
        spin_unlock_irq(&block->request_queue_lock);
 }
 
-static int dasd_open(struct inode *inp, struct file *filp)
+static int dasd_open(struct block_device *bdev, fmode_t mode)
 {
-       struct gendisk *disk = inp->i_bdev->bd_disk;
-       struct dasd_block *block = disk->private_data;
+       struct dasd_block *block = bdev->bd_disk->private_data;
        struct dasd_device *base = block->base;
        int rc;
 
@@ -2029,8 +2048,9 @@ static int dasd_open(struct inode *inp, struct file *filp)
        }
 
        if (dasd_probeonly) {
-               DEV_MESSAGE(KERN_INFO, base, "%s",
-                           "No access to device due to probeonly mode");
+               dev_info(&base->cdev->dev,
+                        "Accessing the DASD failed because it is in "
+                        "probeonly mode\n");
                rc = -EPERM;
                goto out;
        }
@@ -2051,9 +2071,8 @@ unlock:
        return rc;
 }
 
-static int dasd_release(struct inode *inp, struct file *filp)
+static int dasd_release(struct gendisk *disk, fmode_t mode)
 {
-       struct gendisk *disk = inp->i_bdev->bd_disk;
        struct dasd_block *block = disk->private_data;
 
        atomic_dec(&block->open_count);
@@ -2089,7 +2108,7 @@ dasd_device_operations = {
        .open           = dasd_open,
        .release        = dasd_release,
        .ioctl          = dasd_ioctl,
-       .compat_ioctl   = dasd_compat_ioctl,
+       .compat_ioctl   = dasd_ioctl,
        .getgeo         = dasd_getgeo,
 };
 
@@ -2120,6 +2139,22 @@ dasd_exit(void)
  * SECTION: common functions for ccw_driver use
  */
 
+static void dasd_generic_auto_online(void *data, async_cookie_t cookie)
+{
+       struct ccw_device *cdev = data;
+       int ret;
+
+       ret = ccw_device_set_online(cdev);
+       if (ret)
+               pr_warning("%s: Setting the DASD online failed with rc=%d\n",
+                          dev_name(&cdev->dev), ret);
+       else {
+               struct dasd_device *device = dasd_device_from_cdev(cdev);
+               wait_event(dasd_init_waitq, _wait_for_device(device));
+               dasd_put_device(device);
+       }
+}
+
 /*
  * Initial attempt at a probe function. this can be simplified once
  * the other detection code is gone.
@@ -2131,16 +2166,16 @@ int dasd_generic_probe(struct ccw_device *cdev,
 
        ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
        if (ret) {
-               printk(KERN_WARNING
+               DBF_EVENT(DBF_WARNING,
                       "dasd_generic_probe: could not set ccw-device options "
-                      "for %s\n", cdev->dev.bus_id);
+                      "for %s\n", dev_name(&cdev->dev));
                return ret;
        }
        ret = dasd_add_sysfs_files(cdev);
        if (ret) {
-               printk(KERN_WARNING
+               DBF_EVENT(DBF_WARNING,
                       "dasd_generic_probe: could not add sysfs entries "
-                      "for %s\n", cdev->dev.bus_id);
+                      "for %s\n", dev_name(&cdev->dev));
                return ret;
        }
        cdev->handler = &dasd_int_handler;
@@ -2151,13 +2186,8 @@ int dasd_generic_probe(struct ccw_device *cdev,
         * initial probe.
         */
        if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) ||
-           (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0))
-               ret = ccw_device_set_online(cdev);
-       if (ret)
-               printk(KERN_WARNING
-                      "dasd_generic_probe: could not initially "
-                      "online ccw-device %s; return code: %d\n",
-                      cdev->dev.bus_id, ret);
+           (dasd_autodetect && dasd_busid_known(dev_name(&cdev->dev)) != 0))
+               async_schedule(dasd_generic_auto_online, cdev);
        return 0;
 }
 
@@ -2220,10 +2250,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,
        discipline = base_discipline;
        if (device->features & DASD_FEATURE_USEDIAG) {
                if (!dasd_diag_discipline_pointer) {
-                       printk (KERN_WARNING
-                               "dasd_generic couldn't online device %s "
-                               "- discipline DIAG not available\n",
-                               cdev->dev.bus_id);
+                       pr_warning("%s Setting the DASD online failed because "
+                                  "of missing DIAG discipline\n",
+                                  dev_name(&cdev->dev));
                        dasd_delete_device(device);
                        return -ENODEV;
                }
@@ -2244,10 +2273,9 @@ int dasd_generic_set_online(struct ccw_device *cdev,
        /* check_device will allocate block device if necessary */
        rc = discipline->check_device(device);
        if (rc) {
-               printk (KERN_WARNING
-                       "dasd_generic couldn't online device %s "
-                       "with discipline %s rc=%i\n",
-                       cdev->dev.bus_id, discipline->name, rc);
+               pr_warning("%s Setting the DASD online with discipline %s "
+                          "failed with rc=%i\n",
+                          dev_name(&cdev->dev), discipline->name, rc);
                module_put(discipline->owner);
                module_put(base_discipline->owner);
                dasd_delete_device(device);
@@ -2256,9 +2284,8 @@ int dasd_generic_set_online(struct ccw_device *cdev,
 
        dasd_set_target_state(device, DASD_STATE_ONLINE);
        if (device->state <= DASD_STATE_KNOWN) {
-               printk (KERN_WARNING
-                       "dasd_generic discipline not found for %s\n",
-                       cdev->dev.bus_id);
+               pr_warning("%s Setting the DASD online failed because of a "
+                          "missing discipline\n", dev_name(&cdev->dev));
                rc = -ENODEV;
                dasd_set_target_state(device, DASD_STATE_NEW);
                if (device->block)
@@ -2266,14 +2293,8 @@ int dasd_generic_set_online(struct ccw_device *cdev,
                dasd_delete_device(device);
        } else
                pr_debug("dasd_generic device %s found\n",
-                               cdev->dev.bus_id);
-
-       /* FIXME: we have to wait for the root device but we don't want
-        * to wait for each single device but for all at once. */
-       wait_event(dasd_init_waitq, _wait_for_device(device));
-
+                               dev_name(&cdev->dev));
        dasd_put_device(device);
-
        return rc;
 }
 
@@ -2298,18 +2319,17 @@ int dasd_generic_set_offline(struct ccw_device *cdev)
         * in the other openers.
         */
        if (device->block) {
-               struct dasd_block *block = device->block;
-               max_count = block->bdev ? 0 : -1;
-               open_count = (int) atomic_read(&block->open_count);
+               max_count = device->block->bdev ? 0 : -1;
+               open_count = atomic_read(&device->block->open_count);
                if (open_count > max_count) {
                        if (open_count > 0)
-                               printk(KERN_WARNING "Can't offline dasd "
-                                      "device with open count = %i.\n",
-                                      open_count);
+                               pr_warning("%s: The DASD cannot be set offline "
+                                          "with open count %i\n",
+                                          dev_name(&cdev->dev), open_count);
                        else
-                               printk(KERN_WARNING "%s",
-                                      "Can't offline dasd device due "
-                                      "to internal use\n");
+                               pr_warning("%s: The DASD cannot be set offline "
+                                          "while it is in use\n",
+                                          dev_name(&cdev->dev));
                        clear_bit(DASD_FLAG_OFFLINE, &device->flags);
                        dasd_put_device(device);
                        return -EBUSY;
@@ -2333,16 +2353,15 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
 {
        struct dasd_device *device;
        struct dasd_ccw_req *cqr;
-       unsigned long flags;
        int ret;
 
-       device = dasd_device_from_cdev(cdev);
+       device = dasd_device_from_cdev_locked(cdev);
        if (IS_ERR(device))
                return 0;
-       spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
        ret = 0;
        switch (event) {
        case CIO_GONE:
+       case CIO_BOXED:
        case CIO_NO_PATH:
                /* First of all call extended error reporting. */
                dasd_eer_write(device, NULL, DASD_EER_NOPATH);
@@ -2369,7 +2388,6 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
                ret = 1;
                break;
        }
-       spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
        dasd_put_device(device);
        return ret;
 }
@@ -2385,8 +2403,10 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
        cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device);
 
        if (IS_ERR(cqr)) {
-               DEV_MESSAGE(KERN_WARNING, device, "%s",
-                           "Could not allocate RDC request");
+               /* internal error 13 - Allocating the RDC request failed*/
+               dev_err(&device->cdev->dev,
+                        "An error occurred in the DASD device driver, "
+                        "reason=%s\n", "13");
                return cqr;
        }
 
@@ -2423,12 +2443,47 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
 }
 EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
 
+/*
+ *   In command mode and transport mode we need to look for sense
+ *   data in different places. The sense data itself is allways
+ *   an array of 32 bytes, so we can unify the sense data access
+ *   for both modes.
+ */
+char *dasd_get_sense(struct irb *irb)
+{
+       struct tsb *tsb = NULL;
+       char *sense = NULL;
+
+       if (scsw_is_tm(&irb->scsw) && (irb->scsw.tm.fcxs == 0x01)) {
+               if (irb->scsw.tm.tcw)
+                       tsb = tcw_get_tsb((struct tcw *)(unsigned long)
+                                         irb->scsw.tm.tcw);
+               if (tsb && tsb->length == 64 && tsb->flags)
+                       switch (tsb->flags & 0x07) {
+                       case 1: /* tsa_iostat */
+                               sense = tsb->tsa.iostat.sense;
+                               break;
+                       case 2: /* tsa_ddpc */
+                               sense = tsb->tsa.ddpc.sense;
+                               break;
+                       default:
+                               /* currently we don't use interrogate data */
+                               break;
+                       }
+       } else if (irb->esw.esw0.erw.cons) {
+               sense = irb->ecw;
+       }
+       return sense;
+}
+EXPORT_SYMBOL_GPL(dasd_get_sense);
+
 static int __init dasd_init(void)
 {
        int rc;
 
        init_waitqueue_head(&dasd_init_waitq);
        init_waitqueue_head(&dasd_flush_wq);
+       init_waitqueue_head(&generic_waitq);
 
        /* register 'common' DASD debug area, used for all DBF_XXX calls */
        dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
@@ -2463,7 +2518,7 @@ static int __init dasd_init(void)
 
        return 0;
 failed:
-       MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors");
+       pr_info("The DASD device driver could not be initialized\n");
        dasd_exit();
        return rc;
 }