aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/cio/ccwgroup.c96
-rw-r--r--drivers/s390/net/cu3088.c20
-rw-r--r--drivers/s390/net/qeth_core_main.c23
-rw-r--r--include/asm-s390/ccwgroup.h7
4 files changed, 82 insertions, 64 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 03914fa81174..f38923e38e92 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -153,44 +153,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
153 return 0; 153 return 0;
154} 154}
155 155
156static int __get_next_bus_id(const char **buf, char *bus_id)
157{
158 int rc, len;
159 char *start, *end;
160
161 start = (char *)*buf;
162 end = strchr(start, ',');
163 if (!end) {
164 /* Last entry. Strip trailing newline, if applicable. */
165 end = strchr(start, '\n');
166 if (end)
167 *end = '\0';
168 len = strlen(start) + 1;
169 } else {
170 len = end - start + 1;
171 end++;
172 }
173 if (len < BUS_ID_SIZE) {
174 strlcpy(bus_id, start, len);
175 rc = 0;
176 } else
177 rc = -EINVAL;
178 *buf = end;
179 return rc;
180}
181
182static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
183{
184 int cssid, ssid, devno;
185
186 /* Must be of form %x.%x.%04x */
187 if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
188 return 0;
189 return 1;
190}
191
156/** 192/**
157 * ccwgroup_create() - create and register a ccw group device 193 * ccwgroup_create_from_string() - create and register a ccw group device
158 * @root: parent device for the new device 194 * @root: parent device for the new device
159 * @creator_id: identifier of creating driver 195 * @creator_id: identifier of creating driver
160 * @cdrv: ccw driver of slave devices 196 * @cdrv: ccw driver of slave devices
161 * @argc: number of slave devices 197 * @num_devices: number of slave devices
162 * @argv: bus ids of slave devices 198 * @buf: buffer containing comma separated bus ids of slave devices
163 * 199 *
164 * Create and register a new ccw group device as a child of @root. Slave 200 * Create and register a new ccw group device as a child of @root. Slave
165 * devices are obtained from the list of bus ids given in @argv[] and must all 201 * devices are obtained from the list of bus ids given in @buf and must all
166 * belong to @cdrv. 202 * belong to @cdrv.
167 * Returns: 203 * Returns:
168 * %0 on success and an error code on failure. 204 * %0 on success and an error code on failure.
169 * Context: 205 * Context:
170 * non-atomic 206 * non-atomic
171 */ 207 */
172int ccwgroup_create(struct device *root, unsigned int creator_id, 208int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
173 struct ccw_driver *cdrv, int argc, char *argv[]) 209 struct ccw_driver *cdrv, int num_devices,
210 const char *buf)
174{ 211{
175 struct ccwgroup_device *gdev; 212 struct ccwgroup_device *gdev;
176 int i; 213 int rc, i;
177 int rc; 214 char tmp_bus_id[BUS_ID_SIZE];
215 const char *curr_buf;
178 216
179 if (argc > 256) /* disallow dumb users */ 217 gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
180 return -EINVAL; 218 GFP_KERNEL);
181
182 gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
183 if (!gdev) 219 if (!gdev)
184 return -ENOMEM; 220 return -ENOMEM;
185 221
186 atomic_set(&gdev->onoff, 0); 222 atomic_set(&gdev->onoff, 0);
187 mutex_init(&gdev->reg_mutex); 223 mutex_init(&gdev->reg_mutex);
188 mutex_lock(&gdev->reg_mutex); 224 mutex_lock(&gdev->reg_mutex);
189 for (i = 0; i < argc; i++) { 225 curr_buf = buf;
190 gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); 226 for (i = 0; i < num_devices && curr_buf; i++) {
191 227 rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
192 /* all devices have to be of the same type in 228 if (rc != 0)
193 * order to be grouped */ 229 goto error;
230 if (!__is_valid_bus_id(tmp_bus_id)) {
231 rc = -EINVAL;
232 goto error;
233 }
234 gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
235 /*
236 * All devices have to be of the same type in
237 * order to be grouped.
238 */
194 if (!gdev->cdev[i] 239 if (!gdev->cdev[i]
195 || gdev->cdev[i]->id.driver_info != 240 || gdev->cdev[i]->id.driver_info !=
196 gdev->cdev[0]->id.driver_info) { 241 gdev->cdev[0]->id.driver_info) {
@@ -204,9 +249,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
204 } 249 }
205 dev_set_drvdata(&gdev->cdev[i]->dev, gdev); 250 dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
206 } 251 }
207 252 /* Check for sufficient number of bus ids. */
253 if (i < num_devices && !curr_buf) {
254 rc = -EINVAL;
255 goto error;
256 }
257 /* Check for trailing stuff. */
258 if (i == num_devices && strlen(curr_buf) > 0) {
259 rc = -EINVAL;
260 goto error;
261 }
208 gdev->creator_id = creator_id; 262 gdev->creator_id = creator_id;
209 gdev->count = argc; 263 gdev->count = num_devices;
210 gdev->dev.bus = &ccwgroup_bus_type; 264 gdev->dev.bus = &ccwgroup_bus_type;
211 gdev->dev.parent = root; 265 gdev->dev.parent = root;
212 gdev->dev.release = ccwgroup_release; 266 gdev->dev.release = ccwgroup_release;
@@ -234,7 +288,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
234 device_remove_file(&gdev->dev, &dev_attr_ungroup); 288 device_remove_file(&gdev->dev, &dev_attr_ungroup);
235 device_unregister(&gdev->dev); 289 device_unregister(&gdev->dev);
236error: 290error:
237 for (i = 0; i < argc; i++) 291 for (i = 0; i < num_devices; i++)
238 if (gdev->cdev[i]) { 292 if (gdev->cdev[i]) {
239 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) 293 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
240 dev_set_drvdata(&gdev->cdev[i]->dev, NULL); 294 dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
@@ -244,6 +298,7 @@ error:
244 put_device(&gdev->dev); 298 put_device(&gdev->dev);
245 return rc; 299 return rc;
246} 300}
301EXPORT_SYMBOL(ccwgroup_create_from_string);
247 302
248static int __init 303static int __init
249init_ccwgroup (void) 304init_ccwgroup (void)
@@ -519,6 +574,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
519MODULE_LICENSE("GPL"); 574MODULE_LICENSE("GPL");
520EXPORT_SYMBOL(ccwgroup_driver_register); 575EXPORT_SYMBOL(ccwgroup_driver_register);
521EXPORT_SYMBOL(ccwgroup_driver_unregister); 576EXPORT_SYMBOL(ccwgroup_driver_unregister);
522EXPORT_SYMBOL(ccwgroup_create);
523EXPORT_SYMBOL(ccwgroup_probe_ccwdev); 577EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
524EXPORT_SYMBOL(ccwgroup_remove_ccwdev); 578EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index 76728ae4b843..8e7697305a4c 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -62,30 +62,14 @@ static struct device *cu3088_root_dev;
62static ssize_t 62static ssize_t
63group_write(struct device_driver *drv, const char *buf, size_t count) 63group_write(struct device_driver *drv, const char *buf, size_t count)
64{ 64{
65 const char *start, *end;
66 char bus_ids[2][BUS_ID_SIZE], *argv[2];
67 int i;
68 int ret; 65 int ret;
69 struct ccwgroup_driver *cdrv; 66 struct ccwgroup_driver *cdrv;
70 67
71 cdrv = to_ccwgroupdrv(drv); 68 cdrv = to_ccwgroupdrv(drv);
72 if (!cdrv) 69 if (!cdrv)
73 return -EINVAL; 70 return -EINVAL;
74 start = buf; 71 ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
75 for (i=0; i<2; i++) { 72 &cu3088_driver, 2, buf);
76 static const char delim[] = {',', '\n'};
77 int len;
78
79 if (!(end = strchr(start, delim[i])))
80 return -EINVAL;
81 len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
82 strlcpy (bus_ids[i], start, len);
83 argv[i] = bus_ids[i];
84 start = end + 1;
85 }
86
87 ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
88 &cu3088_driver, 2, argv);
89 73
90 return (ret == 0) ? count : ret; 74 return (ret == 0) ? count : ret;
91} 75}
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 055f5c3e7b56..231d18c3b6f7 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -3827,27 +3827,8 @@ static struct ccw_driver qeth_ccw_driver = {
3827static int qeth_core_driver_group(const char *buf, struct device *root_dev, 3827static int qeth_core_driver_group(const char *buf, struct device *root_dev,
3828 unsigned long driver_id) 3828 unsigned long driver_id)
3829{ 3829{
3830 const char *start, *end; 3830 return ccwgroup_create_from_string(root_dev, driver_id,
3831 char bus_ids[3][BUS_ID_SIZE], *argv[3]; 3831 &qeth_ccw_driver, 3, buf);
3832 int i;
3833
3834 start = buf;
3835 for (i = 0; i < 3; i++) {
3836 static const char delim[] = { ',', ',', '\n' };
3837 int len;
3838
3839 end = strchr(start, delim[i]);
3840 if (!end)
3841 return -EINVAL;
3842 len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
3843 strncpy(bus_ids[i], start, len);
3844 bus_ids[i][len] = '\0';
3845 start = end + 1;
3846 argv[i] = bus_ids[i];
3847 }
3848
3849 return (ccwgroup_create(root_dev, driver_id,
3850 &qeth_ccw_driver, 3, argv));
3851} 3832}
3852 3833
3853int qeth_core_hardsetup_card(struct qeth_card *card) 3834int qeth_core_hardsetup_card(struct qeth_card *card)
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h
index 289053ef5e60..a27f68985a79 100644
--- a/include/asm-s390/ccwgroup.h
+++ b/include/asm-s390/ccwgroup.h
@@ -57,10 +57,9 @@ struct ccwgroup_driver {
57 57
58extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); 58extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
59extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver); 59extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
60extern int ccwgroup_create (struct device *root, 60int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
61 unsigned int creator_id, 61 struct ccw_driver *cdrv, int num_devices,
62 struct ccw_driver *gdrv, 62 const char *buf);
63 int argc, char *argv[]);
64 63
65extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev); 64extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
66extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev); 65extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);