FWARC 2008/300 Sun4v FMA Platform Independent FMA Topology Enumeration
authorsd77468
Mon, 28 Jul 2008 15:46:04 -0700
changeset 7205 e288f08b9204
parent 7204 ab68fd836507
child 7206 dc9137c304e0
FWARC 2008/300 Sun4v FMA Platform Independent FMA Topology Enumeration PSARC 2008/392 FMA new canonical hc names for sun4v_pi enumerator PSARC 2008/440 sun4v Platform Independent Topology Enumerator - libmdesc extensions 6628827 Need platform independent topo enumeration for sun4v platforms
usr/src/common/mdesc/mdesc_getproparcs.c
usr/src/common/mdesc/mdesc_walkdag.c
usr/src/lib/fm/libmdesc/Makefile.com
usr/src/lib/fm/libmdesc/common/mapfile-vers
usr/src/lib/fm/topo/libtopo/common/hc.c
usr/src/lib/fm/topo/libtopo/common/topo_hc.h
usr/src/lib/fm/topo/maps/sun4v/sun4v-hc-topology.xml
usr/src/lib/fm/topo/modules/sun4v/Makefile
usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile
usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_cpu.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_defer.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_generic.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_ldom.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_niu.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_pciexrc.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_top.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c
usr/src/lib/fm/topo/modules/sun4v/sun4vpi/sun4vpi.c
usr/src/pkgdefs/SUNWfmd/prototype_sparc
usr/src/uts/common/sys/mdesc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/mdesc/mdesc_getproparcs.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/mdesc.h>
+#include <sys/mdesc_impl.h>
+
+static int md_find_node_arcs(md_impl_t *, mde_cookie_t, mde_str_cookie_t, int,
+    mde_cookie_t *, size_t);
+
+
+/*
+ * Return an array containing the node indexes for the arcs in
+ * the given node.  The array is allocated using the allocator
+ * defined at machine description initialization time and the
+ * number of arcs found returned.
+ *
+ * Input		Description
+ * -------------------	----------------------------------------
+ * md_t *		Pointer to md session
+ * mde_cookie_t		Node containing arcs
+ * char *		Arc name to count (e.g. "fwd" or "back")
+ * mde_cookie_t *	Buffer to store indexes, or NULL
+ * size_t		Size of buffer
+ *
+ * Output		Description
+ * -------------------	----------------------------------------
+ * int			Count of arcs in node
+ */
+int
+md_get_prop_arcs(md_t *ptr, mde_cookie_t node, char *namep, mde_cookie_t *arcp,
+    size_t arcsize)
+{
+	int		 result;
+	mde_str_cookie_t prop_name;
+	md_impl_t	*mdp;
+
+	mdp = (md_impl_t *)ptr;
+
+	if (node == MDE_INVAL_ELEM_COOKIE) {
+		return (-1);
+	}
+
+	prop_name = md_find_name(ptr, namep);
+	if (prop_name == MDE_INVAL_STR_COOKIE) {
+		return (-1);
+	}
+
+	result = md_find_node_arcs(mdp, node, prop_name, MDET_PROP_ARC, arcp,
+	    arcsize);
+
+	return (result);
+}
+
+
+/*
+ * Find the number of arcs in the node of the requested prop_name.  If storage
+ * is given in arcp, store the first arcsize number of node indexes.
+ */
+static int
+md_find_node_arcs(md_impl_t *mdp, mde_cookie_t node,
+    mde_str_cookie_t prop_name, int tag_type, mde_cookie_t *arcp,
+    size_t arcsize)
+{
+	int		result;
+	md_element_t	*mdep;
+	int		idx;
+
+	/* Get the private node information from session data */
+	idx = (int)node;
+	mdep = &(mdp->mdep[idx]);
+
+	/* Make sure the cookie is in fact a node */
+	if (MDE_TAG(mdep) != MDET_NODE) {
+		return (-1);
+	}
+
+	/*
+	 * Walk the elements in the node and find all the arcs of the
+	 * requested type, and store them in an array.
+	 */
+	result = 0;
+	for (idx++, mdep++; MDE_TAG(mdep) != MDET_NODE_END; idx++, mdep++) {
+		if ((MDE_TAG(mdep) == tag_type) &&
+		    (MDE_NAME(mdep) == prop_name)) {
+			if (arcp != NULL && result < arcsize) {
+				arcp[result] =
+				    (mde_cookie_t)MDE_PROP_INDEX(mdep);
+			}
+
+			/* Increment the count of arcs found */
+			result++;
+		}
+	}
+
+	/* Return the total count of arcs in the node */
+	return (result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/mdesc/mdesc_walkdag.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,204 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <string.h>
+#include <strings.h>
+#endif
+
+#include <sys/mdesc.h>
+#include <sys/mdesc_impl.h>
+
+static int
+mdl_walk_dag(md_impl_t *, mde_cookie_t, mde_cookie_t, mde_str_cookie_t,
+    mde_str_cookie_t, uint8_t *, md_walk_fn_t, void *, int);
+
+
+/*
+ * Walk the machine description directed graph from a starting
+ * node searching for nodes of a given node name and using a
+ * given arc type.  Call a callback function for each node found.
+ * Each node will be visited only once.
+ *
+ * Input		Description
+ * -------------------	----------------------------------------
+ * md_t *		Pointer to md session
+ * mde_cookie_t		Index of the starting node
+ * mde_str_cookie_t	Node name cookie of the nodes to call
+ *			the walk function
+ * mde_str_cookie_t	Arc name cookie of the path to follow
+ * md_walk_fn_t		The function to call for each node
+ * void *		Private data to pass to the walker function
+ *
+ */
+int
+md_walk_dag(md_t *ptr, mde_cookie_t startnode,
+    mde_str_cookie_t node_name_cookie, mde_str_cookie_t arc_name_cookie,
+    md_walk_fn_t func, void *private)
+{
+	int		res;
+	uint8_t		*seenp;
+	md_impl_t	*mdp;
+	mde_cookie_t	start;
+
+	mdp = (md_impl_t *)ptr;
+	if (mdp == NULL) {
+		return (-1);
+	}
+
+	/*
+	 * Possible the caller was lazy and didn't check the
+	 * validitiy of either the node name or the arc name
+	 * on calling ... in which case fail to find any
+	 * nodes.
+	 * This is distinct, from a fail (-1) since we return
+	 * that nothing was found.
+	 */
+	if (node_name_cookie == MDE_INVAL_STR_COOKIE ||
+	    arc_name_cookie == MDE_INVAL_STR_COOKIE) {
+		return (0);
+	}
+
+	/*
+	 * if we want to start at the top, start at index 0
+	 */
+	start = startnode;
+	if (start == MDE_INVAL_ELEM_COOKIE) {
+		start = 0;
+	}
+
+	/*
+	 * Scan from the start point until the first node.
+	 */
+	while (start < mdp->element_count &&
+	    MDE_TAG(&mdp->mdep[start]) == MDET_NULL) {
+		start++;
+	}
+
+	/*
+	 * This was a bogus start point if no node found
+	 */
+	if (MDE_TAG(&mdp->mdep[start]) != MDET_NODE) {
+		return (-1);	/* illegal start node specified */
+	}
+
+	/*
+	 * Allocate a recursion detection structure so we only visit
+	 * each node once.
+	 */
+	seenp = (uint8_t *)mdp->allocp(mdp->element_count);
+	if (seenp == NULL) {
+		return (-1);
+	}
+	(void) memset(seenp, 0, mdp->element_count);
+
+	/*
+	 * Now build the list of requested nodes.
+	 */
+	res = mdl_walk_dag(mdp, MDE_INVAL_ELEM_COOKIE, start,
+	    node_name_cookie, arc_name_cookie, seenp, func, private, 0);
+
+	mdp->freep(seenp, mdp->element_count);
+
+	return (res >= 0 ? 0 : res);
+}
+
+
+static int
+mdl_walk_dag(md_impl_t *mdp, mde_cookie_t parentidx, mde_cookie_t nodeidx,
+    mde_str_cookie_t node_name_cookie, mde_str_cookie_t arc_name_cookie,
+    uint8_t *seenp, md_walk_fn_t func, void *private, int level)
+{
+	int		result;
+	md_element_t	*mdep;
+
+	/* Get the node element from the session */
+	mdep = &(mdp->mdep[nodeidx]);
+
+	/* see if cookie is infact a node */
+	if (MDE_TAG(mdep) != MDET_NODE) {
+		return (MDE_WALK_ERROR);
+	}
+
+	/* have we been here before ? */
+	if (seenp[nodeidx]) {
+		return (MDE_WALK_NEXT);
+	}
+	seenp[nodeidx] = 1;
+
+#ifdef	DEBUG_LIBMDESC
+	{
+		int x;
+		for (x = 0; x < level; x++) {
+			printf("-");
+		}
+		printf("%d (%s)\n", nodeidx,
+		    (char *)(mdp->datap + MDE_NAME(mdep)));
+	}
+#endif
+
+	/* is this node of the type we seek ? */
+	if (MDE_NAME(mdep) == node_name_cookie) {
+		/*
+		 * Yes.  Call the callback function.
+		 */
+		result = (func)((md_t *)mdp, parentidx, nodeidx, private);
+		if (result != MDE_WALK_NEXT) {
+			return (result);
+		}
+	}
+
+	/*
+	 * Simply walk the elements in the node.
+	 * if we find a matching arc, then recursively call
+	 * the subordinate looking for a match
+	 */
+	result = MDE_WALK_NEXT;
+	for (mdep++; MDE_TAG(mdep) != MDET_NODE_END; mdep++) {
+		if (MDE_TAG(mdep) == MDET_PROP_ARC &&
+		    MDE_NAME(mdep) == arc_name_cookie) {
+			/*
+			 * The current node becomes the parent node, and the
+			 * arc index is the new current node.
+			 */
+			result = mdl_walk_dag(mdp, nodeidx, mdep->d.prop_idx,
+			    node_name_cookie, arc_name_cookie, seenp, func,
+			    private, level+1);
+			if (result != MDE_WALK_NEXT) {
+				/* The walk is complete or terminated. */
+				return (result);
+			}
+		}
+	}
+
+	return (result);
+}
--- a/usr/src/lib/fm/libmdesc/Makefile.com	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/libmdesc/Makefile.com	Mon Jul 28 15:46:04 2008 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -32,11 +32,13 @@
 	mdesc_fini.c \
 	mdesc_findname.c \
 	mdesc_findnodeprop.c \
+	mdesc_getproparcs.c \
 	mdesc_getpropstr.c \
 	mdesc_getpropval.c \
 	mdesc_init_intern.c \
 	mdesc_nodecount.c \
-	mdesc_scandag.c
+	mdesc_scandag.c \
+	mdesc_walkdag.c
 
 OBJECTS = $(LIBSRCS:%.c=%.o)
 
--- a/usr/src/lib/fm/libmdesc/common/mapfile-vers	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/libmdesc/common/mapfile-vers	Mon Jul 28 15:46:04 2008 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -30,11 +30,13 @@
 	md_find_name;
 	md_find_node_prop;
 	md_fini;
+	md_get_prop_arcs;
 	md_get_prop_str;
 	md_get_prop_val;
 	md_init_intern;
 	md_node_count;
 	md_scan_dag;
+	md_walk_dag;
     local:
 	*;
 };
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c	Mon Jul 28 15:46:04 2008 -0700
@@ -107,18 +107,22 @@
 	{ HC, FM_FMRI_SCHEME_HC, HC_VERSION, &hc_ops };
 
 static const hcc_t hc_canon[] = {
+	{ BANK, TOPO_STABILITY_PRIVATE },
 	{ BAY, TOPO_STABILITY_PRIVATE },
+	{ BLADE, TOPO_STABILITY_PRIVATE },
 	{ BRANCH, TOPO_STABILITY_PRIVATE },
 	{ CMP, TOPO_STABILITY_PRIVATE },
 	{ CENTERPLANE, TOPO_STABILITY_PRIVATE },
 	{ CHASSIS, TOPO_STABILITY_PRIVATE },
 	{ CHIP, TOPO_STABILITY_PRIVATE },
 	{ CHIP_SELECT, TOPO_STABILITY_PRIVATE },
+	{ CORE, TOPO_STABILITY_PRIVATE },
 	{ CONTROLLER, TOPO_STABILITY_PRIVATE },
 	{ CPU, TOPO_STABILITY_PRIVATE },
 	{ CPUBOARD, TOPO_STABILITY_PRIVATE },
 	{ DIMM, TOPO_STABILITY_PRIVATE },
 	{ DISK, TOPO_STABILITY_PRIVATE },
+	{ DRAM, TOPO_STABILITY_PRIVATE },
 	{ DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
 	{ FAN, TOPO_STABILITY_PRIVATE },
 	{ FANMODULE, TOPO_STABILITY_PRIVATE },
@@ -126,7 +130,9 @@
 	{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
 	{ IOBOARD, TOPO_STABILITY_PRIVATE },
 	{ MEMBOARD, TOPO_STABILITY_PRIVATE },
+	{ MEMORYBUFFER, TOPO_STABILITY_PRIVATE },
 	{ MEMORYCONTROL, TOPO_STABILITY_PRIVATE },
+	{ MICROCORE, TOPO_STABILITY_PRIVATE },
 	{ MOTHERBOARD, TOPO_STABILITY_PRIVATE },
 	{ NIU, TOPO_STABILITY_PRIVATE },
 	{ NIUFN, TOPO_STABILITY_PRIVATE },
@@ -142,6 +148,8 @@
 	{ POWERMODULE, TOPO_STABILITY_PRIVATE },
 	{ PSU, TOPO_STABILITY_PRIVATE },
 	{ RANK, TOPO_STABILITY_PRIVATE },
+	{ RISER, TOPO_STABILITY_PRIVATE },
+	{ SHELF, TOPO_STABILITY_PRIVATE },
 	{ SES_ENCLOSURE, TOPO_STABILITY_PRIVATE },
 	{ SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
 	{ XAUI, TOPO_STABILITY_PRIVATE },
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h	Mon Jul 28 15:46:04 2008 -0700
@@ -36,18 +36,22 @@
 /*
  * Allowable hardware component names for hc FMRIs
  */
+#define	BANK		"bank"
 #define	BAY		"bay"
+#define	BLADE		"blade"
 #define	BRANCH		"branch"
 #define	CMP		"CMP"
 #define	CENTERPLANE	"centerplane"
 #define	CHASSIS		"chassis"
 #define	CHIP		"chip"
 #define	CHIP_SELECT	"chip-select"
+#define	CORE		"core"
 #define	CONTROLLER	"controller"
 #define	CPU		"cpu"
 #define	CPUBOARD	"cpuboard"
 #define	DIMM		"dimm"
 #define	DISK		"disk"
+#define	DRAM		"dram"
 #define	DRAMCHANNEL	"dram-channel"
 #define	FAN		"fan"
 #define	FANMODULE	"fanmodule"
@@ -55,7 +59,9 @@
 #define	INTERCONNECT	"interconnect"
 #define	IOBOARD		"ioboard"
 #define	MEMBOARD	"memboard"
+#define	MEMORYBUFFER	"memory-buffer"
 #define	MEMORYCONTROL	"memory-controller"
+#define	MICROCORE	"micro-core"
 #define	MOTHERBOARD	"motherboard"
 #define	NIU		"niu"
 #define	NIUFN		"niufn"
@@ -71,6 +77,8 @@
 #define	POWERMODULE	"powermodule"
 #define	PSU		"psu"
 #define	RANK		"rank"
+#define	RISER		"riser"
+#define	SHELF		"shelf"
 #define	SES_ENCLOSURE	"ses-enclosure"
 #define	SYSTEMBOARD	"systemboard"
 #define	XAUI		"xaui"
--- a/usr/src/lib/fm/topo/maps/sun4v/sun4v-hc-topology.xml	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/maps/sun4v/sun4v-hc-topology.xml	Mon Jul 28 15:46:04 2008 -0700
@@ -27,16 +27,8 @@
 -->
 
 <topology name='sun4v' scheme='hc'>
-  <range name='motherboard' min='0' max='0'>
-   <enum-method name='motherboard' version='1'/>
-    <dependents grouping='children'>
-     <range name='chip' min='0' max='32'>
-       <enum-method name='chip' version='1' />
-     </range>
-     <range name='hostbridge' min='0' max='254'>
-       <enum-method name='hostbridge' version='1' />
-     </range>
-    </dependents>
+  <range name='chassis' min='0' max='0'>
+    <enum-method name='sun4vpi' version='1' />
   </range>
   <range name='ses-enclosure' min='0' max='1024'>
     <enum-method name='ses' version='1' />
--- a/usr/src/lib/fm/topo/modules/sun4v/Makefile	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/Makefile	Mon Jul 28 15:46:04 2008 -0700
@@ -34,6 +34,7 @@
 	niu \
 	platform-cpu \
 	platform-mem \
+	sun4vpi \
 	xaui \
 	zambezi
 
--- a/usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/pcibus/Makefile	Mon Jul 28 15:46:04 2008 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -29,3 +29,4 @@
 ARCH = sun4v
 include ../../sun4/pcibus/Makefile.pci
 
+LDLIBS += -ldevinfo
--- a/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/lib/fm/topo/modules/sun4v/pcibus/pci_sun4v.c	Mon Jul 28 15:46:04 2008 -0700
@@ -29,6 +29,10 @@
 #include <fm/topo_mod.h>
 #include <sys/fm/protocol.h>
 #include <string.h>
+#include <alloca.h>
+#include <libdevinfo.h>
+#include <did_props.h>
+
 /*
  * Including the following file gives us definitions of the three
  * global arrays used to adjust labels, Slot_Rewrites, Physlot_Names,
@@ -36,15 +40,62 @@
  * routines for pci.
  */
 #include "pci_sun4v.h"
+#include "pci_sun4.h"
 
-#include "pci_sun4.h"
+#define	PI_PROP_CHASSIS_LOCATION_NAME		"chassis-location-name"
+
+typedef struct _pci_fru {
+	tnode_t	*node;
+	char	*location;
+	int	locsiz;
+} _pci_fru_t;
+
+
+static int platform_pci_fru_location(topo_mod_t *, tnode_t *, uchar_t *, int);
+static int platform_pci_fru_cb(topo_mod_t *, tnode_t *, void *);
+
 
 int
 platform_pci_label(topo_mod_t *mod, tnode_t *node, nvlist_t *in,
     nvlist_t **out)
 {
-	return (pci_label_cmn(mod, node, in, out));
+	int	result;
+	int	err;
+	int	locsiz = 0;
+	uchar_t	*loc = NULL;
+	char	*nac = NULL;
+
+	topo_mod_dprintf(mod, "entering platform_pci_label\n");
+
+	*out = NULL;
+	result = di_bytes_get(mod, topo_node_getspecific(node),
+	    PI_PROP_CHASSIS_LOCATION_NAME, &locsiz, &loc);
+	if (result == -1 || locsiz < 0) {
+		topo_mod_dprintf(mod, "platform_pci_label: %s not found (%s)\n",
+		    PI_PROP_CHASSIS_LOCATION_NAME, strerror(errno));
+
+		/* Invoke the generic label generator for this node */
+		return (pci_label_cmn(mod, node, in, out));
+	}
+
+	/*
+	 * We have crossed a FRU boundary.  Use the value in the
+	 * chassis-location-name property as the node label.
+	 */
+	nac = alloca(locsiz+1);
+	(void) memset(nac, 0, locsiz+1);
+	(void) memcpy(nac, loc, locsiz);
+	result = topo_node_label_set(node, nac, &err);
+	if (result < 0) {
+		if (err != ETOPO_PROP_NOENT) {
+			return (topo_mod_seterrno(mod, err));
+		}
+	}
+
+	return (0);
 }
+
+
 int
 platform_pci_fru(topo_mod_t *mod, tnode_t *node, nvlist_t *in,
     nvlist_t **out)
@@ -56,6 +107,8 @@
 	char *nm, *plat, *pp, **cp;
 	const char *label;
 	int found_t1plat = 0;
+	uchar_t *loc;
+	int locsiz;
 
 	topo_mod_dprintf(mod, "entering platform_pci_fru\n");
 
@@ -119,7 +172,94 @@
 			*out = rnvl;
 		}
 		return (0);
+	} else if (di_bytes_get(mod, topo_node_getspecific(node),
+	    PI_PROP_CHASSIS_LOCATION_NAME, &locsiz, &loc) == 0 && locsiz > 0) {
+		/*
+		 * We have crossed a FRU boundary and need to find the parent
+		 * node with this location and set our FMRI to that value.
+		 */
+		return (platform_pci_fru_location(mod, node, loc, locsiz));
 	} else {
 		return (pci_fru_compute(mod, node, in, out));
 	}
 }
+
+
+static int
+platform_pci_fru_location(topo_mod_t *mod, tnode_t *node, uchar_t *loc,
+    int locsiz)
+{
+	int		err;
+	tnode_t		*parent;
+	tnode_t		*top;
+	topo_walk_t	*wp;
+	_pci_fru_t	walkdata;
+
+	topo_mod_dprintf(mod, "entering platform_pci_fru_location\n");
+
+	/* Find the root node */
+	top = node;
+	while ((parent = topo_node_parent(top)) != NULL) {
+		top = parent;
+	}
+	walkdata.node = node;
+	walkdata.locsiz = locsiz;
+	walkdata.location = alloca(locsiz+1);
+	(void) memset(walkdata.location, 0, locsiz+1);
+	(void) memcpy(walkdata.location, loc, locsiz);
+
+	/* Create a walker starting at the root node */
+	wp = topo_mod_walk_init(mod, top, platform_pci_fru_cb, &walkdata, &err);
+	if (wp == NULL) {
+		return (topo_mod_seterrno(mod, err));
+	}
+
+	/*
+	 * Walk the tree breadth first to hopefully avoid visiting too many
+	 * nodes while searching for the node with the appropriate FMRI.
+	 */
+	(void) topo_walk_step(wp, TOPO_WALK_SIBLING);
+	topo_walk_fini(wp);
+
+	return (0);
+}
+
+
+static int
+platform_pci_fru_cb(topo_mod_t *mod, tnode_t *node, void *private)
+{
+	int		err;
+	_pci_fru_t	*walkdata = (_pci_fru_t *)private;
+	nvlist_t	*fmri;
+	char		*location;
+	int 		result, rc;
+
+	if (node == walkdata->node) {
+		/* This is the starting node.  Do not check the location */
+		return (TOPO_WALK_NEXT);
+	}
+
+	if (topo_node_label(node, &location, &err) != 0) {
+		/* This node has no location property.  Continue the walk */
+		return (TOPO_WALK_NEXT);
+	}
+
+	result = TOPO_WALK_NEXT;
+	if (strncmp(location, walkdata->location, walkdata->locsiz) == 0) {
+		/*
+		 * We have a match.  Set the node's FRU FMRI to this nodes
+		 * FRU FMRI
+		 */
+		rc = topo_node_fru(node, &fmri, NULL, &err);
+		if (rc == 0) {
+			rc = topo_node_fru_set(walkdata->node, fmri, 0, &err);
+			nvlist_free(fmri);
+		}
+		if (rc != 0) {
+			result = TOPO_WALK_TERMINATE;
+			topo_mod_seterrno(mod, err);
+		}
+	}
+	topo_mod_strfree(mod, location);
+	return (result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/Makefile	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+MODULE	= sun4vpi
+ARCH	= sun4v
+CLASS	= arch
+TOPODIR	= ../../../libtopo/common
+
+MODULESRCS =	pi_defer.c pi_ldom.c pi_walker.c pi_subr.c \
+		pi_cpu.c pi_generic.c pi_pciexrc.c pi_niu.c pi_top.c \
+		sun4vpi.c
+
+include ../../Makefile.plugin
+
+LDLIBS += -ldevinfo -lmdesc -lldom -luutil
+
+CPPFLAGS += -I. -I$(ROOT)/usr/platform/sun4v/include -I$(TOPODIR)
+
+%.o: ../../../../../common/mdesc/%.c
+	$(COMPILE.c) $<
+	$(CTFCONVERT_O)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_cpu.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Enumerate a CPU node
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define	_ENUM_NAME	"enum_cpu"
+
+typedef struct cpuwalk_s {
+	topo_mod_t	*mod;
+	char		*serial;
+} cpuwalk_t;
+
+static int pi_enum_cpu_serial(topo_mod_t *, md_t *, mde_cookie_t, char **);
+static int pi_enum_cpu_serial_cb(md_t *, mde_cookie_t, mde_cookie_t, void *);
+
+int
+pi_enum_cpu(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+    tnode_t **t_node)
+{
+	int		result;
+	int		err;
+	int		cpumask;
+	nvlist_t	*asru = NULL;
+	char		*serial = NULL;
+
+	*t_node = NULL;
+
+	/*
+	 * Create the basic topology node for the CPU using the generic
+	 * enumerator.
+	 */
+	result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+	    t_parent, hc_name, _ENUM_NAME, t_node);
+	if (result != 0) {
+		/* Error messages are printed by the generic routine */
+		return (result);
+	}
+
+	/*
+	 * Get the parameters required to create an FMRI.  The cpumask is
+	 * on the chip itself and while it may be part of an ereport
+	 * payload is unavailable here, so we set it to zero.
+	 */
+	cpumask = 0;
+
+	/*
+	 * Find the serial number, which is on the "chip" node, not the
+	 * "cpu" node.
+	 */
+	result = pi_enum_cpu_serial(mod, mdp, mde_node, &serial);
+	if (result != 0 || serial == NULL) {
+		topo_mod_dprintf(mod, "%s node_0x%llx failed to find serial "
+		    "number.\n", _ENUM_NAME, (uint64_t)mde_node);
+		return (result);
+	}
+
+	/* Create a CPU scheme FMRI and set it as the ASRU for the CPU node */
+	asru = topo_mod_cpufmri(mod, FM_CPU_SCHEME_VERSION, inst, cpumask,
+	    serial);
+	topo_mod_strfree(mod, serial);
+	if (asru == NULL) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to compute cpu scheme ASRU: %s\n",
+		    _ENUM_NAME, (uint64_t)mde_node,
+		    topo_strerror(topo_mod_errno(mod)));
+		return (-1);
+	}
+
+	/* Set the ASRU on the node without flags (the 0) */
+	result = topo_node_asru_set(*t_node, asru, 0, &err);
+	nvlist_free(asru);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to set ASRU: %s\n", _ENUM_NAME,
+		    (uint64_t)mde_node, topo_strerror(err));
+		return (-1);
+	}
+
+	return (0);
+}
+
+
+static int
+pi_enum_cpu_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    char **serial)
+{
+	int			result;
+	cpuwalk_t		args;
+	mde_str_cookie_t	component_cookie;
+	mde_str_cookie_t	back_cookie;
+
+	args.mod = mod;
+	args.serial = NULL;
+
+	/*
+	 * Search backwards through the PRI graph, starting at the current
+	 * strand (aka cpu) mde_node, and find the MD_STR_CHIP node.  This
+	 * node has the serial number for the cpu.
+	 */
+	component_cookie = md_find_name(mdp, MD_STR_COMPONENT);
+	back_cookie	 = md_find_name(mdp, MD_STR_BACK);
+
+	result = md_walk_dag(mdp, mde_node, component_cookie, back_cookie,
+	    pi_enum_cpu_serial_cb, (void *)&args);
+	*serial = args.serial;
+
+	return (result);
+}
+
+
+/*ARGSUSED*/
+static int
+pi_enum_cpu_serial_cb(md_t *mdp, mde_cookie_t mde_parent,
+    mde_cookie_t mde_node, void *private)
+{
+	char		*hc_name;
+	cpuwalk_t	*args = (cpuwalk_t *)private;
+
+	if (args == NULL) {
+		return (MDE_WALK_ERROR);
+	}
+	args->serial = NULL;
+
+	hc_name = pi_get_topo_hc_name(args->mod, mdp, mde_node);
+	if (hc_name != NULL && strcmp(hc_name, MD_STR_CHIP) == 0) {
+		args->serial = pi_get_serial(args->mod, mdp, mde_node);
+	}
+	topo_mod_strfree(args->mod, hc_name);
+
+	return ((args->serial == NULL ? MDE_WALK_NEXT : MDE_WALK_DONE));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_defer.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,238 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Some topology creation routines may need to defer completing enumeration
+ * until after the entire PRI graph has been visited.  This file includes
+ * the interfaces necessary to permit these routines to do this in a general
+ * way.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <strings.h>
+#include <string.h>
+#include <libuutil.h>
+#include <libnvpair.h>
+#include <sys/mdesc.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+static uu_list_pool_t	*defer_pool;
+static uu_list_t	*defer_list;
+
+struct pi_defernode_s {
+	uu_list_node_t	defer_node;
+
+	mde_cookie_t	mde_node;	/* MDE node index */
+	tnode_t		*t_parent;	/* Parent topology node */
+	tnode_t		*t_node;	/* Topo node associated with MDE node */
+	void		*private;	/* Private data for defer routine */
+
+	pi_deferenum_fn_t *func;	/* Defered enumeration routine */
+};
+typedef struct pi_defernode_s pi_defernode_t;
+
+/* Routines to handle the list of topology parents and mde_nodes */
+static int  pi_deferlist_create(topo_mod_t *);
+static int  pi_deferlist_compare(const void *, const void *, void *);
+
+
+/*
+ * Add a new routine to the list of deferred enumeration routines
+ */
+int
+pi_defer_add(topo_mod_t *mod, mde_cookie_t mde_node, tnode_t *t_parent,
+    tnode_t *t_node, pi_deferenum_fn_t func, void *private)
+{
+	int		result;
+	uu_list_index_t	idx;
+	pi_defernode_t	*dnp;
+
+	if (defer_list == NULL) {
+		result = pi_deferlist_create(mod);
+		if (result != 0) {
+			return (result);
+		}
+	}
+
+	/*
+	 * Create a data structure to store information about the node for
+	 * which to defer enumeration.  The defer_pool is created by the
+	 * list creation routine, above.
+	 */
+	dnp = topo_mod_zalloc(mod, sizeof (pi_defernode_t));
+	if (dnp == NULL) {
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (-1);
+	}
+	uu_list_node_init(dnp, &(dnp->defer_node), defer_pool);
+
+	dnp->mde_node	= mde_node;
+	dnp->t_parent	= t_parent;
+	dnp->t_node	= t_node;
+	dnp->private	= private;
+	dnp->func	= func;
+
+	(void) uu_list_find(defer_list, dnp, NULL, &idx);
+	uu_list_insert(defer_list, dnp, idx);
+
+	return (0);
+}
+
+
+/*
+ * Execute the list of deferred enumeration routines, destroying the list as
+ * we go.
+ */
+int
+pi_defer_exec(topo_mod_t *mod, md_t *mdp)
+{
+	int		result;
+
+	void		*dvp;
+	pi_defernode_t	*dp;
+	topo_instance_t	inst;
+	mde_cookie_t	mde_node;
+	tnode_t		*t_parent;
+	tnode_t		*t_node;
+	void		*private;
+	char		*hc_name;
+
+	pi_deferenum_fn_t *func;
+
+	topo_mod_dprintf(mod, "beginning deferred enumerator execution\n");
+	if (defer_list == NULL) {
+		topo_mod_dprintf(mod, "no deferred enumerators.  done.\n");
+		return (0);
+	}
+
+	while ((dvp = uu_list_first(defer_list)) != NULL) {
+		/* Extract the necessary information from the defernode_t */
+		dp = (pi_defernode_t *)dvp;
+		mde_node = dp->mde_node;
+		t_parent = dp->t_parent;
+		t_node   = dp->t_node;
+		private  = dp->private;
+		func	 = dp->func;
+
+		/*
+		 * Remove the element from the list.  Once we are done calling
+		 * the routine we do not need it any more.
+		 */
+		uu_list_remove(defer_list, dvp);
+		uu_list_node_fini(dp, &(dp->defer_node), defer_pool);
+		topo_mod_free(mod, dp, sizeof (pi_defernode_t));
+
+		/* Get the instance value from the mde node */
+		if (pi_get_instance(mod, mdp, mde_node, &inst) != 0) {
+			topo_mod_dprintf(mod, "deferred node_0x%llx invalid\n",
+			    (uint64_t)mde_node);
+
+			/* Move on to the next node */
+			topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+			continue;
+		}
+
+		/* Get the hc name from the mde node */
+		hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
+		if (hc_name == NULL) {
+			topo_mod_dprintf(mod,
+			    "deferred node_0x%llx has invalid NULL hc_name\n",
+			    (uint64_t)mde_node);
+
+			/* Move on to the next node */
+			topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+			continue;
+		}
+		topo_mod_dprintf(mod,
+		    "calling deferred enumerator for node_0x%llx\n",
+		    (uint64_t)mde_node);
+
+		/* Call the deferred enumeration function */
+		result = (func)(mod, mdp, mde_node, inst, t_parent, hc_name,
+		    t_node, private);
+		if (result != 0) {
+			topo_mod_dprintf(mod,
+			    "deferred enumeration for node_0x%llx failed\n",
+			    (uint64_t)mde_node);
+			topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+		}
+
+		/* Clean up from the deferred call */
+		topo_mod_strfree(mod, hc_name);
+	}
+	topo_mod_dprintf(mod, "deferred enumeration completed.\n");
+
+	uu_list_destroy(defer_list);
+	uu_list_pool_destroy(defer_pool);
+
+	return (0);
+}
+
+
+static int
+pi_deferlist_create(topo_mod_t *mod)
+{
+	/* Initialize the uutil list structure */
+	defer_pool = uu_list_pool_create("pi_defer_pool",
+	    sizeof (pi_defernode_t), offsetof(pi_defernode_t, defer_node),
+	    pi_deferlist_compare, 0);
+	if (defer_pool == NULL) {
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (-1);
+	}
+	defer_list = uu_list_create(defer_pool, NULL, 0);
+	if (defer_list == NULL) {
+		uu_list_pool_destroy(defer_pool);
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (-1);
+	}
+
+	return (0);
+}
+
+
+/* ARGSUSED */
+static int
+pi_deferlist_compare(const void *l_arg, const void *r_arg, void *private)
+{
+	pi_defernode_t	*lp = (pi_defernode_t *)l_arg;
+	pi_defernode_t	*rp = (pi_defernode_t *)r_arg;
+
+	if (lp->func != rp->func) {
+		return (1);
+	}
+	if (lp->t_parent != rp->t_parent) {
+		return (-1);
+	}
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_generic.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Create a generic topology node for a given PRI node.
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define	_ENUM_NAME	"enum_generic"
+
+int
+pi_enum_generic(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+    tnode_t **t_node)
+{
+	int		result;
+
+	/*
+	 * For a generic node that is not a top-level node, we use the
+	 * same parent topology node to generate the FMRI as well as
+	 * to bind the new node.
+	 */
+	result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+	    t_parent, hc_name, _ENUM_NAME, t_node);
+
+	return (result);
+}
+
+
+/*
+ * Create a generic topo node based on the PRI information in the machine
+ * description information.
+ */
+int
+pi_enum_generic_impl(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t inst, tnode_t *t_bindparent, tnode_t *t_fmriparent,
+    const char *hc_name, const char *enum_name, tnode_t **t_node)
+{
+	nvlist_t	*fmri;
+	nvlist_t	*auth;
+
+	topo_mod_dprintf(mod, "%s adding entry for node_0x%llx type %s\n",
+	    enum_name, (uint64_t)mde_node, hc_name);
+
+	if (t_bindparent == NULL) {
+		topo_mod_dprintf(mod,
+		    "%s called with NULL parent for node_0x%llx type %s\n",
+		    enum_name, (uint64_t)mde_node, hc_name);
+		return (-1);
+	}
+
+	/* Create the FMRI for this node */
+	auth = topo_mod_auth(mod, t_bindparent);
+	fmri = topo_mod_hcfmri(mod, t_fmriparent, FM_HC_SCHEME_VERSION, hc_name,
+	    inst, NULL, auth, NULL, NULL, NULL);
+	if (fmri == NULL) {
+		topo_mod_dprintf(mod,
+		    "%s failed to create fmri node_0x%llx: %s\n", enum_name,
+		    (uint64_t)mde_node, topo_strerror(topo_mod_errno(mod)));
+		nvlist_free(auth);
+		return (-1);
+	}
+
+	/* Bind this node to the parent */
+	*t_node = pi_node_bind(mod, mdp, mde_node, t_bindparent, hc_name, inst,
+	    fmri);
+	nvlist_free(fmri);
+	nvlist_free(auth);
+	if (*t_node == NULL) {
+		topo_mod_dprintf(mod,
+		    "%s failed to bind node_0x%llx instance %d: %s\n",
+		    enum_name, (uint64_t)mde_node, (uint32_t)inst,
+		    topo_strerror(topo_mod_errno(mod)));
+		return (-1);
+	}
+
+	topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+	    enum_name, (uint64_t)mde_node, hc_name);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_impl.h	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PI_IMPL_H
+#define	_PI_IMPL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * SUN4V Platform Independent Enumerator private interfaces
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <pthread.h>
+#include <libuutil.h>
+#include <sys/mdesc.h>
+#include <sys/fm/ldom.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+
+/* Definitions used when registering the enumerator with libtopo */
+#define	SUN4VPI_DESC		"SUN4V Platform independent topology enumerator"
+#define	SUN4VPI_SCHEME		"hc"
+#define	SUN4VPI_VERSION		TOPO_VERSION
+
+/* Definitions used when working with PRI machine description nodes */
+#define	MD_STR_BACK		"back"
+#define	MD_STR_CFG_HANDLE	"cfg-handle"		/* FWARC/2008/300 */
+#define	MD_STR_CHIP		"chip"
+#define	MD_STR_COMPONENT	"component"		/* FWARC/2006/700 */
+#define	MD_STR_CHASSIS		"chassis"
+#define	MD_STR_COMPONENTS	"components"		/* FWARC/2006/700 */
+#define	MD_STR_DASH_NUMBER	"dash_number"		/* FWARC/2006/700 */
+#define	MD_STR_FRU		"fru"			/* FWARC/2006/700 */
+#define	MD_STR_FWD		"fwd"
+#define	MD_STR_ID		"id"			/* FWARC/2008/300 */
+#define	MD_STR_NAC		"nac"			/* FWARC/2008/300 */
+#define	MD_STR_NAME		"name"
+#define	MD_STR_PART_NUMBER	"part_number"		/* FWARC/2008/300 */
+#define	MD_STR_PLATFORM		"platform"
+#define	MD_STR_REVISION_NUMBER	"rev_number"		/* FWARC/2008/300 */
+#define	MD_STR_SERIAL_NUMBER	"serial_number"		/* FWARC/2008/300 */
+#define	MD_STR_TOPO_HC_NAME	"topo-hc-name"		/* FWARC/2008/300 */
+#define	MD_STR_TOPO_SKIP	"topo-skip"		/* FWARC/2008/300 */
+#define	MD_STR_TYPE		"type"
+
+
+/*
+ * The enumerator needs to pass some state in to the function that walks
+ * the PRI graph.  This structure contains the necessary information.
+ */
+struct pi_enum_s {
+	topo_mod_t	*mod;		/* Topo module handle		*/
+
+	ldom_hdl_t	*ldomp;		/* LDOM connection handle	*/
+	uint64_t	*ldom_bufp;	/* LDOM connection data		*/
+	ssize_t		ldom_bufsize;	/* LDOM connection data size	*/
+
+	md_t		*mdp;		/* Machine Description handle	*/
+	int		md_nodes;	/* Number of md nodes		*/
+
+	void		*wp;		/* Walker private data		*/
+};
+typedef struct pi_enum_s pi_enum_t;
+
+
+/*
+ * Some node types require custom functions to create their topology nodes.
+ * This function prototype defines the interface to these functions.
+ */
+typedef int pi_enum_fn_t(topo_mod_t *, md_t *, mde_cookie_t, topo_instance_t,
+    tnode_t *, const char *, tnode_t **);
+
+pi_enum_fn_t	pi_enum_cpu;		/* Enumerate a CPU node */
+pi_enum_fn_t	pi_enum_generic;	/* Enumerate a generic PRI node */
+pi_enum_fn_t	pi_enum_niu;		/* Enumerate an NIU node */
+pi_enum_fn_t	pi_enum_pciexrc;	/* Enumerate a PCIEX root complex */
+pi_enum_fn_t	pi_enum_top;		/* Enumerate a top-level PRI node */
+
+int pi_enum_generic_impl(topo_mod_t *, md_t *, mde_cookie_t, topo_instance_t,
+    tnode_t *, tnode_t *, const char *, const char *, tnode_t **);
+
+
+/*
+ * Some enumeration functions may need to defer execution until after the
+ * entire PRI graph has been walked for some nodes.  This interface is
+ * provided to allow for the registration of routines to execute after the
+ * entire graph has been walked (for example, to execute sub-enumerators).
+ */
+typedef int pi_deferenum_fn_t(topo_mod_t *, md_t *, mde_cookie_t,
+    topo_instance_t, tnode_t *, const char *, tnode_t *, void *);
+
+int pi_defer_add(topo_mod_t *, mde_cookie_t, tnode_t *, tnode_t *,
+    pi_deferenum_fn_t, void *);
+int pi_defer_exec(topo_mod_t *, md_t *);
+
+
+/* Functions to handle LDOM PRI sessions */
+int  pi_ldompri_open(topo_mod_t *, pi_enum_t *);
+void pi_ldompri_close(topo_mod_t *, pi_enum_t *);
+
+
+/* Walk the PRI and create a topology starting at a particular PRI node */
+int  pi_walker(pi_enum_t *, tnode_t *, const char *, mde_cookie_t,
+    mde_str_cookie_t, mde_str_cookie_t);
+int  pi_walker_init(topo_mod_t *);
+void pi_walker_fini(topo_mod_t *);
+
+/* PRI machine description node data access routines */
+int	pi_find_mdenodes(topo_mod_t *, md_t *, mde_cookie_t, char *, char *,
+    mde_cookie_t **, size_t *);
+int	pi_skip_node(topo_mod_t *, md_t *, mde_cookie_t);
+int	pi_get_cfg_handle(topo_mod_t *, md_t *, mde_cookie_t, uint64_t *);
+char   *pi_get_chassisid(topo_mod_t *, md_t *, mde_cookie_t);
+char   *pi_get_topo_hc_name(topo_mod_t *, md_t *, mde_cookie_t);
+int	pi_get_instance(topo_mod_t *, md_t *, mde_cookie_t, topo_instance_t *);
+char   *pi_get_part(topo_mod_t *, md_t *, mde_cookie_t);
+char   *pi_get_productid(topo_mod_t *, md_t *);
+char   *pi_get_revision(topo_mod_t *, md_t *, mde_cookie_t);
+char   *pi_get_serial(topo_mod_t *, md_t *, mde_cookie_t);
+char   *pi_get_serverid(topo_mod_t *);
+int	pi_get_fru(topo_mod_t *, md_t *, mde_cookie_t, int *);
+char   *pi_get_label(topo_mod_t *, md_t *, mde_cookie_t);
+
+int	pi_set_auth(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *, tnode_t *);
+int	pi_set_frufmri(topo_mod_t *, md_t *, mde_cookie_t, const char *,
+    topo_instance_t, tnode_t *, tnode_t *);
+int	pi_set_label(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *);
+int	pi_set_system(topo_mod_t *, tnode_t *);
+
+tnode_t *pi_node_bind(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *,
+    const char *, topo_instance_t, nvlist_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PI_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_ldom.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Open connections to the LDOM and Machine Description libraries used during
+ * enumeration.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mdesc.h>
+#include <sys/fm/ldom.h>
+#include <sys/systeminfo.h>
+
+#include "pi_impl.h"
+
+static topo_mod_t *Pi_mod;
+
+static void pi_free(void *, size_t);
+static void * pi_alloc(size_t);
+
+/*
+ * Initialize a connection to the LDOM machine description interface.
+ */
+int
+pi_ldompri_open(topo_mod_t *mod, pi_enum_t *pip)
+{
+	if (mod == NULL || pip == NULL) {
+		return (-1);
+	}
+
+	/*
+	 * Store the module pointer for this session.  This file-global
+	 * is used by the allocators called by libldom and libmdesc.
+	 */
+	Pi_mod = mod;
+
+	/* Initialize the LDOM connection */
+	pip->ldomp = ldom_init(pi_alloc, pi_free);
+	if (pip->ldomp == NULL) {
+		topo_mod_dprintf(mod,
+		    "sun4vpi failed to initialize LDOM layer.\n");
+		Pi_mod = NULL;
+		return (-1);
+	}
+
+	/* Initialize the machine description layer for this ldom instance */
+	pip->ldom_bufsize = ldom_get_core_md(pip->ldomp, &(pip->ldom_bufp));
+	if (pip->ldom_bufsize < 1) {
+		topo_mod_dprintf(mod, "ldom_get_core_md error: bufsize = %d\n",
+		    pip->ldom_bufsize);
+		ldom_fini(pip->ldomp);
+		Pi_mod = NULL;
+		return (-1);
+	}
+
+	/* Initialize the machine description internal layer */
+	pip->mdp = md_init_intern(pip->ldom_bufp, pi_alloc, pi_free);
+	if (pip->mdp == NULL ||
+	    (pip->md_nodes = md_node_count(pip->mdp)) < 1) {
+		topo_mod_dprintf(mod, "md_init_intern error\n");
+		pi_free(pip->ldom_bufp, pip->ldom_bufsize);
+		ldom_fini(pip->ldomp);
+		Pi_mod = NULL;
+		return (-1);
+	}
+
+	return (0);
+}
+
+
+/* ARGSUSED */
+void
+pi_ldompri_close(topo_mod_t *mod, pi_enum_t *pip)
+{
+	if (pip == NULL) {
+		return;
+	}
+
+	/* Close the machine description connection */
+	(void) md_fini(pip->mdp);
+
+	/* Close the connection to the LDOM layer */
+	ldom_fini(pip->ldomp);
+
+	/* Free the ldom connection data */
+	pi_free(pip->ldom_bufp, pip->ldom_bufsize);
+
+	/* Reset the file-global module pointer */
+	Pi_mod = NULL;
+}
+
+
+static void *
+pi_alloc(size_t size)
+{
+	if (Pi_mod == NULL) {
+		/* Cannot allocate memory without a module pointer */
+		return (NULL);
+	}
+	return (topo_mod_alloc(Pi_mod, size));
+}
+
+
+static void
+pi_free(void *buf, size_t size)
+{
+	if (Pi_mod == NULL) {
+		/* Cannot free memory without a module pointer */
+		return;
+	}
+	topo_mod_free(Pi_mod, buf, size);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_niu.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Create a topology node for a PRI node of type 'niu'
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define	_ENUM_NAME	"enum_niu"
+
+
+/* ARGSUSED */
+int
+pi_enum_niu(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+    tnode_t **t_node)
+{
+	int		result;
+
+	*t_node = NULL;
+
+	topo_mod_dprintf(mod,
+	    "%s node_0x%llx enumeration starting\n", _ENUM_NAME,
+	    (uint64_t)mde_node);
+
+	/* Make sure our dependent modules are loaded */
+	if (topo_mod_load(mod, NIU, TOPO_VERSION) == NULL) {
+		topo_mod_dprintf(mod, "%s could not load %s module: %s\n",
+		    _ENUM_NAME, NIU, topo_strerror(topo_mod_errno(mod)));
+		return (-1);
+	}
+
+	/*
+	 * Invoke the niu enumerator for this node.
+	 */
+	result = topo_mod_enumerate(mod, t_parent, NIU, hc_name, inst, inst,
+	    NULL);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx enumeration failed: %s\n", _ENUM_NAME,
+		    (uint64_t)mde_node, topo_strerror(topo_mod_errno(mod)));
+		return (-1);
+	}
+
+	topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+	    _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_pciexrc.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,387 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Create a topology node for a PRI node of type 'pciexrc'
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include <libdevinfo.h>
+#include "pi_impl.h"
+
+#define	TOPO_PGROUP_PCIEX	"pciex"
+#define	TOPO_PCIEX_DRIVER	"px"
+#define	PCIEX_MAX_DEVICE	255
+
+#define	_ENUM_NAME	"enum_pciexrc"
+
+static const topo_pgroup_info_t io_pgroup =
+	{ TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
+
+static const topo_pgroup_info_t pci_pgroup =
+	{ TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
+
+static int pi_enum_pciexrc_finddev(topo_mod_t *, md_t *, mde_cookie_t,
+    tnode_t *);
+static int pi_enum_pciexrc_update(topo_mod_t *, md_t *, mde_cookie_t,
+    tnode_t *, tnode_t *);
+
+static int pi_enum_pciexrc_defer(topo_mod_t *, md_t *, mde_cookie_t,
+    topo_instance_t, tnode_t *, const char *, tnode_t *, void *);
+
+
+/*
+ * Create a pciexrc topo by calling the pciexrc enumerator for this instance.
+ */
+int
+pi_enum_pciexrc(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+    tnode_t **t_node)
+{
+	int		result;
+
+	topo_mod_dprintf(mod, "%s called for node_0x%llx type %s\n",
+	    _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+	*t_node = NULL;
+
+	/*
+	 * Create the root complex topo node.  Use the generic enumerator to
+	 * do this, and then we will add more attributes below.
+	 */
+	result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+	    t_parent, hc_name, _ENUM_NAME, t_node);
+	if (result != 0 || *t_node == NULL) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to create topo node: %s\n",
+		    _ENUM_NAME, topo_strerror(topo_mod_errno(mod)));
+		return (result);
+	}
+
+	/* Update the topo node with more specific information */
+	result = pi_enum_pciexrc_update(mod, mdp, mde_node, t_parent, *t_node);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to create node properites: %s\n",
+		    _ENUM_NAME, topo_strerror(topo_mod_errno(mod)));
+		return (result);
+	}
+
+	result = pi_enum_pciexrc_finddev(mod, mdp, mde_node, *t_node);
+	if (result == 0) {
+		/*
+		 * The node exists in this domain.  We will call the PCIBUS
+		 * enumerator after the entire PRI graph has been walked so
+		 * that all the possible FRU nodes are available for bus's
+		 * that span multiple FRU boundaries.
+		 */
+		result = pi_defer_add(mod, mde_node, t_parent, *t_node,
+		    pi_enum_pciexrc_defer, NULL);
+		if (result != 0) {
+			/* We cannot defer the call, so we need to do it now */
+			result = pi_enum_pciexrc_defer(mod, mdp, mde_node, inst,
+			    t_parent, hc_name, *t_node, NULL);
+		}
+	} else {
+		/*
+		 * It is OK if the node does not exist for further PCIBUS
+		 * enumeration.  We can return success having created the
+		 * root complex node itself.
+		 */
+		result = 0;
+	}
+	topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+	    _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+	return (result);
+}
+
+
+/* ARGSUSED */
+static int
+pi_enum_pciexrc_defer(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+    tnode_t *t_node, void *private)
+{
+	int		result;
+	topo_instance_t	min;
+	topo_instance_t	max;
+
+	topo_mod_dprintf(mod,
+	    "%s node_0x%llx deferred enumeration starting\n", _ENUM_NAME,
+	    (uint64_t)mde_node);
+
+	/* Make sure our dependent modules are loaded */
+	if (topo_mod_load(mod, PCI_BUS, TOPO_VERSION) == NULL) {
+		topo_mod_dprintf(mod, "%s could not load %s module: %s\n",
+		    _ENUM_NAME, PCI_BUS, topo_strerror(topo_mod_errno(mod)));
+		return (-1);
+	}
+
+	/* Create a node range for children of this bus */
+	min = 0;
+	max = PCIEX_MAX_DEVICE;
+	result = topo_node_range_create(mod, t_node, PCI_BUS, min, max);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to create node range: %s\n",
+		    _ENUM_NAME, topo_strerror(topo_mod_errno(mod)));
+		return (-1);
+	}
+
+	/*
+	 * Invoke the pcibus enumerator for this node.
+	 */
+	result = topo_mod_enumerate(mod, t_node, PCI_BUS, PCIEX_BUS,
+	    min, max, NULL);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx enumeration failed: %s\n", _ENUM_NAME,
+		    (uint64_t)mde_node, topo_strerror(topo_mod_errno(mod)));
+	}
+
+	topo_mod_dprintf(mod, "%s added node_0x%llx type %s\n",
+	    _ENUM_NAME, (uint64_t)mde_node, hc_name);
+
+	return (result);
+}
+
+
+/*
+ * Update a PCIEXRC topo node with node-specific information
+ *
+ * The following is mostly a duplicate of code contained in:
+ *	usr/src/lib/fm/topo/modules/sun4v/cpuboard/
+ *	    cpuboard_hostbridge.c:cpuboard_rc_node_create
+ */
+static int
+pi_enum_pciexrc_update(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    tnode_t *t_parent, tnode_t *t_node)
+{
+	int		result;
+	int		err;
+	char		dnpath[MAXPATHLEN];
+	uint64_t	cfg_handle;
+	nvlist_t	*modfmri;
+	nvlist_t	*devfmri;
+
+	if (t_parent == NULL || t_node == NULL) {
+		topo_mod_dprintf(mod, "%s node_0x%llx has no parent\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		return (-1);
+	}
+
+	/*
+	 * Calculate the device path for this root complex node.
+	 */
+	result = pi_get_cfg_handle(mod, mdp, mde_node, &cfg_handle);
+	if (result != 0) {
+		topo_mod_dprintf(mod, "node_0x%llx has no cfg-handle\n",
+		    (uint64_t)mde_node);
+		return (result);
+	}
+	(void) snprintf(dnpath, sizeof (dnpath), "/pci@%llx", cfg_handle);
+
+	/*
+	 * Set the ASRU for this node using the dev scheme
+	 */
+	devfmri = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, dnpath, NULL);
+	if (devfmri == NULL) {
+		topo_mod_dprintf(mod, "%s node_0x%llx fmri creation failed\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		return (-1);
+	}
+
+	result = topo_node_asru_set(t_node, devfmri, 0, &err);
+	nvlist_free(devfmri);
+	if (result != 0) {
+		topo_mod_dprintf(mod, "%s node_0x%llx failed to set ASRU\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (-1);
+	}
+
+	/*
+	 * Set PCIEXRC properties for root complex nodes
+	 */
+	result = topo_pgroup_create(t_node, &io_pgroup, &err);
+	if (result < 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx topo_pgroup_create for io pgroup failed\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+	result = topo_pgroup_create(t_node, &pci_pgroup, &err);
+	if (result < 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx topo_pgroup_create for pci pgroup failed\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+
+	result = topo_prop_set_string(t_node, TOPO_PGROUP_IO, TOPO_IO_DEV,
+	    TOPO_PROP_IMMUTABLE, dnpath, &err);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to set DEV property\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+
+	/* device type is always "pciex" */
+	result = topo_prop_set_string(t_node, TOPO_PGROUP_IO, TOPO_IO_DEVTYPE,
+	    TOPO_PROP_IMMUTABLE, TOPO_PGROUP_PCIEX, &err);
+	if (result < 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to set DEVTYPE property\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+
+	/*
+	 * driver is always "px"
+	 */
+	result = topo_prop_set_string(t_node, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
+	    TOPO_PROP_IMMUTABLE, TOPO_PCIEX_DRIVER, &err);
+	if (result < 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to set DRIVER property\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+
+	modfmri = topo_mod_modfmri(mod, FM_MOD_SCHEME_VERSION,
+	    TOPO_PCIEX_DRIVER);
+	if (modfmri == NULL) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to create module fmri\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+	result = topo_prop_set_fmri(t_node, TOPO_PGROUP_IO, TOPO_IO_MODULE,
+	    TOPO_PROP_IMMUTABLE, modfmri, &err);
+	nvlist_free(modfmri);
+	if (result < 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to set MODULE property\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+
+	/* This is a PCIEX root complex */
+	result = topo_prop_set_string(t_node, TOPO_PGROUP_PCI, TOPO_PCI_EXCAP,
+	    TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err);
+	if (result < 0) {
+		topo_mod_dprintf(mod,
+		    "%s node_0x%llx failed to set EXCAP property\n",
+		    _ENUM_NAME, (uint64_t)mde_node);
+		topo_mod_seterrno(mod, err);
+		return (result);
+	}
+
+	/* Create a node range for the children of this root complex */
+	topo_node_range_create(mod, t_node, PCIEX_BUS, 0, PCIEX_MAX_DEVICE);
+
+	return (0);
+}
+
+
+static int
+pi_enum_pciexrc_finddev(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    tnode_t *t_node)
+{
+	int		result;
+	di_node_t	devtree;
+	di_node_t	dnode;
+	uint64_t	cfg_handle;
+
+	/* Initialize the device information structure for this module */
+	devtree = topo_mod_devinfo(mod);
+	if (devtree == DI_NODE_NIL) {
+		topo_mod_dprintf(mod, "devinfo init failed\n");
+		return (-1);
+	}
+
+	/*
+	 * Find the PRI node cfg-handle.  This will be used to associate the
+	 * PRI node with the device node
+	 */
+	result = pi_get_cfg_handle(mod, mdp, mde_node, &cfg_handle);
+	if (result != 0) {
+		topo_mod_dprintf(mod, "node_0x%llx has no cfg-handle\n",
+		    (uint64_t)mde_node);
+		return (result);
+	}
+	topo_mod_dprintf(mod, "node_0x%llx has cfg-handle = /pci@%llx\n",
+	    (uint64_t)mde_node, cfg_handle);
+
+	/*
+	 * Scan the device node list and find the node associated with
+	 * the given PRI node.  Equality is defined as the PRI cfg-handle
+	 * equalling the device node bus address.
+	 */
+	dnode = di_drv_first_node(TOPO_PCIEX_DRIVER, devtree);
+	while (dnode != DI_NODE_NIL) {
+		uint64_t	bus_addr;
+		char		*addr;
+
+		addr = di_bus_addr(dnode);
+		if (addr != NULL) {
+			bus_addr = strtoull(addr, NULL, 16);
+			if (bus_addr == cfg_handle) {
+				/* We have found the matching dnode */
+				break;
+			}
+		}
+
+		/* We have not found the matching dnode yet */
+		dnode = di_drv_next_node(dnode);
+	}
+	if (dnode != DI_NODE_NIL) {
+		topo_mod_dprintf(mod, "%s node_0x%llx found bus 0x%llx\n",
+		    _ENUM_NAME, (uint64_t)mde_node, cfg_handle);
+
+		/*
+		 * Associate this dnode with the topo node.  The PCI
+		 * enumerator requires this information.
+		 */
+		topo_node_setspecific(t_node, (void *)dnode);
+	}
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_subr.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,963 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Subroutines used by various components of the Sun4v PI enumerator
+ */
+
+#include <sys/types.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include <sys/mdesc.h>
+#include <libnvpair.h>
+
+#include "pi_impl.h"
+
+static const topo_pgroup_info_t sys_pgroup = {
+	TOPO_PGROUP_SYSTEM,
+	TOPO_STABILITY_PRIVATE,
+	TOPO_STABILITY_PRIVATE,
+	1
+};
+
+static const topo_pgroup_info_t auth_pgroup = {
+	FM_FMRI_AUTHORITY,
+	TOPO_STABILITY_PRIVATE,
+	TOPO_STABILITY_PRIVATE,
+	1
+};
+
+
+/*
+ * Search the PRI for MDE nodes using md_scan_dag.  Using this routine
+ * consolodates similar searches used in a few places within the sun4vpi
+ * enumerator.
+ *
+ * The routine returns the number of nodes found, or -1.  If the node array
+ * is non-NULL on return, then it must be freed:
+ *	topo_mod_free(mod, nodes, nsize);
+ *
+ */
+int
+pi_find_mdenodes(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_start,
+    char *type_str, char *arc_str, mde_cookie_t **nodes, size_t *nsize)
+{
+	int	result;
+	int	total_mdenodes;
+
+	mde_str_cookie_t	start_cookie;
+	mde_str_cookie_t	arc_cookie;
+
+	/* Prepare to scan the PRI using the start string and given arc */
+	total_mdenodes	= md_node_count(mdp);
+	start_cookie	= md_find_name(mdp, type_str);
+	arc_cookie	= md_find_name(mdp, arc_str);
+
+	/* Allocate an array to hold the results of the scan */
+	*nsize		= sizeof (mde_cookie_t) * total_mdenodes;
+	*nodes		= topo_mod_zalloc(mod, *nsize);
+	if (*nodes == NULL) {
+		/* We have no memory.  Set an error code and return failure */
+		*nsize = 0;
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (-1);
+	}
+
+	result = md_scan_dag(mdp, mde_start, start_cookie, arc_cookie, *nodes);
+	if (result <= 0) {
+		/* No nodes found.  Free the node array before returning */
+		topo_mod_free(mod, *nodes, *nsize);
+		*nodes = NULL;
+		*nsize = 0;
+	}
+
+	return (result);
+}
+
+
+/*
+ * Determine if this node should be skipped by finding the topo-skip property.
+ */
+int
+pi_skip_node(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+	int		result;
+	uint64_t	skip;
+
+	if (mod == NULL || mdp == NULL) {
+		/*
+		 * These parameters are required.  Tell the caller to skip
+		 * all nodes.
+		 */
+		return (1);
+	}
+
+	skip = 0;	/* do not skip by default */
+	result = md_get_prop_val(mdp, mde_node, MD_STR_TOPO_SKIP, &skip);
+	if (result != 0) {
+		/*
+		 * There is no topo-skip property.  Assume we are not skipping
+		 * the mde node.
+		 */
+		skip = 0;
+	}
+
+	/*
+	 * If skip is present and non-zero we want to skip this node.  We
+	 * return 1 to indicate this.
+	 */
+	if (skip != 0) {
+		return (1);
+	}
+	return (0);
+}
+
+
+/*
+ * Get the cfg-handle property value from the given PRI node
+ */
+int
+pi_get_cfg_handle(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    uint64_t *cfg_handle)
+{
+	int		result;
+
+	if (cfg_handle == NULL) {
+		return (-1);
+	}
+
+	result = md_get_prop_val(mdp, mde_node, MD_STR_CFG_HANDLE, cfg_handle);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "failed to get property %s from node_0x%llx\n",
+		    MD_STR_CFG_HANDLE, (uint64_t)mde_node);
+	}
+	return (result);
+}
+
+
+/*
+ * Get the chassis serial number (the ID as far as the topo authority is
+ * concerned) either from the current node, if it is of type 'chassis', or
+ * search for a chassis node in the PRI.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_chassisid(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+	int		result;
+	int		idx;
+	int		num_nodes;
+	char		*id = NULL;
+	char		*hc_name = NULL;
+	size_t		chassis_size;
+	mde_cookie_t	*chassis_nodes = NULL;
+
+	topo_mod_dprintf(mod, "pi_get_chassis: enter\n");
+
+	hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
+	if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
+		topo_mod_strfree(mod, hc_name);
+
+		/*
+		 * This is a chassis node.  We need only search for the serial
+		 * number property on this node to return the ID.
+		 */
+		result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER,
+		    &id);
+		if (result != 0 || id == NULL || strlen(id) == 0) {
+			return (NULL);
+		}
+		topo_mod_dprintf(mod, "pi_get_chassis: chassis-id = %s\n", id);
+		return (topo_mod_strdup(mod, id));
+	}
+
+	/*
+	 * Search the PRI for nodes of type MD_STR_COMPONENT and find the
+	 * first element with topo-hc-type of MD_STR_CHASSIS.  This node
+	 * will contain the MD_STR_SERIAL_NUMBER property to use as the
+	 * chassis-id.
+	 */
+	num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
+	    MD_STR_COMPONENT, MD_STR_FWD, &chassis_nodes, &chassis_size);
+	if (num_nodes <= 0 || chassis_nodes == NULL) {
+		/* We did not find any chassis nodes */
+		return (NULL);
+	}
+	topo_mod_dprintf(mod, "pi_get_chassisid: found %d %s nodes\n",
+	    num_nodes, MD_STR_COMPONENT);
+
+	idx = 0;
+	while (id == NULL && idx < num_nodes) {
+		hc_name = pi_get_topo_hc_name(mod, mdp, chassis_nodes[idx]);
+		if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) {
+			/*
+			 * This is a chassis node.  Get the serial number
+			 * property from the node.
+			 */
+			result = md_get_prop_str(mdp, chassis_nodes[idx],
+			    MD_STR_SERIAL_NUMBER, &id);
+			if (result != 0) {
+				topo_mod_dprintf(mod, "pi_get_chassisid: "
+				    "failed to read %s from node_0x%llx\n",
+				    MD_STR_SERIAL_NUMBER,
+				    (uint64_t)chassis_nodes[idx]);
+			}
+		}
+		topo_mod_strfree(mod, hc_name);
+
+		/* Search the next node, if necessary */
+		idx++;
+	}
+	topo_mod_free(mod, chassis_nodes, chassis_size);
+
+	/* Everything is freed up and it's time to return the platform-id */
+	if (result != 0 || id == NULL || strlen(id) == 0) {
+		return (NULL);
+	}
+	topo_mod_dprintf(mod, "pi_get_chassis: chassis-id %s\n", id);
+
+	return (topo_mod_strdup(mod, id));
+}
+
+
+/*
+ * Determine if the node is a FRU by checking for the existance and non-zero
+ * value of the 'fru' property on the mde node.
+ */
+int
+pi_get_fru(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, int *is_fru)
+{
+	int		result;
+	uint64_t	fru;
+
+	if (mod == NULL || mdp == NULL || is_fru == NULL) {
+		return (-1);
+	}
+	fru = 0;
+	*is_fru = 0;
+
+	result = md_get_prop_val(mdp, mde_node, MD_STR_FRU, &fru);
+	if (result != 0) {
+		/* The node is not a FRU. */
+		return (-1);
+	}
+	if (fru != 0) {
+		*is_fru = 1;
+	}
+	return (0);
+}
+
+
+/*
+ * Get the id property value from the given PRI node
+ */
+int
+pi_get_instance(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t *ip)
+{
+	int		result;
+	uint64_t	id;
+
+	id = 0;
+	result = md_get_prop_val(mdp, mde_node, MD_STR_ID, &id);
+	if (result != 0) {
+		/*
+		 * There is no id property.
+		 */
+		topo_mod_dprintf(mod, "node_0x%llx has no id property\n",
+		    (uint64_t)mde_node);
+		return (-1);
+	}
+	*ip = id;
+
+	return (0);
+}
+
+
+/*
+ * If the given MDE node is a FRU return the 'nac' property, if it exists,
+ * to use as the label.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+	int	result;
+	int	is_fru;
+	char	*lp = NULL;
+
+	result = pi_get_fru(mod, mdp, mde_node, &is_fru);
+	if (result != 0 || is_fru == 0) {
+		/* This node is not a FRU.  It has no label */
+		return (NULL);
+	}
+
+	/*
+	 * The node is a FRU.  Get the NAC name to use as a label.
+	 */
+	result = md_get_prop_str(mdp, mde_node, MD_STR_NAC, &lp);
+	if (result != 0 || lp == NULL || strlen(lp) == 0) {
+		/* No NAC label.  Return NULL */
+		return (NULL);
+	}
+
+	/* Return a copy of the label */
+	return (topo_mod_strdup(mod, lp));
+}
+
+
+/*
+ * Return the complete part number string to the caller.  The complete part
+ * number is made up of the part number attribute concatenated with the dash
+ * number attribute of the mde node.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_part(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+	int	result;
+	size_t	bufsize;
+	char	*buf  = NULL;
+	char	*part = NULL;
+	char	*dash = NULL;
+
+	result = md_get_prop_str(mdp, mde_node, MD_STR_PART_NUMBER, &part);
+	if (result != 0) {
+		part = NULL;
+	}
+	result = md_get_prop_str(mdp, mde_node, MD_STR_DASH_NUMBER, &dash);
+	if (result != 0) {
+		dash = NULL;
+	}
+	bufsize = 1 + (part ? strlen(part) : 0) + (dash ? strlen(dash) : 0);
+	if (bufsize == 1) {
+		return (NULL);
+	}
+
+	/* Construct the part number from the part and dash values */
+	buf = topo_mod_alloc(mod, bufsize);
+	if (buf != NULL) {
+		(void) snprintf(buf, bufsize, "%s%s", (part ? part : ""),
+		    (dash ? dash : ""));
+	}
+
+	return (buf);
+}
+
+
+/*
+ * Get the product ID from the 'platform' node in the PRI
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_productid(topo_mod_t *mod, md_t *mdp)
+{
+	int		result;
+	char		*id = NULL;
+	size_t		platform_size;
+	mde_cookie_t	*platform_nodes = NULL;
+
+	topo_mod_dprintf(mod, "pi_get_product: enter\n");
+
+	/*
+	 * Search the PRI for nodes of type MD_STR_PLATFORM, which contains
+	 * the product-id in it's MD_STR_NAME property.
+	 */
+	result = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE,
+	    MD_STR_PLATFORM, MD_STR_FWD, &platform_nodes, &platform_size);
+	if (result <= 0 || platform_nodes == NULL) {
+		/* We did not find any platform nodes */
+		return (NULL);
+	}
+	topo_mod_dprintf(mod, "pi_get_productid: found %d platform nodes\n",
+	    result);
+
+	/*
+	 * There should only be 1 platform node, so we will always
+	 * use the first if we find any at all.
+	 */
+	result = md_get_prop_str(mdp, platform_nodes[0], MD_STR_NAME, &id);
+	topo_mod_free(mod, platform_nodes, platform_size);
+
+	/* Everything is freed up and it's time to return the platform-id */
+	if (result != 0 || id == NULL || strlen(id) == 0) {
+		return (NULL);
+	}
+	topo_mod_dprintf(mod, "pi_get_product: returning %s\n", id);
+
+	return (topo_mod_strdup(mod, id));
+}
+
+
+/*
+ * Return the revision string to the caller.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_revision(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+	int	result;
+	char	*rp = NULL;
+
+	result = md_get_prop_str(mdp, mde_node, MD_STR_REVISION_NUMBER, &rp);
+	if (result != 0 || rp == NULL || strlen(rp) == 0) {
+		return (NULL);
+	}
+
+	return (topo_mod_strdup(mod, rp));
+}
+
+
+/*
+ * Return the serial number string to the caller.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+	int		result;
+	uint64_t	sn;
+	char		*sp = NULL;
+	char		buf[MAXNAMELEN];
+
+	result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER, &sp);
+	if (result != 0 || sp == NULL || strlen(sp) == 0) {
+		/* Is this a uint64_t type serial number? */
+		result = md_get_prop_val(mdp, mde_node, MD_STR_SERIAL_NUMBER,
+		    &sn);
+		if (result != 0) {
+			/* No.  We have failed to find a serial number */
+			return (NULL);
+		}
+		topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx numeric "
+		    "serial number %llx\n", (uint64_t)mde_node, sn);
+
+		/* Convert the acquired value to a string */
+		result = snprintf(buf, sizeof (buf), "%llu", sn);
+		if (result < 0) {
+			return (NULL);
+		}
+		sp = buf;
+	}
+	topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx = %s\n",
+	    (uint64_t)mde_node, (sp == NULL ? "NULL" : sp));
+
+	return (topo_mod_strdup(mod, sp));
+}
+
+
+/*
+ * Get the server hostname (the ID as far as the topo authority is
+ * concerned) from sysinfo and return a copy to the caller.
+ *
+ * The string must be freed with topo_mod_strfree()
+ */
+char *
+pi_get_serverid(topo_mod_t *mod)
+{
+	int	result;
+	char	hostname[MAXNAMELEN];
+
+	topo_mod_dprintf(mod, "pi_get_serverid: enter\n");
+
+	result = sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
+	/* Everything is freed up and it's time to return the platform-id */
+	if (result == -1) {
+		return (NULL);
+	}
+	topo_mod_dprintf(mod, "pi_get_serverid: hostname = %s\n", hostname);
+
+	return (topo_mod_strdup(mod, hostname));
+}
+
+
+/*
+ * Get the hc scheme name for the given node
+ */
+char *
+pi_get_topo_hc_name(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node)
+{
+	int	result;
+	char	*hc_name;
+
+	/*
+	 * Request the hc name from the node.
+	 */
+	hc_name = NULL;
+	result = md_get_prop_str(mdp, mde_node, MD_STR_TOPO_HC_NAME, &hc_name);
+	if (result != 0 || hc_name == NULL) {
+		topo_mod_dprintf(mod,
+		    "failed to get property %s from node_0x%llx\n",
+		    MD_STR_TOPO_HC_NAME, (uint64_t)mde_node);
+		return (NULL);
+	}
+
+	/* Return a copy of the type string */
+	return (topo_mod_strdup(mod, hc_name));
+}
+
+
+/*
+ * Calculate the authority information for a node.  Inherit the data if
+ * possible, but always create an appropriate property group.
+ */
+int
+pi_set_auth(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    tnode_t *t_parent, tnode_t *t_node)
+{
+	int 		result;
+	int		err;
+	nvlist_t	*auth;
+	char		*val = NULL;
+	char		*prod = NULL;
+	char		*csn = NULL;
+	char		*server = NULL;
+
+	if (mod == NULL || mdp == NULL || t_parent == NULL || t_node == NULL) {
+		return (-1);
+	}
+
+	result = topo_pgroup_create(t_node, &auth_pgroup, &err);
+	if (result != 0 && err != ETOPO_PROP_DEFD) {
+		/*
+		 * We failed to create the property group and it was not
+		 * already defined.  Set the err code and return failure.
+		 */
+		topo_mod_seterrno(mod, err);
+		return (-1);
+	}
+
+	/* Get the authority information already available from the parent */
+	auth = topo_mod_auth(mod, t_parent);
+
+	/*
+	 * Set the authority data, inheriting it if possible, but creating it
+	 * if necessary.
+	 */
+	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
+	    FM_FMRI_AUTH_PRODUCT, &err);
+	if (result != 0 && err != ETOPO_PROP_DEFD) {
+		val = NULL;
+		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT,
+		    &val);
+		if (result != 0 || val == NULL) {
+			/*
+			 * No product information in the parent node or auth
+			 * list.  Find the product information in the PRI.
+			 */
+			prod = pi_get_productid(mod, mdp);
+			if (prod == NULL) {
+				topo_mod_dprintf(mod, "pi_set_auth: product "
+				    "name not found for node_0x%llx\n",
+				    (uint64_t)mde_node);
+			}
+		} else {
+			/*
+			 * Dup the string.  If we cannot find it in the auth
+			 * nvlist we will need to free it, so this lets us
+			 * have a single code path.
+			 */
+			prod = topo_mod_strdup(mod, val);
+		}
+
+		/*
+		 * We continue even if the product information is not available
+		 * to enumerate as much as possible.
+		 */
+		if (prod != NULL) {
+			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
+			    FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
+			    &err);
+			if (result != 0) {
+				/* Preserve the error and continue */
+				topo_mod_seterrno(mod, err);
+				topo_mod_dprintf(mod, "pi_set_auth: failed to "
+				    "set property %s (%d) : %s\n",
+				    FM_FMRI_AUTH_CHASSIS, err,
+				    topo_strerror(err));
+			}
+			topo_mod_strfree(mod, prod);
+		}
+	}
+
+	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
+	    FM_FMRI_AUTH_CHASSIS, &err);
+	if (result != 0 && err != ETOPO_PROP_DEFD) {
+		val = NULL;
+		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS,
+		    &val);
+		if (result != 0 || val == NULL) {
+			/*
+			 * No product information in the parent node or auth
+			 * list.  Find the product information in the PRI.
+			 */
+			csn = pi_get_chassisid(mod, mdp, mde_node);
+			if (csn == NULL) {
+				topo_mod_dprintf(mod, "pi_set_auth: csn "
+				    "name not found for node_0x%llx\n",
+				    (uint64_t)mde_node);
+			}
+		} else {
+			/*
+			 * Dup the string.  If we cannot find it in the auth
+			 * nvlist we will need to free it, so this lets us
+			 * have a single code path.
+			 */
+			csn = topo_mod_strdup(mod, val);
+		}
+
+		/*
+		 * We continue even if the product information is not available
+		 * to enumerate as much as possible.
+		 */
+		if (csn != NULL) {
+			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
+			    FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn,
+			    &err);
+			if (result != 0) {
+				/* Preserve the error and continue */
+				topo_mod_seterrno(mod, err);
+				topo_mod_dprintf(mod, "pi_set_auth: failed to "
+				    "set property %s (%d) : %s\n",
+				    FM_FMRI_AUTH_CHASSIS, err,
+				    topo_strerror(err));
+			}
+			topo_mod_strfree(mod, csn);
+		}
+	}
+
+	result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY,
+	    FM_FMRI_AUTH_SERVER, &err);
+	if (result != 0 && err != ETOPO_PROP_DEFD) {
+		val = NULL;
+		result = nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER,
+		    &val);
+		if (result != 0 || val == NULL) {
+			/*
+			 * No product information in the parent node or auth
+			 * list.  Find the product information in the PRI.
+			 */
+			server = pi_get_serverid(mod);
+			if (server == NULL) {
+				topo_mod_dprintf(mod, "pi_set_auth: server "
+				    "name not found for node_0x%llx\n",
+				    (uint64_t)mde_node);
+			}
+		} else {
+			/*
+			 * Dup the string.  If we cannot find it in the auth
+			 * nvlist we will need to free it, so this lets us
+			 * have a single code path.
+			 */
+			server = topo_mod_strdup(mod, val);
+		}
+
+		/*
+		 * We continue even if the product information is not available
+		 * to enumerate as much as possible.
+		 */
+		if (server != NULL) {
+			result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY,
+			    FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server,
+			    &err);
+			if (result != 0) {
+				/* Preserve the error and continue */
+				topo_mod_seterrno(mod, err);
+				topo_mod_dprintf(mod, "pi_set_auth: failed to "
+				    "set property %s (%d) : %s\n",
+				    FM_FMRI_AUTH_SERVER, err,
+				    topo_strerror(err));
+			}
+			topo_mod_strfree(mod, server);
+		}
+	}
+
+	nvlist_free(auth);
+
+	return (0);
+}
+
+
+/*
+ * Calculate a generic FRU for the given node.  If the node is not a FRU,
+ * then inherit the FRU data from the nodes parent.
+ */
+int
+pi_set_frufmri(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    const char *name, topo_instance_t inst, tnode_t *t_parent, tnode_t *t_node)
+{
+	int		result;
+	int		err;
+	int		is_fru;
+	char		*part;
+	char		*rev;
+	char		*serial;
+	nvlist_t	*auth = NULL;
+	nvlist_t	*frufmri = NULL;
+
+	if (t_node == NULL || mod == NULL || mdp == NULL) {
+		return (-1);
+	}
+
+	/*
+	 * Determine if this node is a FRU
+	 */
+	result = pi_get_fru(mod, mdp, mde_node, &is_fru);
+	if (result != 0 || is_fru == 0) {
+		/* This node is not a FRU.  Inherit from parent and return */
+		topo_node_fru_set(t_node, NULL, 0, &result);
+		return (0);
+	}
+
+	/*
+	 * This node is a FRU.  Create an FMRI.
+	 */
+	part	= pi_get_part(mod, mdp, mde_node);
+	rev	= pi_get_revision(mod, mdp, mde_node);
+	serial	= pi_get_serial(mod, mdp, mde_node);
+	auth	= topo_mod_auth(mod, t_parent);
+	frufmri	= topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION, name,
+	    inst, NULL, auth, part, rev, serial);
+	if (frufmri == NULL) {
+		topo_mod_dprintf(mod, "failed to create FRU: %s\n",
+		    topo_strerror(topo_mod_errno(mod)));
+	}
+	nvlist_free(auth);
+	topo_mod_strfree(mod, part);
+	topo_mod_strfree(mod, rev);
+	topo_mod_strfree(mod, serial);
+
+	/* Set the FRU, whether NULL or not */
+	result = topo_node_fru_set(t_node, frufmri, 0, &err);
+	if (result != 0)  {
+		topo_mod_seterrno(mod, err);
+	}
+	nvlist_free(frufmri);
+
+	return (result);
+}
+
+
+int
+pi_set_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, tnode_t *t_node)
+{
+	int	result;
+	int	err;
+	char	*label;
+
+	if (mod == NULL || mdp == NULL) {
+		return (-1);
+	}
+
+	/*
+	 * Get the label, if any, from the mde node and apply it as the label
+	 * for this topology node.  Note that a NULL label will inherit the
+	 * label from topology node's parent.
+	 */
+	label = pi_get_label(mod, mdp, mde_node);
+	result = topo_node_label_set(t_node, label, &err);
+	topo_mod_strfree(mod, label);
+	if (result != 0) {
+		topo_mod_seterrno(mod, err);
+		topo_mod_dprintf(mod, "pi_set_label: failed with label %s "
+		    "on node_0x%llx: %s\n", (label == NULL ? "NULL" : label),
+		    (uint64_t)mde_node, topo_strerror(err));
+	}
+
+	return (result);
+}
+
+
+/*
+ * Calculate the system information for a node.  Inherit the data if
+ * possible, but always create an appropriate property group.
+ */
+int
+pi_set_system(topo_mod_t *mod, tnode_t *t_node)
+{
+	int		result;
+	int		err;
+	struct utsname	uts;
+	char		isa[MAXNAMELEN];
+
+	if (mod == NULL || t_node == NULL) {
+		return (-1);
+	}
+
+	result = topo_pgroup_create(t_node, &sys_pgroup, &err);
+	if (result != 0 && err != ETOPO_PROP_DEFD) {
+		/*
+		 * We failed to create the property group and it was not
+		 * already defined.  Set the err code and return failure.
+		 */
+		topo_mod_seterrno(mod, err);
+		return (-1);
+	}
+
+	result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
+	    &err);
+	if (result != 0 && err != ETOPO_PROP_DEFD) {
+		isa[0] = '\0';
+		result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa));
+		if (result == -1) {
+			/* Preserve the error and continue */
+			topo_mod_dprintf(mod, "pi_set_system: failed to "
+			    "read SI_ARCHITECTURE: %d\n", errno);
+		}
+		if (strnlen(isa, MAXNAMELEN) > 0) {
+			result = topo_prop_set_string(t_node,
+			    TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA,
+			    TOPO_PROP_IMMUTABLE, isa, &err);
+			if (result != 0) {
+				/* Preserve the error and continue */
+				topo_mod_seterrno(mod, err);
+				topo_mod_dprintf(mod, "pi_set_auth: failed to "
+				    "set property %s (%d) : %s\n",
+				    TOPO_PROP_ISA, err, topo_strerror(err));
+			}
+		}
+	}
+
+	result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM,
+	    TOPO_PROP_MACHINE, &err);
+	if (result != 0 && err != ETOPO_PROP_DEFD) {
+		result = uname(&uts);
+		if (result == -1) {
+			/* Preserve the error and continue */
+			topo_mod_seterrno(mod, errno);
+			topo_mod_dprintf(mod, "pi_set_system: failed to "
+			    "read uname: %d\n", errno);
+		}
+		if (strnlen(uts.machine, sizeof (uts.machine)) > 0) {
+			result = topo_prop_set_string(t_node,
+			    TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE,
+			    TOPO_PROP_IMMUTABLE, uts.machine, &err);
+			if (result != 0) {
+				/* Preserve the error and continue */
+				topo_mod_seterrno(mod, err);
+				topo_mod_dprintf(mod, "pi_set_auth: failed to "
+				    "set property %s (%d) : %s\n",
+				    TOPO_PROP_MACHINE, err, topo_strerror(err));
+			}
+		}
+	}
+
+	return (0);
+}
+
+
+tnode_t *
+pi_node_bind(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    tnode_t *t_parent, const char *hc_name, topo_instance_t inst,
+    nvlist_t *fmri)
+{
+	int	result;
+	tnode_t	*t_node;
+
+	if (t_parent == NULL) {
+		topo_mod_dprintf(mod,
+		    "cannot bind for node_0x%llx instance %d type %s\n",
+		    (uint64_t)mde_node, inst, hc_name);
+		return (NULL);
+	}
+
+	/* Bind this node to the parent */
+	t_node = topo_node_bind(mod, t_parent, hc_name, inst, fmri);
+	if (t_node == NULL) {
+		topo_mod_dprintf(mod,
+		    "failed to bind node_0x%llx instance %d: %s\n",
+		    (uint64_t)mde_node, (uint32_t)inst,
+		    topo_strerror(topo_mod_errno(mod)));
+		return (NULL);
+	}
+	topo_mod_dprintf(mod, "bound node_0x%llx instance %d type %s\n",
+	    (uint64_t)mde_node, inst, hc_name);
+
+	/*
+	 * We have bound the node.  Now decorate it with an appropriate
+	 * FRU and label (which may be inherited from the parent).
+	 */
+	result = pi_set_frufmri(mod, mdp, mde_node, hc_name, inst, t_parent,
+	    t_node);
+	if (result != 0) {
+		/*
+		 * Though we have failed to set the FRU FMRI we still continue.
+		 * The module errno is set by the called routine, so we report
+		 * the problem and move on.
+		 */
+		topo_mod_dprintf(mod,
+		    "failed to set FRU FMRI for node_0x%llx\n",
+		    (uint64_t)mde_node);
+	}
+
+	result = pi_set_label(mod, mdp, mde_node, t_node);
+	if (result != 0) {
+		/*
+		 * Though we have failed to set the label, we still continue.
+		 * The module errno is set by the called routine, so we report
+		 * the problem and move on.
+		 */
+		topo_mod_dprintf(mod, "failed to set label for node_0x%llx\n",
+		    (uint64_t)mde_node);
+	}
+
+	result = pi_set_auth(mod, mdp, mde_node, t_parent, t_node);
+	if (result != 0) {
+		/*
+		 * Though we have failed to set the authority, we still
+		 * continue. The module errno is set by the called routine, so
+		 * we report the problem and move on.
+		 */
+		topo_mod_dprintf(mod, "failed to set authority for "
+		    "node_0x%llx\n", (uint64_t)mde_node);
+	}
+
+	result = pi_set_system(mod, t_node);
+	if (result != 0) {
+		/*
+		 * Though we have failed to set the system group, we still
+		 * continue. The module errno is set by the called routine, so
+		 * we report the problem and move on.
+		 */
+		topo_mod_dprintf(mod, "failed to set system for node_0x%llx\n",
+		    (uint64_t)mde_node);
+	}
+
+	return (t_node);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_top.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,63 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Create a topology node for a top level PRI node, one that is a child
+ * of the 'components' node.
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <sys/fm/protocol.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define	_ENUM_NAME	"enum_top"
+
+/*
+ * This enumerator is the same as the generic enumerator, except that when
+ * the FMRI is created, the parent node must be NULL.  This is true for all
+ * top level nodes.
+ */
+int
+pi_enum_top(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    topo_instance_t inst, tnode_t *t_parent, const char *hc_name,
+    tnode_t **t_node)
+{
+	int	result;
+
+	/*
+	 * This is a top-level topology node and there is no resource data
+	 * from which to generate an FMRI.  We use a NULL value for the FMRI
+	 * parent when creating the FMRI for this node so that the underlying
+	 * libtopo method does not fail.
+	 */
+	result = pi_enum_generic_impl(mod, mdp, mde_node, inst, t_parent,
+	    NULL, hc_name, _ENUM_NAME, t_node);
+	return (result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/pi_walker.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,754 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Walk the LDOM PRI component nodes and create appropriate topology nodes
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <strings.h>
+#include <string.h>
+#include <libuutil.h>
+#include <libnvpair.h>
+#include <sys/mdesc.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include "pi_impl.h"
+
+#define	PI_STR_MIN	"instance_min"
+#define	PI_STR_MAX	"instance_max"
+
+/*
+ * Allow for custom topo node creation routines based on topo-hc-name.
+ */
+struct pi_enum_functions_s {
+	pi_enum_fn_t	*func;
+	char		*hc_name;	/* topo-hc-name */
+};
+typedef struct pi_enum_functions_s pi_enum_functions_t;
+
+/*
+ * List of custom enumerators for PRI nodes that require them.  The most
+ * common nodes are listed first.
+ */
+static pi_enum_functions_t pi_enum_fns_builtin[] = {
+	{pi_enum_cpu,		CPU},
+	{pi_enum_pciexrc,	PCIEX_ROOT},
+	{pi_enum_niu,		NIU},
+	{NULL, NULL}
+};
+static nvlist_t *pi_enum_fns;
+
+
+/*
+ * In order to create a topology node from a PRI MDE node we need to know the
+ * topology parent node that should be used.  So, after creating a topology
+ * node from an MDE node, we associate children of the MDE node with the new
+ * topology node.  Thus, when the children are visited we can know the
+ * appropriate parent topology node to use.
+ *
+ * We take advantage of the libtopo threading model here, which guarantees a
+ * single thread and a single invocation at a time for an enumerator.  This
+ * makes using a file-global safe.
+ */
+static uu_list_pool_t	*walker_pool;
+static uu_list_t	*walker_list;
+
+struct pi_walkernode_s {
+	uu_list_node_t	walker_node;
+	tnode_t		*t_parent;	/* Parent topology node */
+	mde_cookie_t	mde_node;	/* Child MDE node index */
+};
+typedef struct pi_walkernode_s pi_walkernode_t;
+
+
+/* The routine called for each node in the PRI while walking the graph */
+static int pi_walker_node(md_t *, mde_cookie_t, mde_cookie_t, void *);
+
+/*
+ * Create a sub-range for a given PRI node and associate the given topology
+ * node with the children.
+ */
+static int  pi_walker_node_range(topo_mod_t *, md_t *, tnode_t *, mde_cookie_t);
+static int  pi_walker_node_create(topo_mod_t *, md_t *, mde_cookie_t, tnode_t *,
+    topo_instance_t, tnode_t **);
+
+/* Routines to handle the list of topology parents and mde_nodes */
+static int  pi_walkerlist_compare(const void *, const void *, void *);
+static int  pi_walkerlist_create(topo_mod_t *);
+static void pi_walkerlist_destroy(topo_mod_t *);
+static int  pi_walkerlist_add(topo_mod_t *, tnode_t *, mde_cookie_t);
+static int  pi_walkerlist_addtype(topo_mod_t *, nvlist_t *, char *, uint32_t,
+    uint32_t);
+static int  pi_walkerlist_find(topo_mod_t *, mde_cookie_t, tnode_t **);
+
+
+int
+pi_walker_init(topo_mod_t *mod)
+{
+	int			result;
+	pi_enum_functions_t	*fp;
+
+	result = topo_mod_nvalloc(mod, &pi_enum_fns, NV_UNIQUE_NAME);
+	if (result != 0) {
+		topo_mod_dprintf(mod, "pi_walker_init failed\n");
+		return (-1);
+	}
+
+	/* Add the builtin functions to the list */
+	fp = pi_enum_fns_builtin;
+	while (fp != NULL && fp->hc_name != NULL) {
+		uint64_t	faddr;
+
+		faddr = (uint64_t)(uintptr_t)*(fp->func);
+		result = nvlist_add_uint64(pi_enum_fns, fp->hc_name, faddr);
+		if (result != 0) {
+			topo_mod_dprintf(mod, "pi_walker_init failed\n");
+			nvlist_free(pi_enum_fns);
+			return (-1);
+		}
+		fp++;
+	}
+
+	return (0);
+}
+
+
+void
+pi_walker_fini(topo_mod_t *mod)
+{
+	topo_mod_dprintf(mod, "pi_walker_fini: enter\n");
+	nvlist_free(pi_enum_fns);
+}
+
+
+/*
+ * Begin to walk the machine description array starting at the given PRI node.
+ */
+int
+pi_walker(pi_enum_t *pip, tnode_t *t_parent, const char *hc_name,
+    mde_cookie_t mde_node, mde_str_cookie_t component_cookie,
+    mde_str_cookie_t arc_cookie)
+{
+	int		result;
+	hrtime_t	starttime;
+	hrtime_t	endtime;
+	topo_mod_t	*mod;
+
+	if (pip == NULL) {
+		return (-1);
+	}
+	mod = pip->mod;
+
+	starttime = gethrtime();
+	topo_mod_dprintf(mod, "walker starting at node_0x%llx\n",
+	    mde_node);
+
+	/*
+	 * Create a list to store topology nodes and their associated machine
+	 * description index.  This allows the code to know the parent of a
+	 * node when creating topology entries.
+	 */
+	result = pi_walkerlist_create(mod);
+	if (result != 0) {
+		topo_mod_dprintf(mod, "walker could not create list\n");
+		return (result);
+	}
+
+	/* Create a walker node for the parent of the start node */
+	result = pi_walkerlist_add(mod, t_parent, mde_node);
+	if (result != 0) {
+		pi_walkerlist_destroy(mod);
+		topo_mod_dprintf(mod, "walker could not add to list\n");
+		topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+		return (result);
+	}
+
+	/*
+	 * This is a top-level node.  Make sure we call the top level
+	 * enumerator if there is not already a custom enumerator registered.
+	 */
+	if (! nvlist_exists(pi_enum_fns, hc_name)) {
+		uint64_t	faddr;
+
+		/*
+		 * There is no enumerator function registered for this
+		 * hc name.  Automatically register the top level node
+		 * enumerator function.
+		 */
+		faddr = (uint64_t)(uintptr_t)pi_enum_top;
+		result = nvlist_add_uint64(pi_enum_fns, hc_name, faddr);
+		if (result != 0) {
+			pi_walkerlist_destroy(mod);
+			topo_mod_dprintf(mod,
+			    "walker could not register enumerator for type "
+			    "%s\n", hc_name);
+			topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+			return (-1);
+		}
+		topo_mod_dprintf(mod,
+		    "walker registered pi_enum_top enumerator for type %s\n",
+		    hc_name);
+	}
+
+	/* Walk the machine description list starting at the given node */
+	result = md_walk_dag(pip->mdp, mde_node, component_cookie, arc_cookie,
+	    pi_walker_node, (void *)pip);
+	switch (result) {
+		case 0:
+			/* Successful completion */
+			/* DO NOTHING */
+		break;
+
+		case MDE_WALK_ERROR:
+			/*
+			 * Store that we have a partial enumeration and return
+			 * that we have encountered an error.
+			 */
+			topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+			result = -1;
+		break;
+
+		default:
+			/*
+			 * This should not happen.  We want to always produce
+			 * as complete a topology as possible, even in the face
+			 * of errors, however, so set an error and continue.
+			 */
+			topo_mod_dprintf(mod,
+			    "walker encountered invalid result: %d. "
+			    "Continuing\n", result);
+			topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+			result = 0;
+		break;
+	}
+
+	/* Destroy the walker list, which is no longer necessary */
+	pi_walkerlist_destroy(mod);
+
+	topo_mod_dprintf(mod, "walker done with node_0x%llx\n", mde_node);
+
+	endtime = gethrtime();
+	topo_mod_dprintf(mod, "walker scan time %lld ms\n",
+	    (endtime-starttime)/MICROSEC);
+
+	return (result);
+}
+
+
+/*
+ * Visited once for each node in the machine description.  Creates a topo
+ * node for the machine description node and associates it with it's parent,
+ * by calling an appropriate creation routine for the node type.
+ *
+ * Output:
+ * 	This routine returns MDE_WALK_NEXT, MDE_WALK_DONE or MDE_WALK_ERROR
+ * only.
+ */
+static int
+pi_walker_node(md_t *mdp, mde_cookie_t parent_mde_node, mde_cookie_t mde_node,
+    void *private)
+{
+	int		result;
+	pi_enum_t	*pip	= (pi_enum_t *)private;
+	uint64_t	skip;		/* flag in md to skip this node	*/
+	tnode_t		*t_parent;	/* topo parent to this md node	*/
+	tnode_t		*t_node;	/* topo parent to this md node	*/
+	topo_instance_t	inst;
+
+	topo_mod_t	*mod;
+
+	/* Make sure we have our private data */
+	if (pip == NULL) {
+		return (MDE_WALK_ERROR);
+	}
+	mod = pip->mod;
+
+	topo_mod_dprintf(pip->mod,
+	    "walker processing node_0x%llx parent node 0x%llx\n",
+	    (uint64_t)mde_node, (uint64_t)parent_mde_node);
+
+	/* Should we skip this node ? */
+	skip = pi_skip_node(mod, pip->mdp, mde_node);
+	if (skip) {
+		/* Skip this node and continue to the next node */
+		topo_mod_dprintf(mod, "walker skipping node_0x%llx\n",
+		    (uint64_t)mde_node);
+		return (MDE_WALK_NEXT);
+	}
+
+	result = pi_get_instance(mod, mdp, mde_node, &inst);
+	if (result != 0) {
+		/*
+		 * No ID available to place this mde node in the topology so
+		 * we cannot create a topology node.
+		 */
+		topo_mod_dprintf(mod, "walker skipping node_0x%llx: "
+		    "no instance\n", (uint64_t)mde_node);
+		topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+		return (MDE_WALK_NEXT);
+	}
+
+	/*
+	 * Find the parent topo node for this machine description node.
+	 *
+	 * If found, the element will also be removed from the list and the
+	 * memory used to keep track of it released.  We will only visit an
+	 * MDE node once and so the memory is no longer needed.
+	 */
+	t_parent = NULL;
+	result = pi_walkerlist_find(mod, mde_node, &t_parent);
+	if (result != 0 || t_parent == NULL) {
+		/*
+		 * No parent was found or a NULL parent encountered.  We
+		 * cannot create a new topology node without a parent (
+		 * even for top level nodes).  We associate children of
+		 * this MDE node with a NULL parent to silently skip the
+		 * remainder of this MDE branch.
+		 */
+		topo_mod_dprintf(mod, "no topo parent found for node_0x%llx\n",
+		    mde_node);
+		result = pi_walker_node_range(mod, mdp, NULL, mde_node);
+		topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+
+		return (result);
+	}
+
+	/*
+	 * We have the mde node instance and parent information.
+	 * Attempt to create a topology node for this mde node.
+	 */
+	t_node = NULL;
+	result = pi_walker_node_create(mod, mdp, mde_node, t_parent, inst,
+	    &t_node);
+	if (result != MDE_WALK_NEXT || t_node == NULL) {
+		/*
+		 * We have failed to create a new topology node based on
+		 * the current MDE node.  We set partial enumeration and
+		 * return without associating the children of this MDE
+		 * node with a topology parent.  This will propgate the
+		 * creation error down this MDE branch.
+		 */
+		topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+		return (result);
+	}
+
+	/*
+	 * Associate the new topology node with any children of this mde node.
+	 */
+	result = pi_walker_node_range(mod, mdp, t_node, mde_node);
+
+	topo_mod_dprintf(mod, "walker completed node_0x%llx result = %d\n",
+	    (uint64_t)mde_node, result);
+
+	return (result);
+}
+
+
+static int
+pi_walker_node_create(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node,
+    tnode_t *t_parent, topo_instance_t inst, tnode_t **t_node)
+{
+	int		result;
+	char		*hc_name;
+	uint64_t	faddr;
+	pi_enum_fn_t	*func;
+
+	if (t_parent == NULL) {
+		/*
+		 * A parent topology node is required even for top-level
+		 * nodes.
+		 */
+		return (MDE_WALK_NEXT);
+	}
+
+	/*
+	 * Find the topo-hc-name for this node which is used to find
+	 * the specific creation function
+	 */
+	hc_name = pi_get_topo_hc_name(mod, mdp, mde_node);
+	if (hc_name == NULL) {
+		/* Cannot get the hc-name */
+		topo_mod_dprintf(mod,
+		    "failed to find hc-name for node_0x%llx\n", mde_node);
+		return (MDE_WALK_NEXT);
+	}
+
+	/* Determine the topology node creation routine to use */
+	func = pi_enum_generic;
+	faddr = 0;
+	result = nvlist_lookup_uint64(pi_enum_fns, hc_name, &faddr);
+	if (result == 0) {
+		/*
+		 * A function is registered for this node. Convert the
+		 * address to a pointer to function
+		 */
+		func = (pi_enum_fn_t *)(uintptr_t)faddr;
+	}
+
+	/*
+	 * Create a topology node for this mde node by calling the identified
+	 * enumeration function
+	 */
+	*t_node = NULL;
+	result = (func)(mod, mdp, mde_node, inst, t_parent, hc_name, t_node);
+	if (result != 0) {
+		topo_mod_dprintf(mod,
+		    "failed to create topo entry for node_0x%llx type %s\n",
+		    (uint64_t)mde_node, hc_name);
+	}
+	topo_mod_strfree(mod, hc_name);
+
+	return (MDE_WALK_NEXT);
+}
+
+
+/*
+ * Scan the children of a given MDE node and find all the sets of topo-hc-name
+ * types and their instance ranges.  From this information we create topology
+ * node ranges on the given parent so that when the children are visited and a
+ * topology node is created, the range exists and the creation will succeed.
+ */
+static int
+pi_walker_node_range(topo_mod_t *mod, md_t *mdp, tnode_t *t_parent,
+    mde_cookie_t mde_node)
+{
+	int		result;
+	int		rc;
+	int		num_arcs;
+	nvlist_t	*typelist;
+	nvpair_t	*nvp;
+	mde_cookie_t	*arcp;
+	size_t		arcsize;
+	int		arcidx;
+	char		*hc_name;
+	nvlist_t	*hc_range;
+	topo_instance_t	inst;
+	uint32_t	min;
+	uint32_t	max;
+
+	if (t_parent == NULL) {
+		topo_mod_dprintf(mod,
+		"walker failed to create node range with a NULL parent\n");
+		return (MDE_WALK_NEXT);
+	}
+
+	/* Determine how many children the given node has */
+	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, NULL, 0);
+	if (num_arcs == 0) {
+		/* This node has no children */
+		return (MDE_WALK_NEXT);
+	}
+	topo_mod_dprintf(mod, "node_0x%llx has %d children\n",
+	    (uint64_t)mde_node, num_arcs);
+
+	/* Get the indexes for all the child nodes and put them in an array */
+	arcsize	= sizeof (mde_cookie_t) * num_arcs;
+	arcp = topo_mod_zalloc(mod, arcsize);
+	if (arcp == NULL) {
+		topo_mod_dprintf(mod, "out of memory\n");
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (MDE_WALK_ERROR);
+	}
+	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, arcp, arcsize);
+
+	/*
+	 * The children of the given node may have multiple types.
+	 * Potentially, each child may have a different type and we need to
+	 * create a topo node range for each one.
+	 *
+	 * We loop through the children and collect the type information for
+	 * each one and associate the child with the given parent topo node.
+	 */
+	result = topo_mod_nvalloc(mod, &typelist, NV_UNIQUE_NAME);
+	if (result != 0) {
+		topo_mod_free(mod, arcp, arcsize);
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (MDE_WALK_ERROR);
+	}
+
+	arcidx = 0;
+	for (arcidx = 0; arcidx < num_arcs; arcidx++) {
+		/* Should this node be skipped? */
+		if (pi_skip_node(mod, mdp, arcp[arcidx])) {
+			/* Skip this node */
+			topo_mod_dprintf(mod, "skipping node_0x%llx\n",
+			    (uint64_t)arcp[arcidx]);
+			continue;
+		}
+
+		/* Get the type of this node */
+		hc_name = pi_get_topo_hc_name(mod, mdp, arcp[arcidx]);
+		rc = pi_get_instance(mod, mdp, arcp[arcidx], &inst);
+		if (rc == 0 && hc_name != NULL) {
+			/* Increment the count of nodes with this type */
+			hc_range = NULL;
+			rc = nvlist_lookup_nvlist(typelist, hc_name, &hc_range);
+			if (rc != 0) {
+				/*
+				 * We have not visited this type yet.  Create
+				 * a new range based on this nodes instance
+				 * information.
+				 */
+				result = pi_walkerlist_addtype(mod, typelist,
+				    hc_name, (uint32_t)inst, (uint32_t)inst);
+				if (result != 0) {
+					/*
+					 * This error can only if there was a
+					 * memory failure of some kind.  Stop
+					 * the walk or it will just get worse.
+					 */
+					nvlist_free(typelist);
+					topo_mod_strfree(mod, hc_name);
+					topo_mod_free(mod, arcp, arcsize);
+					topo_mod_seterrno(mod,
+					    EMOD_PARTIAL_ENUM);
+					return (MDE_WALK_ERROR);
+				}
+
+				/*
+				 * We know the list exists now or the above
+				 * would have failed.  Just look it up.
+				 */
+				(void) nvlist_lookup_nvlist(typelist, hc_name,
+				    &hc_range);
+			}
+
+			/* Re-calculate the range minimums and maximums */
+			(void) nvlist_lookup_uint32(hc_range, PI_STR_MIN, &min);
+			(void) nvlist_lookup_uint32(hc_range, PI_STR_MAX, &max);
+			min = MIN(min, (uint32_t)inst);
+			max = MAX(max, (uint32_t)inst);
+			(void) nvlist_add_uint32(hc_range, PI_STR_MIN, min);
+			(void) nvlist_add_uint32(hc_range, PI_STR_MAX, max);
+
+		} else {
+			topo_mod_dprintf(mod, "node_0x%llx type %s has no id. "
+			    "Excluding from range", (uint64_t)arcp[arcidx],
+			    hc_name);
+		}
+		topo_mod_strfree(mod, hc_name);
+
+		/*
+		 * Associate this node with the given topo parent even if it
+		 * has no instance.  We do this so that later an error with
+		 * the PRI node will be reported instead of an internal
+		 * error about not being able to find the parent of a node
+		 */
+		rc = pi_walkerlist_add(mod, t_parent, arcp[arcidx]);
+		if (rc != 0) {
+			topo_mod_dprintf(mod,
+			    "could not add node_0x%llx to walker list\n",
+			    (uint64_t)arcp[arcidx]);
+		}
+	}
+
+	/*
+	 * We have associated all the child nodes with the given topo parent
+	 * in the walker list.  Now we need to create topo ranges for each
+	 * set of child types under the parent.
+	 */
+	nvp = nvlist_next_nvpair(typelist, NULL);
+	while (nvp != NULL) {
+		/* Get the type name and count from the list element */
+		hc_name = nvpair_name(nvp);
+		(void) nvpair_value_nvlist(nvp, &hc_range);
+		(void) nvlist_lookup_uint32(hc_range, PI_STR_MIN, &min);
+		(void) nvlist_lookup_uint32(hc_range, PI_STR_MAX, &max);
+
+		/*
+		 * We have the number of children with this type.
+		 * Create an appropriate range.
+		 */
+		topo_mod_dprintf(mod,
+		    "creating instance range %d to %d of type %s\n",
+		    min, max, hc_name);
+		rc = topo_node_range_create(mod, t_parent, hc_name,
+		    (topo_instance_t)min, (topo_instance_t)max);
+		if (rc != 0) {
+			topo_mod_dprintf(mod,
+			    "failed to created node range %d to %d for "
+			    "nodes of type %s\n", min, max, hc_name);
+		}
+
+		/* Check the next node */
+		nvp = nvlist_next_nvpair(typelist, nvp);
+	}
+	topo_mod_free(mod, arcp, arcsize);
+	nvlist_free(typelist);
+
+	return (MDE_WALK_NEXT);
+}
+
+
+static int
+pi_walkerlist_addtype(topo_mod_t *mod, nvlist_t *typelist, char *hc_name,
+    uint32_t min, uint32_t max)
+{
+	int		result;
+	nvlist_t	*nvl;
+
+	result = topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME);
+	if (result != 0) {
+		return (result);
+	}
+
+	/* Create min and max elements in this list */
+	if (nvlist_add_uint32(nvl, PI_STR_MIN, min) != 0 ||
+	    nvlist_add_uint32(nvl, PI_STR_MAX, max) != 0 ||
+	    nvlist_add_nvlist(typelist, hc_name, nvl) != 0) {
+		nvlist_free(nvl);
+		return (-1);
+	}
+	nvlist_free(nvl);
+
+	return (0);
+}
+
+
+/* ARGSUSED */
+static int
+pi_walkerlist_compare(const void *left, const void *right, void *private)
+{
+	pi_walkernode_t	*lp = (pi_walkernode_t *)left;
+	pi_walkernode_t	*rp = (pi_walkernode_t *)right;
+
+	if (lp->mde_node > rp->mde_node) {
+		return (1);
+	}
+	if (lp->mde_node < rp->mde_node) {
+		return (-1);
+	}
+	return (0);
+}
+
+
+static int
+pi_walkerlist_create(topo_mod_t *mod)
+{
+	/* Initialize the uutil list structure */
+	walker_pool = uu_list_pool_create("pi_walker_pool",
+	    sizeof (pi_walkernode_t), offsetof(pi_walkernode_t, walker_node),
+	    pi_walkerlist_compare, NULL);
+	if (walker_pool == NULL) {
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (-1);
+	}
+	walker_list = uu_list_create(walker_pool, NULL, 0);
+	if (walker_list == NULL) {
+		uu_list_pool_destroy(walker_pool);
+		return (-1);
+	}
+
+	return (0);
+}
+
+
+static void
+pi_walkerlist_destroy(topo_mod_t *mod)
+{
+	void		*wvp;
+	pi_walkernode_t	*wp;
+
+	/* Destroy our list of items */
+	while ((wvp = uu_list_first(walker_list)) != NULL) {
+		/*
+		 * First, we empty the list of elements and free each one.
+		 * We do not free the data elements as they are libtopo nodes
+		 * and will be freed by libtopo
+		 */
+		wp = (pi_walkernode_t *)wvp;
+		uu_list_remove(walker_list, wvp);
+		uu_list_node_fini(wp, &(wp->walker_node), walker_pool);
+
+		topo_mod_free(mod, wvp, sizeof (pi_walkernode_t));
+	}
+	uu_list_destroy(walker_list);
+	uu_list_pool_destroy(walker_pool);
+}
+
+
+static int
+pi_walkerlist_add(topo_mod_t *mod, tnode_t *t_parent, mde_cookie_t mde_node)
+{
+	uu_list_index_t	idx;
+	pi_walkernode_t	*wnp;
+
+	wnp = topo_mod_zalloc(mod, sizeof (pi_walkernode_t));
+	if (wnp == NULL) {
+		topo_mod_dprintf(mod, "failed to add node_0x%llx parent %p\n",
+		    (uint64_t)mde_node, t_parent);
+		return (-1);
+	}
+	uu_list_node_init(wnp, &(wnp->walker_node), walker_pool);
+
+	wnp->t_parent	= t_parent;
+	wnp->mde_node	= mde_node;
+
+	(void) uu_list_find(walker_list, wnp, NULL, &idx);
+	uu_list_insert(walker_list, wnp, idx);
+
+	return (0);
+}
+
+
+/*
+ * Find the parent topo node for this machine description node.
+ *
+ * Nodes are removed from the list as they are found.  They are only
+ * visited once and this eliminates the need for a separate routine
+ * that walks the list to free elements later.
+ */
+static int
+pi_walkerlist_find(topo_mod_t *mod, mde_cookie_t mde_node, tnode_t **tpp)
+{
+	pi_walkernode_t	*result;
+
+	uu_list_index_t	idx;
+	pi_walkernode_t	search_criteria;
+
+	search_criteria.mde_node = mde_node;
+	search_criteria.t_parent = NULL;
+
+	*tpp = NULL;
+	result = uu_list_find(walker_list, &search_criteria, NULL, &idx);
+	if (result == NULL) {
+		return (-1);
+	}
+	*tpp = result->t_parent;
+
+	/* Remove this element from the list */
+	uu_list_remove(walker_list, result);
+	uu_list_node_fini(result, &(result->walker_node), walker_pool);
+	topo_mod_free(mod, result, sizeof (pi_walkernode_t));
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/sun4vpi.c	Mon Jul 28 15:46:04 2008 -0700
@@ -0,0 +1,289 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Main entry points for SUN4V Platform Independent topology enumerator
+ */
+#include <sys/types.h>
+#include <strings.h>
+#include <fm/topo_mod.h>
+#include <fm/topo_hc.h>
+#include <sys/systeminfo.h>
+#include <pi_impl.h>
+
+/*
+ * Entry point called by libtopo when enumeration is required
+ */
+static topo_enum_f	pi_enum;	/* libtopo enumeration entry point */
+
+
+/*
+ * Declare the operations vector and information structure used during
+ * module registration
+ */
+static topo_modops_t	pi_ops	= {pi_enum, NULL};
+static topo_modinfo_t	pi_modinfo	= {
+    SUN4VPI_DESC, SUN4VPI_SCHEME, SUN4VPI_VERSION, &pi_ops
+};
+
+static int pi_enum_components(pi_enum_t *, tnode_t *, const char *,
+    mde_cookie_t, mde_str_cookie_t, mde_str_cookie_t);
+
+
+/*
+ * Called by libtopo when the topo module is loaded.
+ */
+void
+_topo_init(topo_mod_t *mod, topo_version_t version)
+{
+	int		result;
+	char		isa[MAXNAMELEN];
+
+	if (getenv("TOPOSUN4VPIDBG") != NULL) {
+		/* Debugging is requested for this module */
+		topo_mod_setdebug(mod);
+	}
+	topo_mod_dprintf(mod, "sun4vpi module initializing.\n");
+
+	if (version != TOPO_VERSION) {
+		topo_mod_seterrno(mod, EMOD_VER_NEW);
+		topo_mod_dprintf(mod, "incompatible topo version %d\n",
+		    version);
+		return;
+	}
+
+	/* Verify that this is a SUN4V architecture machine */
+	(void) sysinfo(SI_MACHINE, isa, MAXNAMELEN);
+	if (strncmp(isa, "sun4v", MAXNAMELEN) != 0) {
+		topo_mod_dprintf(mod, "not sun4v architecture: %s\n", isa);
+		return;
+	}
+
+	result = topo_mod_register(mod, &pi_modinfo, TOPO_VERSION);
+	if (result < 0) {
+		topo_mod_dprintf(mod, "registration failed: %s\n",
+		    topo_mod_errmsg(mod));
+
+		/* module errno already set */
+		return;
+	}
+	topo_mod_dprintf(mod, "module ready.\n");
+}
+
+
+/*
+ * Clean up any data used by the module before it is unloaded.
+ */
+void
+_topo_fini(topo_mod_t *mod)
+{
+	topo_mod_dprintf(mod, "module finishing.\n");
+
+	/* Unregister from libtopo */
+	topo_mod_unregister(mod);
+}
+
+
+/*
+ * Enumeration entry point for the SUN4V topology enumerator
+ */
+/* ARGSUSED */
+static int
+pi_enum(topo_mod_t *mod, tnode_t *t_parent, const char *name,
+    topo_instance_t min, topo_instance_t max, void *pi_private, void *data)
+{
+	int		result;
+	int		idx;
+	int		num_components;
+	size_t		csize;
+	hrtime_t	starttime;
+
+	pi_enum_t	pi;
+
+	mde_cookie_t	*components;
+	mde_str_cookie_t arc_cookie;
+	mde_str_cookie_t component_cookie;
+
+	/* Begin enumeration */
+	starttime = gethrtime();
+	topo_mod_dprintf(mod, "enumeration starting.\n");
+
+	/* Initialize the walker */
+	result = pi_walker_init(mod);
+	if (result != 0) {
+		topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+		return (-1);
+	}
+
+	/* Open a connection to the LDOM PRI */
+	bzero(&pi, sizeof (pi_enum_t));
+	result = pi_ldompri_open(mod, &pi);
+	if (result != 0) {
+		pi_walker_fini(mod);
+		topo_mod_dprintf(mod, "could not open LDOM PRI\n");
+		topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+		return (-1);
+	}
+	pi.mod = mod;
+
+	/*
+	 * Find the top of the components graph in the PRI using the machine
+	 * description library.
+	 */
+	num_components = pi_find_mdenodes(mod, pi.mdp, MDE_INVAL_ELEM_COOKIE,
+	    MD_STR_COMPONENTS, MD_STR_FWD, &components, &csize);
+	if (num_components < 0 || components == NULL) {
+		/* No nodes were found */
+		pi_walker_fini(mod);
+		topo_mod_dprintf(mod, "could not find components in PRI\n");
+		topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
+		return (-1);
+	}
+
+	/*
+	 * There should be a single components node.  But scan all of the
+	 * results just in case a future machine has multiple hierarchies
+	 * for some unknown reason.
+	 *
+	 * We continue to walk components nodes until they are all exhausted
+	 * and do not stop if a node cannot be enumerated.  Instead, we
+	 * enumerate what we can and return a partial-enumeration error if
+	 * there is a problem.
+	 */
+	topo_mod_dprintf(mod, "enumerating %d components hierarchies\n",
+	    num_components);
+
+	component_cookie = md_find_name(pi.mdp, MD_STR_COMPONENT);
+	arc_cookie	 = md_find_name(pi.mdp, MD_STR_FWD);
+	result = 0;
+	for (idx = 0; idx < num_components; idx++) {
+		int	skip;
+
+		/*
+		 * We have found a component hierarchy to process.  First,
+		 * make sure we are not supposed to skip the graph.
+		 */
+		skip = pi_skip_node(mod, pi.mdp, components[idx]);
+		if (skip == 0) {
+			/*
+			 * We have found a components node.  Find the top-
+			 * level nodes and create a topology tree from them.
+			 */
+			result = pi_enum_components(&pi, t_parent, name,
+			    components[idx], component_cookie, arc_cookie);
+		}
+	}
+	topo_mod_free(mod, components, csize);
+
+	/* Close our connection to the PRI */
+	pi_ldompri_close(mod, &pi);
+
+	/* Clean up after the walker */
+	pi_walker_fini(mod);
+
+	/* Complete enumeration */
+	topo_mod_dprintf(mod, "enumeration complete in %lld ms.\n",
+	    ((gethrtime() - starttime)/MICROSEC));
+
+	/* All done */
+	return (result);
+}
+
+
+/*
+ * This routined is called once for each mde node of type 'components'.  It
+ * initiates enumeration of the graph starting with with this node.
+ */
+static int
+pi_enum_components(pi_enum_t *pip, tnode_t *t_parent, const char *hc_name,
+    mde_cookie_t mde_node, mde_str_cookie_t component_cookie,
+    mde_str_cookie_t arc_cookie)
+{
+	int		result;
+
+	int		num_arcs;
+	mde_cookie_t	*arcp;
+	size_t		arcsize;
+	int		arcidx;
+
+	topo_mod_t	*mod = pip->mod;
+	md_t		*mdp = pip->mdp;
+
+	if (t_parent == NULL) {
+		topo_mod_dprintf(mod,
+		    "walker failed to create node range with a NULL parent\n");
+		topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
+		return (-1);
+	}
+
+	/* Determine how many children the given node has */
+	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, NULL, 0);
+	if (num_arcs == 0) {
+		/*
+		 * This components node has no children and is not a topo
+		 * node itself, so set partial enumeration and return.
+		 */
+		topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+		return (0);
+	}
+	topo_mod_dprintf(mod, "node_0x%llx has %d children\n",
+	    (uint64_t)mde_node, num_arcs);
+
+	/* Get the indexes for all the child nodes and put them in an array */
+	arcsize = sizeof (mde_cookie_t) * num_arcs;
+	arcp = topo_mod_zalloc(mod, arcsize);
+	if (arcp == NULL) {
+		topo_mod_dprintf(mod, "out of memory\n");
+		topo_mod_seterrno(mod, EMOD_NOMEM);
+		return (-1);
+	}
+	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, arcp,
+	    arcsize);
+
+	result = 0;
+	for (arcidx = 0; arcidx < num_arcs; arcidx++) {
+		/*
+		 * Initiate walking the PRI graph starting with the current
+		 * child of the components node.
+		 */
+		result = pi_walker(pip, t_parent, hc_name,
+		    arcp[arcidx], component_cookie, arc_cookie);
+		if (result != 0) {
+			topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
+		}
+	}
+	topo_mod_free(mod, arcp, arcsize);
+
+	/*
+	 * We have now walked the entire PRI graph.  Execute any deferred
+	 * enumeration routines that need all the nodes to be available.
+	 */
+	result = pi_defer_exec(mod, mdp);
+
+	return (result);
+}
--- a/usr/src/pkgdefs/SUNWfmd/prototype_sparc	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_sparc	Mon Jul 28 15:46:04 2008 -0700
@@ -145,6 +145,7 @@
 f none usr/platform/sun4v/lib/fm/topo/plugins/platform-mem.so 555 root bin
 f none usr/platform/sun4v/lib/fm/topo/plugins/motherboard.so 555 root bin
 f none usr/platform/sun4v/lib/fm/topo/plugins/niu.so 555 root bin
