]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.arch/s390-10-10-ccwgroup_fix_unbind.patch
Merge branch 'master' into next
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.arch / s390-10-10-ccwgroup_fix_unbind.patch
1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: cio: ccwgroup - fix unbind behaviour
3 References: bnc#482818,LTC#52098
4
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
11 without a driver.
12
13 Acked-by: John Jolly <jjolly@suse.de>
14 ---
15 drivers/s390/cio/ccwgroup.c | 73 +++++++++++++++++++++++++++++++++-----------
16 1 file changed, 56 insertions(+), 17 deletions(-)
17
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:
23 }
24 EXPORT_SYMBOL(ccwgroup_create_from_string);
25
26 -static int __init
27 -init_ccwgroup (void)
28 +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
29 + void *data);
30 +
31 +static struct notifier_block ccwgroup_nb = {
32 + .notifier_call = ccwgroup_notifier
33 +};
34 +
35 +static int __init init_ccwgroup(void)
36 {
37 - return bus_register (&ccwgroup_bus_type);
38 + int ret;
39 +
40 + ret = bus_register(&ccwgroup_bus_type);
41 + if (ret)
42 + return ret;
43 +
44 + ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
45 + if (ret)
46 + bus_unregister(&ccwgroup_bus_type);
47 +
48 + return ret;
49 }
50
51 -static void __exit
52 -cleanup_ccwgroup (void)
53 +static void __exit cleanup_ccwgroup(void)
54 {
55 - bus_unregister (&ccwgroup_bus_type);
56 + bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
57 + bus_unregister(&ccwgroup_bus_type);
58 }
59
60 module_init(init_ccwgroup);
61 @@ -390,27 +406,28 @@ ccwgroup_online_store (struct device *de
62 unsigned long value;
63 int ret;
64
65 - gdev = to_ccwgroupdev(dev);
66 if (!dev->driver)
67 - return count;
68 + return -ENODEV;
69 +
70 + gdev = to_ccwgroupdev(dev);
71 + gdrv = to_ccwgroupdrv(dev->driver);
72
73 - gdrv = to_ccwgroupdrv (gdev->dev.driver);
74 if (!try_module_get(gdrv->owner))
75 return -EINVAL;
76
77 ret = strict_strtoul(buf, 0, &value);
78 if (ret)
79 goto out;
80 - ret = count;
81 +
82 if (value == 1)
83 - ccwgroup_set_online(gdev);
84 + ret = ccwgroup_set_online(gdev);
85 else if (value == 0)
86 - ccwgroup_set_offline(gdev);
87 + ret = ccwgroup_set_offline(gdev);
88 else
89 ret = -EINVAL;
90 out:
91 module_put(gdrv->owner);
92 - return ret;
93 + return (ret == 0) ? count : ret;
94 }
95
96 static ssize_t
97 @@ -452,13 +469,18 @@ ccwgroup_remove (struct device *dev)
98 struct ccwgroup_device *gdev;
99 struct ccwgroup_driver *gdrv;
100
101 + device_remove_file(dev, &dev_attr_online);
102 + device_remove_file(dev, &dev_attr_ungroup);
103 +
104 + if (!dev->driver)
105 + return 0;
106 +
107 gdev = to_ccwgroupdev(dev);
108 gdrv = to_ccwgroupdrv(dev->driver);
109
110 - device_remove_file(dev, &dev_attr_online);
111 -
112 - if (gdrv && gdrv->remove)
113 + if (gdrv->remove)
114 gdrv->remove(gdev);
115 +
116 return 0;
117 }
118
119 @@ -467,9 +489,13 @@ static void ccwgroup_shutdown(struct dev
120 struct ccwgroup_device *gdev;
121 struct ccwgroup_driver *gdrv;
122
123 + if (!dev->driver)
124 + return;
125 +
126 gdev = to_ccwgroupdev(dev);
127 gdrv = to_ccwgroupdrv(dev->driver);
128 - if (gdrv && gdrv->shutdown)
129 +
130 + if (gdrv->shutdown)
131 gdrv->shutdown(gdev);
132 }
133
134 @@ -482,6 +508,19 @@ static struct bus_type ccwgroup_bus_type
135 .shutdown = ccwgroup_shutdown,
136 };
137
138 +
139 +static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
140 + void *data)
141 +{
142 + struct device *dev = data;
143 +
144 + if (action == BUS_NOTIFY_UNBIND_DRIVER)
145 + device_schedule_callback(dev, ccwgroup_ungroup_callback);
146 +
147 + return NOTIFY_OK;
148 +}
149 +
150 +
151 /**
152 * ccwgroup_driver_register() - register a ccw group driver
153 * @cdriver: driver to be registered