diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/block/dasd.c | 23 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 1 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 1 | ||||
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 7 | ||||
-rw-r--r-- | drivers/s390/cio/ccwreq.c | 15 | ||||
-rw-r--r-- | drivers/s390/cio/ioasm.h | 15 |
6 files changed, 47 insertions, 15 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 0e86247d791..33975e922d6 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1186,6 +1186,29 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, dasd_schedule_device_bh(device); } +enum uc_todo dasd_generic_uc_handler(struct ccw_device *cdev, struct irb *irb) +{ + struct dasd_device *device; + + device = dasd_device_from_cdev_locked(cdev); + + if (IS_ERR(device)) + goto out; + if (test_bit(DASD_FLAG_OFFLINE, &device->flags) || + device->state != device->target || + !device->discipline->handle_unsolicited_interrupt){ + dasd_put_device(device); + goto out; + } + + dasd_device_clear_timer(device); + device->discipline->handle_unsolicited_interrupt(device, irb); + dasd_put_device(device); +out: + return UC_TODO_RETRY; +} +EXPORT_SYMBOL_GPL(dasd_generic_uc_handler); + /* * If we have an error on a dasd_block layer request then we cancel * and return all further requests from the same dasd_block as well. diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 5b1cd8d6e97..ab84da5592e 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3436,6 +3436,7 @@ static struct ccw_driver dasd_eckd_driver = { .freeze = dasd_generic_pm_freeze, .thaw = dasd_generic_restore_device, .restore = dasd_generic_restore_device, + .uc_handler = dasd_generic_uc_handler, }; /* diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 32fac186ba3..49b431d135e 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -617,6 +617,7 @@ int dasd_generic_notify(struct ccw_device *, int); void dasd_generic_handle_state_change(struct dasd_device *); int dasd_generic_pm_freeze(struct ccw_device *); int dasd_generic_restore_device(struct ccw_device *); +enum uc_todo dasd_generic_uc_handler(struct ccw_device *, struct irb *); int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int); char *dasd_get_sense(struct irb *); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 5f97ea2ee6b..97b25d68e3e 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -123,8 +123,10 @@ ccwgroup_release (struct device *dev) for (i = 0; i < gdev->count; i++) { if (gdev->cdev[i]) { + spin_lock_irq(gdev->cdev[i]->ccwlock); if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) dev_set_drvdata(&gdev->cdev[i]->dev, NULL); + spin_unlock_irq(gdev->cdev[i]->ccwlock); put_device(&gdev->cdev[i]->dev); } } @@ -262,11 +264,14 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, goto error; } /* Don't allow a device to belong to more than one group. */ + spin_lock_irq(gdev->cdev[i]->ccwlock); if (dev_get_drvdata(&gdev->cdev[i]->dev)) { + spin_unlock_irq(gdev->cdev[i]->ccwlock); rc = -EINVAL; goto error; } dev_set_drvdata(&gdev->cdev[i]->dev, gdev); + spin_unlock_irq(gdev->cdev[i]->ccwlock); } /* Check for sufficient number of bus ids. */ if (i < num_devices && !curr_buf) { @@ -303,8 +308,10 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, error: for (i = 0; i < num_devices; i++) if (gdev->cdev[i]) { + spin_lock_irq(gdev->cdev[i]->ccwlock); if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) dev_set_drvdata(&gdev->cdev[i]->dev, NULL); + spin_unlock_irq(gdev->cdev[i]->ccwlock); put_device(&gdev->cdev[i]->dev); gdev->cdev[i] = NULL; } diff --git a/drivers/s390/cio/ccwreq.c b/drivers/s390/cio/ccwreq.c index 37df42af05e..7f206ed44fd 100644 --- a/drivers/s390/cio/ccwreq.c +++ b/drivers/s390/cio/ccwreq.c @@ -159,6 +159,7 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) { struct irb *irb = &cdev->private->irb; struct cmd_scsw *scsw = &irb->scsw.cmd; + enum uc_todo todo; /* Perform BASIC SENSE if needed. */ if (ccw_device_accumulate_and_sense(cdev, lcirb)) @@ -178,6 +179,20 @@ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) /* Check for command reject. */ if (irb->ecw[0] & SNS0_CMD_REJECT) return IO_REJECTED; + /* Ask the driver what to do */ + if (cdev->drv && cdev->drv->uc_handler) { + todo = cdev->drv->uc_handler(cdev, lcirb); + switch (todo) { + case UC_TODO_RETRY: + return IO_STATUS_ERROR; + case UC_TODO_RETRY_ON_NEW_PATH: + return IO_PATH_ERROR; + case UC_TODO_STOP: + return IO_REJECTED; + default: + return IO_STATUS_ERROR; + } + } /* Assume that unexpected SENSE data implies an error. */ return IO_STATUS_ERROR; } diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h index 75926279263..fac06155773 100644 --- a/drivers/s390/cio/ioasm.h +++ b/drivers/s390/cio/ioasm.h @@ -23,21 +23,6 @@ struct tpi_info { * Some S390 specific IO instructions as inline */ -static inline int stsch(struct subchannel_id schid, struct schib *addr) -{ - register struct subchannel_id reg1 asm ("1") = schid; - int ccode; - - asm volatile( - " stsch 0(%3)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode), "=m" (*addr) - : "d" (reg1), "a" (addr) - : "cc"); - return ccode; -} - static inline int stsch_err(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; |