#define DASD_FEATURE_INITIAL_ONLINE  0x04
 #define DASD_FEATURE_ERPLOG         0x08
 #define DASD_FEATURE_FAILFAST       0x10
+#define DASD_FEATURE_FAILONSLCK      0x20
 
 #define DASD_PARTN_BITS 2
 
 
                return rc;
        }
        device = (struct dasd_device *) cqr->startdev;
+       if (((cqr->block &&
+             test_bit(DASD_FLAG_LOCK_STOLEN, &cqr->block->base->flags)) ||
+            test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags)) &&
+           !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+               DBF_DEV_EVENT(DBF_DEBUG, device, "start_IO: return request %p "
+                             "because of stolen lock", cqr);
+               cqr->status = DASD_CQR_ERROR;
+               cqr->intrc = -EPERM;
+               return -EPERM;
+       }
        if (cqr->retries < 0) {
                /* internal error 14 - start_IO run out of retries */
                sprintf(errorstring, "14 %p", cqr);
        }
 
        now = get_clock();
-
-       /* check for unsolicited interrupts */
        cqr = (struct dasd_ccw_req *) intparm;
-       if (!cqr || ((scsw_cc(&irb->scsw) == 1) &&
-                    (scsw_fctl(&irb->scsw) & SCSW_FCTL_START_FUNC) &&
-                    ((scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND) ||
-                     (scsw_stctl(&irb->scsw) == (SCSW_STCTL_STATUS_PEND |
-                                                 SCSW_STCTL_ALERT_STATUS))))) {
-               if (cqr && cqr->status == DASD_CQR_IN_IO)
-                       cqr->status = DASD_CQR_QUEUED;
+       /* check for conditions that should be handled immediately */
+       if (!cqr ||
+           !(scsw_dstat(&irb->scsw) == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+             scsw_cstat(&irb->scsw) == 0)) {
                if (cqr)
                        memcpy(&cqr->irb, irb, sizeof(*irb));
                device = dasd_device_from_cdev_locked(cdev);
                        dasd_put_device(device);
                        return;
                }
-               device->discipline->dump_sense_dbf(device, irb,
-                                                  "unsolicited");
-               if ((device->features & DASD_FEATURE_ERPLOG))
-                       device->discipline->dump_sense(device, cqr,
-                                                      irb);
-               dasd_device_clear_timer(device);
-               device->discipline->handle_unsolicited_interrupt(device,
-                                                                irb);
+               device->discipline->dump_sense_dbf(device, irb, "int");
+               if (device->features & DASD_FEATURE_ERPLOG)
+                       device->discipline->dump_sense(device, cqr, irb);
+               device->discipline->check_for_device_change(device, cqr, irb);
                dasd_put_device(device);
-               return;
        }
+       if (!cqr)
+               return;
 
        device = (struct dasd_device *) cqr->startdev;
        if (!device ||
                                          struct dasd_ccw_req, devlist);
                }
        } 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
                goto out;
        if (test_bit(DASD_FLAG_OFFLINE, &device->flags) ||
           device->state != device->target ||
-          !device->discipline->handle_unsolicited_interrupt){
+          !device->discipline->check_for_device_change){
                dasd_put_device(device);
                goto out;
        }
-
-       dasd_device_clear_timer(device);
-       device->discipline->handle_unsolicited_interrupt(device, irb);
+       if (device->discipline->dump_sense_dbf)
+               device->discipline->dump_sense_dbf(device, irb, "uc");
+       device->discipline->check_for_device_change(device, NULL, irb);
        dasd_put_device(device);
 out:
        return UC_TODO_RETRY;
                        continue;
                if (cqr->status != DASD_CQR_FILLED) /* could be failed */
                        continue;
