diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2018-03-15 15:03:43 +0100 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-03-26 16:13:06 +0200 |
commit | 135a8b4ce5d737115571f08c6d0649f1aed6a48a (patch) | |
tree | 2c604872a0bea58568e5435a11797333364d53eb /drivers/s390 | |
parent | 88bf319fc2d6d971ef8692c2cae7f96708340461 (diff) |
s390/cio: fix unbind of io_subchannel_driver
If the io_subchannel_driver is unbound from a subchannel it bluntly kills
all I/O on the subchannel and sets the ccw_device state to not operable
before deregistering the ccw_device. However, for online devices we should
set the device offline (disband path groups etc.) which does not happen if
the device is in not oper state.
Simply deregister the ccw device - ccw_device_remove is smart enough to set
the device offline properly. If everything fails call io_subchannel_quiesce
afterwards as a safeguard.
Reported-by: Shalini Chellathurai Saroja <shalini@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Acked-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/device.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index f50ea035aa9b..1540229a37bb 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1073,8 +1073,7 @@ out_schedule: return 0; } -static int -io_subchannel_remove (struct subchannel *sch) +static int io_subchannel_remove(struct subchannel *sch) { struct io_subchannel_private *io_priv = to_io_private(sch); struct ccw_device *cdev; @@ -1082,14 +1081,12 @@ io_subchannel_remove (struct subchannel *sch) cdev = sch_get_cdev(sch); if (!cdev) goto out_free; - io_subchannel_quiesce(sch); - /* Set ccw device to not operational and drop reference. */ - spin_lock_irq(cdev->ccwlock); + + ccw_device_unregister(cdev); + spin_lock_irq(sch->lock); sch_set_cdev(sch, NULL); set_io_private(sch, NULL); - cdev->private->state = DEV_STATE_NOT_OPER; - spin_unlock_irq(cdev->ccwlock); - ccw_device_unregister(cdev); + spin_unlock_irq(sch->lock); out_free: kfree(io_priv); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); @@ -1721,6 +1718,7 @@ static int ccw_device_remove(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct ccw_driver *cdrv = cdev->drv; + struct subchannel *sch; int ret; if (cdrv->remove) @@ -1746,7 +1744,9 @@ static int ccw_device_remove(struct device *dev) ccw_device_set_timeout(cdev, 0); cdev->drv = NULL; cdev->private->int_class = IRQIO_CIO; + sch = to_subchannel(cdev->dev.parent); spin_unlock_irq(cdev->ccwlock); + io_subchannel_quiesce(sch); __disable_cmf(cdev); return 0; |