s390/ccwgroup: exploit ccwdev_by_dev_id
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Tue, 15 May 2012 15:52:07 +0000 (17:52 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 16 May 2012 12:42:46 +0000 (14:42 +0200)
Instead of finding devices via driver_find_device use the bus_find_device
wrapper get_ccwdev_by_dev_id. This allows us to get rid of the ccw_driver
argument of ccwgroup_create_dev and thus simplify the interface.

Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/ccwgroup.h
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h

index f5cfb79..70c3d4d 100644 (file)
@@ -66,8 +66,8 @@ struct ccwgroup_driver {
 extern int  ccwgroup_driver_register   (struct ccwgroup_driver *cdriver);
 extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
 int ccwgroup_create_dev(struct device *root, unsigned int creator_id,
-                       struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv,
-                       int num_devices, const char *buf);
+                       struct ccwgroup_driver *gdrv, int num_devices,
+                       const char *buf);
 int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
                                struct ccw_driver *cdrv, int num_devices,
                                const char *buf);
index 0c7ed30..c69cee6 100644 (file)
 #include <linux/ctype.h>
 #include <linux/dcache.h>
 
+#include <asm/cio.h>
 #include <asm/ccwdev.h>
 #include <asm/ccwgroup.h>
 
-#define CCW_BUS_ID_SIZE                20
+#include "device.h"
+
+#define CCW_BUS_ID_SIZE                10
 
 /* In Linux 2.4, we had a channel device layer called "chandev"
  * that did all sorts of obscure stuff for networking devices.
@@ -254,9 +257,10 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
        return 0;
 }
 
-static int __get_next_bus_id(const char **buf, char *bus_id)
+static int __get_next_id(const char **buf, struct ccw_dev_id *id)
 {
-       int rc, len;
+       unsigned int cssid, ssid, devno;
+       int ret = 0, len;
        char *start, *end;
 
        start = (char *)*buf;
@@ -271,50 +275,42 @@ static int __get_next_bus_id(const char **buf, char *bus_id)
                len = end - start + 1;
                end++;
        }
-       if (len < CCW_BUS_ID_SIZE) {
-               strlcpy(bus_id, start, len);
-               rc = 0;
+       if (len <= CCW_BUS_ID_SIZE) {
+               if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3)
+                       ret = -EINVAL;
        } else
-               rc = -EINVAL;
-       *buf = end;
-       return rc;
-}
-
-static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE])
-{
-       int cssid, ssid, devno;
+               ret = -EINVAL;
 
-       /* Must be of form %x.%x.%04x */
-       if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
-               return 0;
-       return 1;
+       if (!ret) {
+               id->ssid = ssid;
+               id->devno = devno;
+       }
+       *buf = end;
+       return ret;
 }
 
 /**
  * ccwgroup_create_dev() - create and register a ccw group device
  * @parent: parent device for the new device
  * @creator_id: identifier of creating driver
- * @cdrv: ccw driver of slave devices
  * @gdrv: driver for the new group device
  * @num_devices: number of slave devices
  * @buf: buffer containing comma separated bus ids of slave devices
  *
  * Create and register a new ccw group device as a child of @parent. Slave
- * devices are obtained from the list of bus ids given in @buf and must all
- * belong to @cdrv.
+ * devices are obtained from the list of bus ids given in @buf.
  * Returns:
  *  %0 on success and an error code on failure.
  * Context:
  *  non-atomic
  */
 int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
-                       struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv,
-                       int num_devices, const char *buf)
+                       struct ccwgroup_driver *gdrv, int num_devices,
+                       const char *buf)
 {
        struct ccwgroup_device *gdev;
+       struct ccw_dev_id dev_id;
        int rc, i;
-       char tmp_bus_id[CCW_BUS_ID_SIZE];
-       const char *curr_buf;
 
        gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
                       GFP_KERNEL);
@@ -334,22 +330,18 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
        gdev->dev.release = ccwgroup_release;
        device_initialize(&gdev->dev);
 
-       curr_buf = buf;
-       for (i = 0; i < num_devices && curr_buf; i++) {
-               rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
+       for (i = 0; i < num_devices && buf; i++) {
+               rc = __get_next_id(&buf, &dev_id);
                if (rc != 0)
                        goto error;
-               if (!__is_valid_bus_id(tmp_bus_id)) {
-                       rc = -EINVAL;
-                       goto error;
-               }
-               gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
+               gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id);
                /*
                 * All devices have to be of the same type in
                 * order to be grouped.
                 */
-               if (!gdev->cdev[i]
-                   || gdev->cdev[i]->id.driver_info !=
+               if (!gdev->cdev[i] || !gdev->cdev[i]->drv ||
+                   gdev->cdev[i]->drv != gdev->cdev[0]->drv ||
+                   gdev->cdev[i]->id.driver_info !=
                    gdev->cdev[0]->id.driver_info) {
                        rc = -EINVAL;
                        goto error;
@@ -365,12 +357,12 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id,
                spin_unlock_irq(gdev->cdev[i]->ccwlock);
        }
        /* Check for sufficient number of bus ids. */
-       if (i < num_devices && !curr_buf) {
+       if (i < num_devices) {
                rc = -EINVAL;
                goto error;
        }
        /* Check for trailing stuff. */
-       if (i == num_devices && strlen(curr_buf) > 0) {
+       if (i == num_devices && strlen(buf) > 0) {
                rc = -EINVAL;
                goto error;
        }
@@ -430,8 +422,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
                                struct ccw_driver *cdrv, int num_devices,
                                const char *buf)
 {
-       return ccwgroup_create_dev(root, creator_id, cdrv, NULL,
-                                  num_devices, buf);
+       return ccwgroup_create_dev(root, creator_id, NULL, num_devices, buf);
 }
 EXPORT_SYMBOL(ccwgroup_create_from_string);
 
index 02d0152..f8f952d 100644 (file)
@@ -695,7 +695,17 @@ static int match_dev_id(struct device *dev, void *data)
        return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id);
 }
 
-static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
+/**
+ * get_ccwdev_by_dev_id() - obtain device from a ccw device id
+ * @dev_id: id of the device to be searched
+ *
+ * This function searches all devices attached to the ccw bus for a device
+ * matching @dev_id.
+ * Returns:
+ *  If a device is found its reference count is increased and returned;
+ *  else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
 {
        struct device *dev;
 
@@ -703,6 +713,7 @@ static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id)
 
        return dev ? to_ccwdev(dev) : NULL;
 }
+EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id);
 
 static void ccw_device_do_unbind_bind(struct ccw_device *cdev)
 {
index 179824b..6bace69 100644 (file)
@@ -101,6 +101,7 @@ int ccw_device_test_sense_data(struct ccw_device *);
 void ccw_device_schedule_sch_unregister(struct ccw_device *);
 int ccw_purge_blacklisted(void);
 void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo);
+struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id);
 
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);