-
+               if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
+                   !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+                       cqr->status = DASD_CQR_FAILED;
+                       cqr->intrc = -EPERM;
+                       continue;
+               }
                /* Non-temporary stop condition will trigger fail fast */
                if (device->stopped & ~DASD_STOPPED_PENDING &&
                    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
                        cqr->status = DASD_CQR_FAILED;
                        continue;
                }
-
                /* Don't try to start requests if device is stopped */
                if (interruptible) {
                        rc = wait_event_interruptible(
        int rc;
 
        device = cqr->startdev;
+       if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
+           !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+               cqr->status = DASD_CQR_FAILED;
+               cqr->intrc = -EPERM;
+               return -EIO;
+       }
        spin_lock_irq(get_ccwdev_lock(device->cdev));
        rc = _dasd_term_running_cqr(device);
        if (rc) {
                spin_unlock_irq(get_ccwdev_lock(device->cdev));
                return rc;
        }
-
        cqr->callback = dasd_wakeup_cb;
        cqr->callback_data = DASD_SLEEPON_START_TAG;
        cqr->status = DASD_CQR_QUEUED;
        list_for_each_entry(cqr, &block->ccw_queue, blocklist) {
                if (cqr->status != DASD_CQR_FILLED)
                        continue;
+               if (test_bit(DASD_FLAG_LOCK_STOLEN, &block->base->flags) &&
+                   !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+                       cqr->status = DASD_CQR_FAILED;
+                       cqr->intrc = -EPERM;
+                       dasd_schedule_block_bh(block);
+                       continue;
+               }
                /* Non-temporary stop condition will trigger fail fast */
                if (block->base->stopped & ~DASD_STOPPED_PENDING &&
                    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
 
 
 static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store);
 
+static ssize_t dasd_reservation_policy_show(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       struct dasd_devmap *devmap;
+       int rc = 0;
+
+       devmap = dasd_find_busid(dev_name(dev));
+       if (IS_ERR(devmap)) {
+               rc = snprintf(buf, PAGE_SIZE, "ignore\n");
+       } else {
+               spin_lock(&dasd_devmap_lock);
+               if (devmap->features & DASD_FEATURE_FAILONSLCK)
+                       rc = snprintf(buf, PAGE_SIZE, "fail\n");
+               else
+                       rc = snprintf(buf, PAGE_SIZE, "ignore\n");
+               spin_unlock(&dasd_devmap_lock);
+       }
+       return rc;
+}
+
+static ssize_t dasd_reservation_policy_store(struct device *dev,
+                                            struct device_attribute *attr,
+                                            const char *buf, size_t count)
+{
+       struct dasd_devmap *devmap;
+       int rc;
+
+       devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(devmap))
+               return PTR_ERR(devmap);
+       rc = 0;
+       spin_lock(&dasd_devmap_lock);
+       if (sysfs_streq("ignore", buf))
+               devmap->features &= ~DASD_FEATURE_FAILONSLCK;
+       else if (sysfs_streq("fail", buf))
+               devmap->features |= DASD_FEATURE_FAILONSLCK;
+       else
+               rc = -EINVAL;
+       if (devmap->device)
+               devmap->device->features = devmap->features;
+       spin_unlock(&dasd_devmap_lock);
+       if (rc)
+               return rc;
+       else
+               return count;
+}
+
+static DEVICE_ATTR(reservation_policy, 0644,
+                  dasd_reservation_policy_show, dasd_reservation_policy_store);
+
+static ssize_t dasd_reservation_state_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct dasd_device *device;
+       int rc = 0;
+
+       device = dasd_device_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(device))
+               return snprintf(buf, PAGE_SIZE, "none\n");
+
+       if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags))
+               rc = snprintf(buf, PAGE_SIZE, "reserved\n");
+       else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags))
+               rc = snprintf(buf, PAGE_SIZE, "lost\n");
+       else
+               rc = snprintf(buf, PAGE_SIZE, "none\n");
+       dasd_put_device(device);
+       return rc;
+}
+
+static ssize_t dasd_reservation_state_store(struct device *dev,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t count)
+{
+       struct dasd_device *device;
+       int rc = 0;
+
+       device = dasd_device_from_cdev(to_ccwdev(dev));
+       if (IS_ERR(device))
+               return -ENODEV;
+       if (sysfs_streq("reset", buf))
+               clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags);
+       else
+               rc = -EINVAL;
+       dasd_put_device(device);
+
+       if (rc)
+               return rc;
+       else
+               return count;
+}
+
+static DEVICE_ATTR(last_known_reservation_state, 0644,
+                  dasd_reservation_state_show, dasd_reservation_state_store);
+
 static struct attribute * dasd_attrs[] = {
        &dev_attr_readonly.attr,
        &dev_attr_discipline.attr,
        &dev_attr_erplog.attr,
        &dev_attr_failfast.attr,
        &dev_attr_expires.attr,
+       &dev_attr_reservation_policy.attr,
+       &dev_attr_last_known_reservation_state.attr,
        NULL,
 };
 
 
 
        dasd_eckd_fill_rcd_cqr(device, cqr, rcd_buffer, lpm);
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+       set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
        cqr->retries = 5;
        rc = dasd_sleep_on_immediatly(cqr);
        return rc;
        return dasd_default_erp_postaction;
 }
 
