aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/ccwgroup.h4
-rw-r--r--drivers/s390/cio/ccwgroup.c69
-rw-r--r--drivers/s390/cio/device.c13
-rw-r--r--drivers/s390/cio/device.h1
4 files changed, 45 insertions, 42 deletions
diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h
index f5cfb7925867..70c3d4d2efe8 100644
--- a/arch/s390/include/asm/ccwgroup.h
+++ b/arch/s390/include/asm/ccwgroup.h
@@ -66,8 +66,8 @@ struct ccwgroup_driver {
66extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); 66extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
67extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver); 67extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
68int ccwgroup_create_dev(struct device *root, unsigned int creator_id, 68int ccwgroup_create_dev(struct device *root, unsigned int creator_id,
69 struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv, 69 struct ccwgroup_driver *gdrv, int num_devices,
70 int num_devices, const char *buf); 70 const char *buf);
71int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, 71int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
72 struct ccw_driver *cdrv, int num_devices, 72 struct ccw_driver *cdrv, int num_devices,
73 const char *buf); 73 const char *buf);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 0c7ed30ac87e..c69cee607aed 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -15,10 +15,13 @@
15#include <linux/ctype.h> 15#include <linux/ctype.h>
16#include <linux/dcache.h> 16#include <linux/dcache.h>
17 17
18#include <asm/cio.h>
18#include <asm/ccwdev.h> 19#include <asm/ccwdev.h>
19#include <asm/ccwgroup.h> 20#include <asm/ccwgroup.h>
20 21
21#define CCW_BUS_ID_SIZE 20 22#include "device.h"
23
24#define CCW_BUS_ID_SIZE 10
22 25
23/* In Linux 2.4, we had a channel device layer called "chandev" 26/* In Linux 2.4, we had a channel device layer called "chandev"
24 * that did all sorts of obscure stuff for networking devices. 27 * that did all sorts of obscure stuff for networking devices.
@@ -254,9 +257,10 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
254 return 0; 257 return 0;
255} 258}
256 259
257static int __get_next_bus_id(const char **buf, char *bus_id) 260static int __get_next_id(const char **buf, struct ccw_dev_id *id)
258{ 261{
259 int rc, len; 262 unsigned int cssid, ssid, devno;
263 int ret = 0, len;
260 char *start, *end; 264 char *start, *end;
261 265
262 start = (char *)*buf; 266 start = (char *)*buf;
@@ -271,50 +275,42 @@ static int __get_next_bus_id(const char **buf, char *bus_id)
271 len = end - start + 1; 275 len = end - start + 1;
272 end++; 276 end++;
273 } 277 }
274 if (len < CCW_BUS_ID_SIZE) { 278 if (len <= CCW_BUS_ID_SIZE) {
275 strlcpy(bus_id, start, len); 279 if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3)
276 rc = 0; 280 ret = -EINVAL;
277 } else 281 } else
278 rc = -EINVAL; 282 ret = -EINVAL;
279 *buf = end;
280 return rc;
281}
282
283static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE])
284{
285 int cssid, ssid, devno;
286 283
287 /* Must be of form %x.%x.%04x */ 284 if (!ret) {
288 if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) 285 id->ssid = ssid;
289 return 0; 286 id->devno = devno;
290 return 1; 287 }
288 *buf = end;
289 return ret;
291} 290}
292 291
293/** 292/**
294 * ccwgroup_create_dev() - create and register a ccw group device 293 * ccwgroup_create_dev() - create and register a ccw group device
295 * @parent: parent device for the new device 294 * @parent: parent device for the new device
296 * @creator_id: identifier of creating driver 295 * @creator_id: identifier of creating driver
297 * @cdrv: ccw driver of slave devices
298 * @gdrv: driver for the new group device 296 * @gdrv: driver for the new group device
299 * @num_devices: number of slave devices 297 * @num_devices: number of slave devices
300 * @buf: buffer containing comma separated bus ids of slave devices 298 * @buf: buffer containing comma separated bus ids of slave devices
301 * 299 *
302 * Create and register a new ccw group device as a child of @parent. Slave 300 * Create and register a new ccw group device as a child of @parent. Slave
303 * devices are obtained from the list of bus ids given in @buf and must all 301 * devices are obtained from the list of bus ids given in @buf.
304 * belong to @cdrv.
305 * Returns: 302 * Returns:
306 * %0 on success and an error code on failure. 303 * %0 on success and an error code on failure.
307 * Context: 304 * Context:
308 * non-atomic 305 * non-atomic
309 */ 306 */
310int ccwgroup_create_dev(struct device *parent, unsigned int creator_id, 307int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
311 struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv, 308 struct ccwgroup_driver *gdrv, int num_devices,
312 int num_devices, const char *buf) 309 const char *buf)
313{ 310{
314 struct ccwgroup_device *gdev; 311 struct ccwgroup_device *gdev;
312 struct ccw_dev_id dev_id;
315 int rc, i; 313 int rc, i;
316 char tmp_bus_id[CCW_BUS_ID_SIZE];
317 const char *curr_buf;
318 314
319 gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), 315 gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
320 GFP_KERNEL); 316 GFP_KERNEL);
@@ -334,22 +330,18 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
334 gdev->dev.release = ccwgroup_release; 330 gdev->dev.release = ccwgroup_release;
335 device_initialize(&gdev->dev); 331 device_initialize(&gdev->dev);
336 332
337 curr_buf = buf; 333 for (i = 0; i < num_devices && buf; i++) {
338 for (i = 0; i < num_devices && curr_buf; i++) { 334 rc = __get_next_id(&buf, &dev_id);
339 rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
340 if (rc != 0) 335 if (rc != 0)
341 goto error; 336 goto error;
342 if (!__is_valid_bus_id(tmp_bus_id)) { 337 gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id);
343 rc = -EINVAL;
344 goto error;
345 }
346 gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
347 /* 338 /*
348 * All devices have to be of the same type in 339 * All devices have to be of the same type in
349 * order to be grouped. 340 * order to be grouped.
350 */ 341 */
351 if (!gdev->cdev[i] 342 if (!gdev->cdev[i] || !gdev->cdev[i]->drv ||
352 || gdev->cdev[i]->id.driver_info != 343 gdev->cdev[i]->drv != gdev->cdev[0]->drv ||
344 gdev->cdev[i]->id.driver_info !=
353 gdev->cdev[0]->id.driver_info) { 345 gdev->cdev[0]->id.driver_info) {
354 rc = -EINVAL; 346 rc = -EINVAL;
355 goto error; 347 goto error;
@@ -365,12 +357,12 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
365 spin_unlock_irq(gdev->cdev[i]->ccwlock); 357 spin_unlock_irq(gdev->cdev[i]->ccwlock);
366 } 358 }
367 /* Check for sufficient number of bus ids. */ 359 /* Check for sufficient number of bus ids. */
368 if (i < num_devices && !curr_buf) { 360 if (i < num_devices) {
369 rc = -EINVAL; 361 rc = -EINVAL;
370 goto error; 362 goto error;
371 } 363 }
372 /* Check for trailing stuff. */ 364 /* Check for trailing stuff. */
373 if (i == num_devices && strlen(curr_buf) > 0) { 365 if (i == num_devices && strlen(buf) > 0) {
374 rc = -EINVAL; 366 rc = -EINVAL;
375 goto error; 367 goto error;
376 } 368 }
@@ -430,8 +422,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
430 struct ccw_driver *cdrv, int num_devices, 422 struct ccw_driver *cdrv, int num_devices,
431 const char *buf) 423 const char *buf)
432{ 424{
433 return ccwgroup_create_dev(root, creator_id, cdrv, NULL, 425 return ccwgroup_create_dev(root, creator_id, NULL, num_devices, buf);
434 num_devices, buf);
435} 426}
436EXPORT_SYMBOL(ccwgroup_create_from_string); 427EXPORT_SYMBOL(ccwgroup_create_from_string);
437 428
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 02d015259461..f8f952d52045 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -695,7 +695,17 @@ static int match_dev_id(struct device *dev, void *data)
695 return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); 695 return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
696} 696}
697 697
698static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) 698/**
699 * get_ccwdev_by_dev_id() - obtain device from a ccw device id
700 * @dev_id: id of the device to be searched
701 *
702 * This function searches all devices attached to the ccw bus for a device
703 * matching @dev_id.
704 * Returns:
705 * If a device is found its reference count is increased and returned;
706 * else %NULL is returned.
707 */
708struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
699{ 709{
700 struct device *dev; 710 struct device *dev;
701 711
@@ -703,6 +713,7 @@ static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
703 713
704 return dev ? to_ccwdev(dev) : NULL; 714 return dev ? to_ccwdev(dev) : NULL;
705} 715}
716EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id);
706 717
707static void ccw_device_do_unbind_bind(struct ccw_device *cdev) 718static void ccw_device_do_unbind_bind(struct ccw_device *cdev)
708{ 719{
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 179824b3082f..6bace6942396 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -101,6 +101,7 @@ int ccw_device_test_sense_data(struct ccw_device *);
101void ccw_device_schedule_sch_unregister(struct ccw_device *); 101void ccw_device_schedule_sch_unregister(struct ccw_device *);
102int ccw_purge_blacklisted(void); 102int ccw_purge_blacklisted(void);
103void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo); 103void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo);
104struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id);
104 105
105/* Function prototypes for device status and basic sense stuff. */ 106/* Function prototypes for device status and basic sense stuff. */
106void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); 107void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);