diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2018-03-15 10:03:43 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-03-26 10:13:06 -0400 |
commit | 135a8b4ce5d737115571f08c6d0649f1aed6a48a (patch) | |
tree | 2c604872a0bea58568e5435a11797333364d53eb | |
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>
-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: | |||
1073 | return 0; | 1073 | return 0; |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | static int | 1076 | static int io_subchannel_remove(struct subchannel *sch) |
1077 | io_subchannel_remove (struct subchannel *sch) | ||
1078 | { | 1077 | { |
1079 | struct io_subchannel_private *io_priv = to_io_private(sch); | 1078 | struct io_subchannel_private *io_priv = to_io_private(sch); |
1080 | struct ccw_device *cdev; | 1079 | struct ccw_device *cdev; |
@@ -1082,14 +1081,12 @@ io_subchannel_remove (struct subchannel *sch) | |||
1082 | cdev = sch_get_cdev(sch); | 1081 | cdev = sch_get_cdev(sch); |
1083 | if (!cdev) | 1082 | if (!cdev) |
1084 | goto out_free; | 1083 | goto out_free; |
1085 | io_subchannel_quiesce(sch); | 1084 | |
1086 | /* Set ccw device to not operational and drop reference. */ | 1085 | ccw_device_unregister(cdev); |
1087 | spin_lock_irq(cdev->ccwlock); | 1086 | spin_lock_irq(sch->lock); |
1088 | sch_set_cdev(sch, NULL); | 1087 | sch_set_cdev(sch, NULL); |
1089 | set_io_private(sch, NULL); | 1088 | set_io_private(sch, NULL); |
1090 | cdev->private->state = DEV_STATE_NOT_OPER; | 1089 | spin_unlock_irq(sch->lock); |
1091 | spin_unlock_irq(cdev->ccwlock); | ||
1092 | ccw_device_unregister(cdev); | ||
1093 | out_free: | 1090 | out_free: |
1094 | kfree(io_priv); | 1091 | kfree(io_priv); |
1095 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); | 1092 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); |
@@ -1721,6 +1718,7 @@ static int ccw_device_remove(struct device *dev) | |||
1721 | { | 1718 | { |
1722 | struct ccw_device *cdev = to_ccwdev(dev); | 1719 | struct ccw_device *cdev = to_ccwdev(dev); |
1723 | struct ccw_driver *cdrv = cdev->drv; | 1720 | struct ccw_driver *cdrv = cdev->drv; |
1721 | struct subchannel *sch; | ||
1724 | int ret; | 1722 | int ret; |
1725 | 1723 | ||
1726 | if (cdrv->remove) | 1724 | if (cdrv->remove) |
@@ -1746,7 +1744,9 @@ static int ccw_device_remove(struct device *dev) | |||
1746 | ccw_device_set_timeout(cdev, 0); | 1744 | ccw_device_set_timeout(cdev, 0); |
1747 | cdev->drv = NULL; | 1745 | cdev->drv = NULL; |
1748 | cdev->private->int_class = IRQIO_CIO; | 1746 | cdev->private->int_class = IRQIO_CIO; |
1747 | sch = to_subchannel(cdev->dev.parent); | ||
1749 | spin_unlock_irq(cdev->ccwlock); | 1748 | spin_unlock_irq(cdev->ccwlock); |
1749 | io_subchannel_quiesce(sch); | ||
1750 | __disable_cmf(cdev); | 1750 | __disable_cmf(cdev); |
1751 | 1751 | ||
1752 | return 0; | 1752 | return 0; |