+f none usr/platform/sun4v/lib/fm/topo/plugins/sun4vpi.so 555 root bin
 f none usr/platform/sun4v/lib/fm/topo/plugins/xaui.so 555 root bin
 f none usr/platform/sun4v/lib/fm/topo/plugins/zambezi.so 555 root bin
 d none usr/platform/SUNW,SPARC-Enterprise 755 root sys
--- a/usr/src/uts/common/sys/mdesc.h	Mon Jul 28 13:40:57 2008 -0700
+++ b/usr/src/uts/common/sys/mdesc.h	Mon Jul 28 15:46:04 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -114,6 +114,33 @@
 
 
 /*
+ * Walk callback function return codes
+ */
+#define	MDE_WALK_ERROR	-1	/* Terminate walk with error */
+#define	MDE_WALK_NEXT	0	/* Continue to next node */
+#define	MDE_WALK_DONE	1	/* Terminate walk with success */
+
+/*
+ * The function prototype for a walker callback function.
+ * The machine description session, parent node, current node,
+ * and private data are given to the callback.
+ *
+ * The parent node is given to the callback to provide context
+ * on how the walker arrived at this location.  While the node
+ * may have many parents, it will be visited only once, this
+ * provides context on how the walker arrived at the node.
+ *
+ * Input		Description
+ * -------------------	----------------------------------------
+ * md_t *		Pointer to md session
+ * mde_cookie_t		Index of parent node to provide context
+ * mde_cookie_t		The current node in the walk
+ * void *		Private data for the walking function
+ */
+typedef int md_walk_fn_t(md_t *, mde_cookie_t, mde_cookie_t, void *);
+
+
+/*
  * External Interface
  */
 
@@ -139,6 +166,13 @@
 				mde_str_cookie_t,
 				mde_cookie_t *);
 
+extern int		md_walk_dag(md_t *,
+				mde_cookie_t,
+				mde_str_cookie_t,
+				mde_str_cookie_t,
+				md_walk_fn_t,
+				void *);
+
 extern int		md_get_prop_val(md_t *,
 				mde_cookie_t,
 				char *,
@@ -155,6 +189,13 @@
 				uint8_t **,
 				int *);
 
+extern int		md_get_prop_arcs(md_t *,
+				mde_cookie_t,
+				char *,
+				mde_cookie_t *,
+				size_t);
+
+
 extern md_diff_cookie_t	md_diff_init(md_t *,
 				mde_cookie_t,
 				md_t *,