-
-static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
-                                                  struct irb *irb)
+static void dasd_eckd_check_for_device_change(struct dasd_device *device,
+                                             struct dasd_ccw_req *cqr,
+                                             struct irb *irb)
 {
        char mask;
        char *sense = NULL;
                        /* schedule worker to reload device */
                        dasd_reload_device(device);
                }
-
                dasd_generic_handle_state_change(device);
                return;
        }
 
-       /* summary unit check */
        sense = dasd_get_sense(irb);
-       if (sense && (sense[7] == 0x0D) &&
+       if (!sense)
+               return;
+
+       /* summary unit check */
+       if ((sense[7] == 0x0D) &&
            (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) {
                dasd_alias_handle_summary_unit_check(device, irb);
                return;
        }
 
        /* service information message SIM */
-       if (sense && !(sense[27] & DASD_SENSE_BIT_0) &&
+       if (!cqr && !(sense[27] & DASD_SENSE_BIT_0) &&
            ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)) {
                dasd_3990_erp_handle_sim(device, sense);
-               dasd_schedule_device_bh(device);
                return;
        }
 
-       if ((scsw_cc(&irb->scsw) == 1) && !sense &&
-           (scsw_fctl(&irb->scsw) == SCSW_FCTL_START_FUNC) &&
-           (scsw_actl(&irb->scsw) == SCSW_ACTL_START_PEND) &&
-           (scsw_stctl(&irb->scsw) == SCSW_STCTL_STATUS_PEND)) {
-               /* fake irb do nothing, they are handled elsewhere */
-               dasd_schedule_device_bh(device);
-               return;
+       /* loss of device reservation is handled via base devices only
+        * as alias devices may be used with several bases
+        */
+       if (device->block && (sense[7] == 0x3F) &&
+           (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
+           test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) {
+               if (device->features & DASD_FEATURE_FAILONSLCK)
+                       set_bit(DASD_FLAG_LOCK_STOLEN, &device->flags);
+               clear_bit(DASD_FLAG_IS_RESERVED, &device->flags);
+               dev_err(&device->cdev->dev,
+                       "The device reservation was lost\n");
        }
-
-       dasd_schedule_device_bh(device);
-       return;
-};
-
+}
 
 static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                                               struct dasd_device *startdev,
        cqr->status = DASD_CQR_FILLED;
 
        rc = dasd_sleep_on_immediatly(cqr);
+       if (!rc)
+               clear_bit(DASD_FLAG_IS_RESERVED, &device->flags);
 
        if (useglobal)
                mutex_unlock(&dasd_reserve_mutex);
        cqr->status = DASD_CQR_FILLED;
 
        rc = dasd_sleep_on_immediatly(cqr);
+       if (!rc)
+               set_bit(DASD_FLAG_IS_RESERVED, &device->flags);
 
        if (useglobal)
                mutex_unlock(&dasd_reserve_mutex);
        cqr->status = DASD_CQR_FILLED;
 
        rc = dasd_sleep_on_immediatly(cqr);
+       if (!rc)
+               set_bit(DASD_FLAG_IS_RESERVED, &device->flags);
 
        if (useglobal)
                mutex_unlock(&dasd_reserve_mutex);
        cqr->memdev = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
+       set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
        cqr->retries = 5;
        cqr->expires = 10 * HZ;
        cqr->buildclk = get_clock();
        .format_device = dasd_eckd_format_device,
        .erp_action = dasd_eckd_erp_action,
        .erp_postaction = dasd_eckd_erp_postaction,
-       .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
+       .check_for_device_change = dasd_eckd_check_for_device_change,
        .build_cp = dasd_eckd_build_alias_cp,
        .free_cp = dasd_eckd_free_alias_cp,
        .dump_sense = dasd_eckd_dump_sense,
 
        cqr->retries = 255;
        cqr->expires = 10 * HZ;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+       set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);
 
        ccw = cqr->cpaddr;
        ccw->cmd_code = DASD_ECKD_CCW_SNSS;
 
        return NULL;
 }
 
