1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: cio: ccwgroup - fix unbind behaviour
3 References: bnc#482818,LTC#52098
5 Symptom: Oops after unbinding a ccwgroup device.
6 Problem: There is no special callback to tell a driver to unbind
7 a device - the normal remove is called. In this case
8 the device remains partly registered in the driver core.
9 Solution: Use a bus notifier function to handle this special case
10 and call ungroup since this virtual device can not exist
13 Acked-by: John Jolly <jjolly@suse.de>
15 drivers/s390/cio/ccwgroup.c | 73 +++++++++++++++++++++++++++++++++-----------
16 1 file changed, 56 insertions(+), 17 deletions(-)
18 Index: linux-sles11/drivers/s390/cio/ccwgroup.c
19 ===================================================================
20 --- linux-sles11.orig/drivers/s390/cio/ccwgroup.c 2009-03-09 15:36:56.000000000 +0100
21 +++ linux-sles11/drivers/s390/cio/ccwgroup.c 2009-03-09 15:53:56.000000000 +0100
22 @@ -313,16 +313,32 @@ error:
24 EXPORT_SYMBOL(ccwgroup_create_from_string);
28 +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
31 +static struct notifier_block ccwgroup_nb = {
32 + .notifier_call = ccwgroup_notifier
35 +static int __init init_ccwgroup(void)
37 - return bus_register (&ccwgroup_bus_type);
40 + ret = bus_register(&ccwgroup_bus_type);
44 + ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
46 + bus_unregister(&ccwgroup_bus_type);
52 -cleanup_ccwgroup (void)
53 +static void __exit cleanup_ccwgroup(void)
55 - bus_unregister (&ccwgroup_bus_type);
56 + bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
57 + bus_unregister(&ccwgroup_bus_type);
60 module_init(init_ccwgroup);
61 @@ -390,27 +406,28 @@ ccwgroup_online_store (struct device *de
65 - gdev = to_ccwgroupdev(dev);
70 + gdev = to_ccwgroupdev(dev);
71 + gdrv = to_ccwgroupdrv(dev->driver);
73 - gdrv = to_ccwgroupdrv (gdev->dev.driver);
74 if (!try_module_get(gdrv->owner))
77 ret = strict_strtoul(buf, 0, &value);
83 - ccwgroup_set_online(gdev);
84 + ret = ccwgroup_set_online(gdev);
86 - ccwgroup_set_offline(gdev);
87 + ret = ccwgroup_set_offline(gdev);
91 module_put(gdrv->owner);
93 + return (ret == 0) ? count : ret;
97 @@ -452,13 +469,18 @@ ccwgroup_remove (struct device *dev)
98 struct ccwgroup_device *gdev;
99 struct ccwgroup_driver *gdrv;
101 + device_remove_file(dev, &dev_attr_online);
102 + device_remove_file(dev, &dev_attr_ungroup);
107 gdev = to_ccwgroupdev(dev);
108 gdrv = to_ccwgroupdrv(dev->driver);
110 - device_remove_file(dev, &dev_attr_online);
112 - if (gdrv && gdrv->remove)
119 @@ -467,9 +489,13 @@ static void ccwgroup_shutdown(struct dev
120 struct ccwgroup_device *gdev;
121 struct ccwgroup_driver *gdrv;
126 gdev = to_ccwgroupdev(dev);
127 gdrv = to_ccwgroupdrv(dev->driver);
128 - if (gdrv && gdrv->shutdown)
130 + if (gdrv->shutdown)
131 gdrv->shutdown(gdev);
134 @@ -482,6 +508,19 @@ static struct bus_type ccwgroup_bus_type
135 .shutdown = ccwgroup_shutdown,
139 +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
142 + struct device *dev = data;
144 + if (action == BUS_NOTIFY_UNBIND_DRIVER)
145 + device_schedule_callback(dev, ccwgroup_ungroup_callback);
152 * ccwgroup_driver_register() - register a ccw group driver
153 * @cdriver: driver to be registered