summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-07-18 15:15:45 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-19 21:27:18 -0700
commit91ba3c2128e9ee490a9f04bcd5b54749b18e4410 (patch)
treec90f5711b990468dc684a8859cc9c498b8d4163d
parent48db7b7c50cdb06c85f0ff01b5c19ac34903048b (diff)
downloadlinux-91ba3c2128e9ee490a9f04bcd5b54749b18e4410.tar.gz
[SPARC64]: Fix handling of multiple vdc-port nodes.
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>
-rw-r--r--arch/sparc64/kernel/mdesc.c56
-rw-r--r--arch/sparc64/kernel/vio.c29
-rw-r--r--drivers/block/sunvdc.c24
-rw-r--r--include/asm-sparc64/vio.h2
4 files changed, 88 insertions, 23 deletions
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index 302ba5e5a0bb..13a79fe5115b 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -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;
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 7e65b5a28bff..9ae1f61d4db9 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -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;
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 4ee3920b05cc..d50b82381155 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -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),
diff --git a/include/asm-sparc64/vio.h b/include/asm-sparc64/vio.h
index c0a8d4ed5bcb..f7417e91b170 100644
--- a/include/asm-sparc64/vio.h
+++ b/include/asm-sparc64/vio.h
@@ -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;