[SPARC64]: Fix handling of multiple vdc-port nodes.
authorDavid S. Miller <davem@sunset.davemloft.net>
Wed, 18 Jul 2007 22:15:45 +0000 (15:15 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Fri, 20 Jul 2007 04:27:18 +0000 (21:27 -0700)
The "id" property in vdc-port nodes are not unique, they
are all zero.  Therefore assign ID's using the parent's
"cfg-handle" property which will be unique.

Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc64/kernel/mdesc.c
arch/sparc64/kernel/vio.c
drivers/block/sunvdc.c
include/asm-sparc64/vio.h

index 302ba5e5a0bb85d1b8c5f66b938c0177c9e504d2..13a79fe5115b3da4071a6a8aedb3f3d7f819b37e 100644 (file)
@@ -231,6 +231,25 @@ void mdesc_register_notifier(struct mdesc_notifier_client *client)
        mutex_unlock(&mdesc_mutex);
 }
 
+static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
+{
+       const u64 *id;
+       u64 a;
+
+       id = NULL;
+       mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+               u64 target;
+
+               target = mdesc_arc_target(hp, a);
+               id = mdesc_get_property(hp, target,
+                                       "cfg-handle", NULL);
+               if (id)
+                       break;
+       }
+
+       return id;
+}
+
 /* Run 'func' on nodes which are in A but not in B.  */
 static void invoke_on_missing(const char *name,
                              struct mdesc_handle *a,
@@ -240,13 +259,42 @@ static void invoke_on_missing(const char *name,
        u64 node;
 
        mdesc_for_each_node_by_name(a, node, name) {
-               const u64 *id = mdesc_get_property(a, node, "id", NULL);
-               int found = 0;
+               int found = 0, is_vdc_port = 0;
+               const char *name_prop;
+               const u64 *id;
                u64 fnode;
 
+               name_prop = mdesc_get_property(a, node, "name", NULL);
+               if (name_prop && !strcmp(name_prop, "vdc-port")) {
+                       is_vdc_port = 1;
+                       id = parent_cfg_handle(a, node);
+               } else
+                       id = mdesc_get_property(a, node, "id", NULL);
+
+               if (!id) {
+                       printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
+                              (name_prop ? name_prop : name));
+                       continue;
+               }
+
                mdesc_for_each_node_by_name(b, fnode, name) {
-                       const u64 *fid = mdesc_get_property(b, fnode,
-                                                           "id", NULL);
+                       const u64 *fid;
+
+                       if (is_vdc_port) {
+                               name_prop = mdesc_get_property(b, fnode,
+                                                              "name", NULL);
+                               if (!name_prop ||
+                                   strcmp(name_prop, "vdc-port"))
+                                       continue;
+                               fid = parent_cfg_handle(b, fnode);
+                               if (!fid) {
+                                       printk(KERN_ERR "MD: Cannot find ID "
+                                              "for vdc-port node.\n");
+                                       continue;
+                               }
+                       } else
+                               fid = mdesc_get_property(b, fnode,
+                                                        "id", NULL);
 
                        if (*id == *fid) {
                                found = 1;
index 7e65b5a28bffb77a3c136750245c87c080d273b4..9ae1f61d4db9d9a44c6f9205e42ad592fa73928b 100644 (file)
@@ -221,6 +221,27 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
                return NULL;
        }
 
+       if (!strcmp(type, "vdc-port")) {
+               u64 a;
+
+               id = NULL;
+               mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+                       u64 target;
+
+                       target = mdesc_arc_target(hp, a);
+                       id = mdesc_get_property(hp, target,
+                                               "cfg-handle", NULL);
+                       if (id)
+                               break;
+               }
+               if (!id) {
+                       printk(KERN_ERR "VIO: vdc-prot lacks parent "
+                              "cfg-handle.\n");
+                       return NULL;
+               }
+       } else
+               id = mdesc_get_property(hp, mp, "id", NULL);
+
        bus_id_name = type;
        if (!strcmp(type, "domain-services-port"))
                bus_id_name = "ds";
@@ -260,13 +281,15 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
 
        vio_fill_channel_info(hp, mp, vdev);
 
-       id = mdesc_get_property(hp, mp, "id", NULL);
-       if (!id)
+       if (!id) {
                snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
                         bus_id_name);
-       else
+               vdev->dev_no = ~(u64)0;
+       } else {
                snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
                         bus_id_name, *id);
+               vdev->dev_no = *id;
+       }
 
        vdev->dev.parent = parent;
        vdev->dev.bus = &vio_bus_type;
index 4ee3920b05ccc8c49b9e3b97d02c79d37739d18d..d50b82381155d1990ee5434cc41bf7da59c60a24 100644 (file)
@@ -64,7 +64,6 @@ struct vdc_port {
        u64                     operations;
        u32                     vdisk_size;
        u8                      vdisk_type;
-       u8                      dev_no;
 
        char                    disk_name[32];
 
@@ -703,7 +702,7 @@ static int probe_disk(struct vdc_port *port)
        blk_queue_max_phys_segments(q, port->ring_cookies);
        blk_queue_max_sectors(q, port->max_xfer_size);
        g->major = vdc_major;
-       g->first_minor = port->dev_no << PARTITION_SHIFT;
+       g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
        strcpy(g->disk_name, port->disk_name);
 
        g->fops = &vdc_fops;
@@ -747,21 +746,16 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
 {
        struct mdesc_handle *hp;
        struct vdc_port *port;
-       const u64 *port_id;
        int err;
 
        print_version();
 
        hp = mdesc_grab();
 
-       port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
        err = -ENODEV;
-       if (!port_id) {
-               printk(KERN_ERR PFX "Port lacks id property.\n");
-               goto err_out_release_mdesc;
-       }
-       if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
-               printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+       if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+               printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+                      vdev->dev_no);
                goto err_out_release_mdesc;
        }
 
@@ -772,16 +766,14 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
                goto err_out_release_mdesc;
        }
 
-       port->dev_no = *port_id;
-
-       if (port->dev_no >= 26)
+       if (vdev->dev_no >= 26)
                snprintf(port->disk_name, sizeof(port->disk_name),
                         VDCBLK_NAME "%c%c",
-                        'a' + (port->dev_no / 26) - 1,
-                        'a' + (port->dev_no % 26));
+                        'a' + ((int)vdev->dev_no / 26) - 1,
+                        'a' + ((int)vdev->dev_no % 26));
        else
                snprintf(port->disk_name, sizeof(port->disk_name),
-                        VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+                        VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
 
        err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
                              vdc_versions, ARRAY_SIZE(vdc_versions),
index c0a8d4ed5bcb33669d808b4f1105c1913fe1dfac..f7417e91b1706bb79c438446b8b941e5ddb7c9ef 100644 (file)
@@ -275,6 +275,8 @@ struct vio_dev {
        char                    compat[VIO_MAX_COMPAT_LEN];
        int                     compat_len;
 
+       u64                     dev_no;
+
        unsigned long           channel_id;
 
        unsigned int            tx_irq;