-static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
-                                                  struct irb *irb)
+static void dasd_fba_check_for_device_change(struct dasd_device *device,
+                                            struct dasd_ccw_req *cqr,
+                                            struct irb *irb)
 {
        char mask;
 
        /* first of all check for state change pending interrupt */
        mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-       if ((irb->scsw.cmd.dstat & mask) == mask) {
+       if ((irb->scsw.cmd.dstat & mask) == mask)
                dasd_generic_handle_state_change(device);
-               return;
-       }
-
-       /* check for unsolicited interrupts */
-       DBF_DEV_EVENT(DBF_WARNING, device, "%s",
-                   "unsolicited interrupt received");
-       device->discipline->dump_sense_dbf(device, irb, "unsolicited");
-       dasd_schedule_device_bh(device);
-       return;
 };
 
 static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
        .handle_terminated_request = dasd_fba_handle_terminated_request,
        .erp_action = dasd_fba_erp_action,
        .erp_postaction = dasd_fba_erp_postaction,
-       .handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
+       .check_for_device_change = dasd_fba_check_for_device_change,
        .build_cp = dasd_fba_build_cp,
        .free_cp = dasd_fba_free_cp,
        .dump_sense = dasd_fba_dump_sense,
 
 #define DASD_CQR_FLAGS_USE_ERP   0     /* use ERP for this request */
 #define DASD_CQR_FLAGS_FAILFAST  1     /* FAILFAST */
 #define DASD_CQR_VERIFY_PATH    2      /* path verification request */
+#define DASD_CQR_ALLOW_SLOCK    3      /* Try this request even when lock was
+                                        * stolen. Should not be combined with
+                                        * DASD_CQR_FLAGS_USE_ERP
+                                        */
 
 /* Signature for error recovery functions. */
 typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
        void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
                            struct irb *);
        void (*dump_sense_dbf) (struct dasd_device *, struct irb *, char *);
-
-       void (*handle_unsolicited_interrupt) (struct dasd_device *,
-                                             struct irb *);
+       void (*check_for_device_change) (struct dasd_device *,
+                                        struct dasd_ccw_req *,
+                                        struct irb *);
 
         /* i/o control functions. */
        int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
                                         * confuse this with the user specified
                                         * read-only feature.
                                         */
+#define DASD_FLAG_IS_RESERVED  7       /* The device is reserved */
+#define DASD_FLAG_LOCK_STOLEN  8       /* The device lock was stolen */
+
 
 void dasd_put_device_wake(struct dasd_device *);