diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2007-05-31 15:38:06 (GMT) |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-05-31 15:38:12 (GMT) |
commit | 59a8a6e227cf0bc42e5be741ebfea97c222ab9ef (patch) | |
tree | 01ea59ed41a878ee4f780221aa439ca573c870a4 | |
parent | ea1f4eece943968940a399c72c1ca675d51e466e (diff) | |
download | linux-59a8a6e227cf0bc42e5be741ebfea97c222ab9ef.tar.xz |
[S390] cio: Use device_schedule_callback() for removing disconnected devices.
We can't deregister disconnected and orphaned devices directly from
the online attribute's store method, but must take a detour.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | drivers/s390/cio/device.c | 49 |
1 files changed, 38 insertions, 11 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index a8b373f..6b264bd 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -296,30 +296,57 @@ static void ccw_device_unregister(struct ccw_device *cdev) device_del(&cdev->dev); } +static void ccw_device_remove_orphan_cb(struct device *dev) +{ + struct ccw_device *cdev = to_ccwdev(dev); + + ccw_device_unregister(cdev); + put_device(&cdev->dev); +} + +static void ccw_device_remove_sch_cb(struct device *dev) +{ + struct subchannel *sch; + + sch = to_subchannel(dev); + css_sch_device_unregister(sch); + /* Reset intparm to zeroes. */ + sch->schib.pmcw.intparm = 0; + cio_modify(sch); + put_device(&sch->dev); +} + static void ccw_device_remove_disconnected(struct ccw_device *cdev) { - struct subchannel *sch; unsigned long flags; + int rc; + /* * Forced offline in disconnected state means * 'throw away device'. */ if (ccw_device_is_orphan(cdev)) { - /* Deregister ccw device. */ + /* + * Deregister ccw device. + * Unfortunately, we cannot do this directly from the + * attribute method. + */ spin_lock_irqsave(cdev->ccwlock, flags); cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); - ccw_device_unregister(cdev); - put_device(&cdev->dev); - return ; + rc = device_schedule_callback(&cdev->dev, + ccw_device_remove_orphan_cb); + if (rc) + dev_info(&cdev->dev, "Couldn't unregister orphan\n"); + return; } - sch = to_subchannel(cdev->dev.parent); - css_sch_device_unregister(sch); - /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); - put_device(&sch->dev); + /* Deregister subchannel, which will kill the ccw device. */ + rc = device_schedule_callback(cdev->dev.parent, + ccw_device_remove_sch_cb); + if (rc) + dev_info(&cdev->dev, + "Couldn't unregister disconnected device\n"); } int |