changeset 5068:06d88145c7f7

6492246 x64 cpu/mem topology/diagnosis should include FRU labels 6552234 Add propset/propmethod/propmap support to topology XML schema and libtopo parsing engine 6562046 libtopo dcmds cause mdb crash 6577125 fmtopo coredumps in print_fmri_props 6577127 wrong topo_method_invoke return code when method versions mismatch 6578581 using fmsim in root account. The fmsim can not be started. 6601280 add interfaces to libipmi to simplify access to fru inventory
author robj
date Mon, 17 Sep 2007 12:24:38 -0700
parents d64dc195fe92
children a114332ed71c
files usr/src/cmd/fm/fmd/common/fmd_api.c usr/src/cmd/fm/fmtopo/common/fmtopo.c usr/src/cmd/mdb/common/modules/libtopo/libtopo.c usr/src/lib/fm/topo/libtopo/common/libtopo.h usr/src/lib/fm/topo/libtopo/common/mapfile-vers usr/src/lib/fm/topo/libtopo/common/topo_error.h usr/src/lib/fm/topo/libtopo/common/topo_file.c usr/src/lib/fm/topo/libtopo/common/topo_file.h usr/src/lib/fm/topo/libtopo/common/topo_method.c usr/src/lib/fm/topo/libtopo/common/topo_mod.c usr/src/lib/fm/topo/libtopo/common/topo_node.c usr/src/lib/fm/topo/libtopo/common/topo_parse.h usr/src/lib/fm/topo/libtopo/common/topo_prop.c usr/src/lib/fm/topo/libtopo/common/topo_tree.c usr/src/lib/fm/topo/libtopo/common/topo_xml.c usr/src/lib/fm/topo/maps/common/topology.dtd.1 usr/src/lib/fm/topo/maps/i86pc/Makefile usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml usr/src/lib/fm/topo/modules/i86pc/chip/Makefile usr/src/lib/fm/topo/modules/i86pc/chip/chip.c usr/src/lib/fm/topo/modules/i86pc/chip/chip.h usr/src/lib/fm/topo/modules/i86pc/chip/chip_label.c usr/src/lib/libipmi/Makefile.com usr/src/lib/libipmi/common/ipmi_fru.c usr/src/lib/libipmi/common/libipmi.h usr/src/lib/libipmi/common/mapfile-vers usr/src/pkgdefs/SUNWfmd/prototype_i386
diffstat 28 files changed, 1816 insertions(+), 232 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fm/fmd/common/fmd_api.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/cmd/fm/fmd/common/fmd_api.c	Mon Sep 17 12:24:38 2007 -0700
@@ -1697,6 +1697,8 @@
 	 * Try to find the location label for this resource
 	 */
 	(void) topo_fmri_label(thp, rsrc, &loc, &err);
+	if (loc == NULL)
+		(void) topo_fmri_label(thp, fru, &loc, &err);
 
 	nvl = fmd_protocol_fault(class, certainty, asru, fru, rsrc, loc);
 
--- a/usr/src/cmd/fm/fmtopo/common/fmtopo.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/cmd/fm/fmtopo/common/fmtopo.c	Mon Sep 17 12:24:38 2007 -0700
@@ -1036,7 +1036,7 @@
 		nvlist_free(nvl);
 	}
 
-	if (pcnt > 0)
+	if (pargs && pcnt > 0)
 		print_fmri_props(thp, nvl);
 }
 
--- a/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c	Mon Sep 17 12:24:38 2007 -0700
@@ -111,7 +111,8 @@
 		mdb_printf("%<u>%-12s %-36s %-30s%</u>\n", "FIELD", "VALUE",
 		    "DESCR");
 	}
-	mdb_printf("%-12s 0x%-34p %-30s\n", "th_lock", th.th_lock,
+	mdb_printf("%-12s 0x%-34p %-30s\n", "th_lock",
+	    addr + offsetof(topo_hdl_t, th_lock),
 	    "Mutex lock protecting handle");
 	mdb_printf("%-12s %-36s %-30s\n", "th_uuid", uuid,
 	    "UUID of the topology snapshot");
@@ -180,9 +181,11 @@
 		mdb_printf("%<u>%-12s %-36s %-30s%</u>\n",
 		    "FIELD", "VALUE", "DESCR");
 	}
-	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_lock", tm.tm_lock,
+	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_lock",
+	    addr + offsetof(topo_mod_t, tm_lock),
 	    "Lock for tm_cv/owner/flags/refs");
-	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv", tm.tm_cv,
+	mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv",
+	    addr + offsetof(topo_mod_t, tm_cv),
 	    "Module condition variable");
 	mdb_printf("%-12s %-36s %-30s\n", "tm_busy", tm.tm_busy,
 	    "Busy indicator");
--- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h	Mon Sep 17 12:24:38 2007 -0700
@@ -97,6 +97,7 @@
  */
 extern char *topo_node_name(tnode_t *);
 extern topo_instance_t topo_node_instance(tnode_t *);
+extern tnode_t *topo_node_parent(tnode_t *);
 extern void *topo_node_private(tnode_t *);
 extern int topo_node_asru(tnode_t *, nvlist_t **, nvlist_t *, int *);
 extern int topo_node_fru(tnode_t *, nvlist_t **, nvlist_t *, int *);
--- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers	Mon Sep 17 12:24:38 2007 -0700
@@ -101,6 +101,7 @@
 	topo_node_label;
 	topo_node_label_set;
 	topo_node_name;
+	topo_node_parent;
 	topo_node_range_create;
 	topo_node_range_destroy;
 	topo_node_resource;
--- a/usr/src/lib/fm/topo/libtopo/common/topo_error.h	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_error.h	Mon Sep 17 12:24:38 2007 -0700
@@ -90,6 +90,7 @@
     ETOPO_PRSR_NOMETH,	/* range missing enum-method */
     ETOPO_PRSR_NVPROP,	/* properties as nvlist missing crucial field */
     ETOPO_PRSR_OOR,	/* node instance out of declared range */
+    ETOPO_PRSR_REGMETH,	/* failed to register property method */
     ETOPO_WALK_EMPTY,	/* empty topology */
     ETOPO_WALK_NOTFOUND, /* scheme based topology not found */
     ETOPO_END		/* end of custom errno list (to ease auto-merge) */
--- a/usr/src/lib/fm/topo/libtopo/common/topo_file.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_file.c	Mon Sep 17 12:24:38 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,7 +63,7 @@
 
 int
 topo_file_load(topo_mod_t *mod, tnode_t *node, const char *name,
-    const char *scheme)
+    const char *scheme, int pmap)
 {
 	topo_file_t *tfp;
 	char fp[MAXNAMELEN];
@@ -94,6 +94,9 @@
 		return (topo_mod_seterrno(mod, ETOPO_MOD_XRD));
 	}
 
+	if (pmap)
+		tfp->tf_tmap->tf_flags |= TF_PROPMAP;
+
 	if (topo_xml_enum(mod, tfp->tf_tmap, node) < 0) {
 		topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
 		    "Failed to enumerate topology: %s\n",
--- a/usr/src/lib/fm/topo/libtopo/common/topo_file.h	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_file.h	Mon Sep 17 12:24:38 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -41,7 +41,8 @@
 	topo_mod_t *tf_mod;		/* scheme-specific builtin mod */
 } topo_file_t;
 
-extern int topo_file_load(topo_mod_t *, tnode_t *, const char *, const char *);
+extern int topo_file_load(topo_mod_t *, tnode_t *, const char *, const char *,
+    int);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_method.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_method.c	Mon Sep 17 12:24:38 2007 -0700
@@ -222,10 +222,10 @@
 			continue;
 
 		if (version < mp->tim_version) {
-			*err = ETOPO_METHOD_VERNEW;
+			*err = ETOPO_METHOD_VEROLD;
 			return (-1);
 		} else if (version > mp->tim_version) {
-			*err = ETOPO_METHOD_VEROLD;
+			*err = ETOPO_METHOD_VERNEW;
 			return (-1);
 		}
 
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c	Mon Sep 17 12:24:38 2007 -0700
@@ -278,7 +278,7 @@
 topo_mod_enummap(topo_mod_t *mod, tnode_t *node, const char *name,
     const char *scheme)
 {
-	return (topo_file_load(mod, node, (char *)name, (char *)scheme));
+	return (topo_file_load(mod, node, (char *)name, (char *)scheme, 0));
 }
 
 static nvlist_t *
--- a/usr/src/lib/fm/topo/libtopo/common/topo_node.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_node.c	Mon Sep 17 12:24:38 2007 -0700
@@ -242,6 +242,12 @@
 	return (node->tn_instance);
 }
 
+tnode_t *
+topo_node_parent(tnode_t *node)
+{
+	return (node->tn_parent);
+}
+
 void
 topo_node_setspecific(tnode_t *node, void *data)
 {
--- a/usr/src/lib/fm/topo/libtopo/common/topo_parse.h	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_parse.h	Mon Sep 17 12:24:38 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -110,8 +110,9 @@
 	tf_rdata_t *tf_rd;	/* data for forming topology nodes */
 } tf_info_t;
 
-#define	TF_LIVE	0x1	/* Parsing should create topology nodes */
-#define	TF_BIN	0x2	/* Parsing should create intermediate binary */
+#define	TF_LIVE		0x1	/* Parsing should create topology nodes */
+#define	TF_BIN		0x2	/* Parsing should create intermediate binary */
+#define	TF_PROPMAP	0x4	/* XML file loaded from a propmap element */
 
 /*
  * We store properties using nvlists as an intermediate form.  The
@@ -131,6 +132,7 @@
 /*
  * Valid .xml element and attribute names
  */
+#define	Argval "argval"
 #define	Children "children"
 #define	Dependents "dependents"
 #define	FMRI "fmri"
@@ -141,8 +143,11 @@
 #define	Int64 "int64"
 #define	Name "name"
 #define	Path "path"
+#define	Propname "propname"
+#define	Proptype "proptype"
 #define	Range "range"
 #define	Scheme "scheme"
+#define	Set "set"
 #define	Siblings "siblings"
 #define	Static "static"
 #define	String "string"
@@ -157,8 +162,11 @@
 #define	Max "max"
 
 #define	Enum_meth "enum-method"
+#define	Prop_meth "propmethod"
 #define	Propgrp "propgroup"
 #define	Propval "propval"
+#define	Propset "propset"
+#define	Propmap "propmap"
 
 #define	Node "node"
 #define	Hc "hc"
--- a/usr/src/lib/fm/topo/libtopo/common/topo_prop.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.c	Mon Sep 17 12:24:38 2007 -0700
@@ -846,11 +846,9 @@
 		return (register_methoderror(node, pm, err, 0, *err));
 	}
 
-	if (pv->tp_method != NULL) {
-		topo_node_unlock(node);
+	if (pv->tp_method != NULL)
 		return (register_methoderror(node, pm, err, 1,
 		    ETOPO_METHOD_DEFD));
-	}
 
 	pv->tp_val = NULL;
 	pv->tp_method = pm;
@@ -870,7 +868,9 @@
 
 	if ((mp = topo_method_lookup(node, mname)) == NULL)
 		return (register_methoderror(node, NULL, err, 1,
-		    ETOPO_METHOD_NOTSUP));
+		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
+
+	topo_node_lock(node);
 
 	return (prop_method_register(node, pgname, pname, ptype, mname,
 	    mp->tim_version, args, err)); /* err set and node unlocked */
@@ -887,7 +887,9 @@
 
 	if ((mp = topo_method_lookup(node, mname)) == NULL)
 		return (register_methoderror(node, NULL, err, 1,
-		    ETOPO_METHOD_NOTSUP));
+		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
+
+	topo_node_lock(node);
 
 	if (version < mp->tim_version)
 		return (register_methoderror(node, NULL, err, 1,
@@ -1236,13 +1238,11 @@
 
 	topo_node_lock(node);
 	if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) {
-		topo_node_unlock(node);
 		(void) get_properror(node, err, *err);
 		return (-1);
 	}
 
 	if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) {
-		topo_node_unlock(node);
 		(void) get_properror(node, err, ETOPO_NOMEM);
 		return (-1);
 	}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_tree.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_tree.c	Mon Sep 17 12:24:38 2007 -0700
@@ -174,19 +174,19 @@
 	else
 		pp++;
 	if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root,
-	    pp, tp->tt_scheme) < 0) {
+	    pp, tp->tt_scheme, 0) < 0) {
 		if ((pp = strchr(thp->th_platform, ',')) == NULL)
 			pp = thp->th_platform;
 		else
 			pp++;
 
 		if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root,
-		    pp, tp->tt_scheme) < 0) {
+		    pp, tp->tt_scheme, 0) < 0) {
 			if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root,
-			    thp->th_machine, tp->tt_scheme) < 0) {
+			    thp->th_machine, tp->tt_scheme, 0) < 0) {
 
 				if ((rv = topo_file_load(tp->tt_root->tn_enum,
-				    tp->tt_root, NULL, tp->tt_scheme)) < 0) {
+				    tp->tt_root, NULL, tp->tt_scheme, 0)) < 0) {
 					topo_dprintf(thp, TOPO_DBG_ERR, "no "
 					    "topology map found for the %s "
 					    "FMRI set\n", tp->tt_scheme);
--- a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c	Mon Sep 17 12:24:38 2007 -0700
@@ -39,6 +39,7 @@
 #include <unistd.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <topo_file.h>
 #include <topo_mod.h>
 #include <topo_subr.h>
 #include <topo_alloc.h>
@@ -48,6 +49,9 @@
 static tf_rdata_t *topo_xml_walk(topo_mod_t *,
     tf_info_t *, xmlNodePtr, tnode_t *);
 
+static int decorate_nodes(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn,
+    tnode_t *ptn, char *name, tf_pad_t **rpad);
+
 int
 xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname,
     topo_stability_t *rs)
@@ -126,12 +130,13 @@
 }
 
 static topo_type_t
-xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn)
+xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn, xmlChar *attr)
 {
 	topo_type_t rv;
 	xmlChar *str;
-	if ((str = xmlGetProp(xn, (xmlChar *)Type)) == NULL) {
-		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "Property missing type");
+	if ((str = xmlGetProp(xn, (xmlChar *)attr)) == NULL) {
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s attribute missing",
+		    attr);
 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
 		return (TOPO_TYPE_INVALID);
 	}
@@ -150,7 +155,7 @@
 	} else {
 		xmlFree(str);
 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-		    "Unrecognized type attribute.\n");
+		    "Unrecognized type attribute value.\n");
 		(void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
 		return (TOPO_TYPE_INVALID);
 	}
@@ -159,14 +164,68 @@
 }
 
 static int
+xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
+const char *name)
+{
+	int rv;
+	uint64_t ui;
+	nvlist_t *fmri;
+	xmlChar *str;
+
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xlate_common\n");
+	switch (ptype) {
+	case TOPO_TYPE_INT32:
+		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
+			return (-1);
+		rv = nvlist_add_int32(nvl, name, (int32_t)ui);
+		break;
+	case TOPO_TYPE_UINT32:
+		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
+			return (-1);
+		rv = nvlist_add_uint32(nvl, name, (uint32_t)ui);
+		break;
+	case TOPO_TYPE_INT64:
+		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
+			return (-1);
+		rv = nvlist_add_int64(nvl, name, (int64_t)ui);
+		break;
+	case TOPO_TYPE_UINT64:
+		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
+			return (-1);
+		rv = nvlist_add_uint64(nvl, name, ui);
+		break;
+	case TOPO_TYPE_FMRI:
+		if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0)
+			return (-1);
+		rv = nvlist_add_nvlist(nvl, name, fmri);
+		nvlist_free(fmri);
+		break;
+	case TOPO_TYPE_STRING:
+		if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL)
+			return (-1);
+		rv = nvlist_add_string(nvl, name, (char *)str);
+		xmlFree(str);
+		break;
+	default:
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+		    "Unrecognized type attribute.\n");
+		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE));
+	}
+	if (rv != 0) {
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+		    "Nvlist construction failed.\n");
+		return (topo_mod_seterrno(mp, ETOPO_NOMEM));
+	} else
+		return (0);
+}
+
+static int
 xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl)
 {
 	topo_type_t ptype;
 	xmlChar *str;
-	nvlist_t *fmri;
-	uint64_t ui;
-	int e;
 
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlprop_xlate\n");
 	if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) {
 		if (xmlStrcmp(str, (xmlChar *)False) == 0)
 			(void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
@@ -179,55 +238,14 @@
 		(void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE);
 	}
 
-	if ((ptype = xmlattr_to_type(mp, xn)) == TOPO_TYPE_INVALID)
-		return (-1);
-	e = nvlist_add_int32(nvl, INV_PVALTYPE, ptype);
-	if (e != 0)
+	if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type))
+	    == TOPO_TYPE_INVALID)
 		return (-1);
-	switch (ptype) {
-	case TOPO_TYPE_INT32:
-		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
-			return (-1);
-		e = nvlist_add_int32(nvl, INV_PVAL, (int32_t)ui);
-		break;
-	case TOPO_TYPE_UINT32:
-		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
-			return (-1);
-		e = nvlist_add_uint32(nvl, INV_PVAL, (uint32_t)ui);
-		break;
-	case TOPO_TYPE_INT64:
-		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
-			return (-1);
-		e = nvlist_add_int64(nvl, INV_PVAL, (int64_t)ui);
-		break;
-	case TOPO_TYPE_UINT64:
-		if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
-			return (-1);
-		e = nvlist_add_uint64(nvl, INV_PVAL, ui);
-		break;
-	case TOPO_TYPE_FMRI:
-		if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0)
-			return (-1);
-		e = nvlist_add_nvlist(nvl, INV_PVAL, fmri);
-		nvlist_free(fmri);
-		break;
-	case TOPO_TYPE_STRING:
-		if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL)
-			return (-1);
-		e = nvlist_add_string(nvl, INV_PVAL, (char *)str);
-		xmlFree(str);
-		break;
-	default:
-		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-		    "Unrecognized type attribute.\n");
-		return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE));
-	}
-	if (e != 0) {
-		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-		    "Nvlist construction failed.\n");
-		return (topo_mod_seterrno(mp, ETOPO_NOMEM));
-	}
-	return (0);
+
+	if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0)
+		return (-1);
+
+	return (xlate_common(mp, xn, ptype, nvl, INV_PVAL));
 }
 
 static int
@@ -238,7 +256,7 @@
 	xmlChar *grptype;
 	int sibs = 0;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent create\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent_create\n");
 	if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) {
 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
 		    "Dependents missing grouping attribute");
@@ -284,7 +302,7 @@
 {
 	xmlNodePtr cn;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents create\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents_create\n");
 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
 		if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) {
 			if (dependent_create(mp, xinfo, pad, cn, ptn) < 0)
@@ -307,7 +325,8 @@
 	char *str;
 	int err, e;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop create\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop_create(gnm = %s, "
+	    "pnm = %s)\n", gnm, pnm);
 	switch (ptype) {
 	case TOPO_TYPE_INT32:
 		e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32);
@@ -332,7 +351,7 @@
 	}
 	if (e != 0) {
 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-		    "prop value lookup failed.\n");
+		    "prop_create: prop value lookup failed.\n");
 		return (topo_mod_seterrno(mp, e));
 	}
 	switch (ptype) {
@@ -381,20 +400,20 @@
 	int pn;
 	int e;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props create\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props_create(gnm = %s)\n", gnm);
 	for (pn = 0; pn < nprops; pn++) {
 		e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm);
 		if (e != 0) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
 			    "props create lookup (%s) failure: %s",
-			    INV_PNAME, topo_strerror(e));
+			    INV_PNAME, strerror(e));
 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
 		}
 		e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim);
 		if (e != 0) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
 			    "props create lookup (%s) failure: %s",
-			    INV_IMMUTE, topo_strerror(e));
+			    INV_IMMUTE, strerror(e));
 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
 		}
 		flag = (pim == B_TRUE) ?
@@ -404,7 +423,7 @@
 		if (e != 0) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
 			    "props create lookup (%s) failure: %s",
-			    INV_PVALTYPE, topo_strerror(e));
+			    INV_PVALTYPE, strerror(e));
 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
 		}
 		ptype = (topo_type_t)i32;
@@ -426,14 +445,14 @@
 	int pg;
 	int e;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups create\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_create\n");
 	for (pg = 0; pg < pad->tpad_pgcnt; pg++) {
 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
 		    INV_PGRP_NAME, &gnm);
 		if (e != 0) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-			    "pad lookup (%s) failed.\n",
-			    INV_PGRP_NAME);
+			    "pad lookup (%s) failed (%s).\n",
+			    INV_PGRP_NAME, strerror(errno));
 			return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
 		}
 		e = nvlist_lookup_string(pad->tpad_pgs[pg],
@@ -484,16 +503,22 @@
 		}
 		e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
 		    INV_PGRP_NPROP, &rnprops);
-		e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg],
-		    INV_PGRP_ALLPROPS, &props, &nprops);
-		if (rnprops != nprops) {
-			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-			    "recorded number of props %d does not "
-			    "match number of props recorded %d.\n",
-			    rnprops, nprops);
+		/*
+		 * The number of properties could be zero if the property
+		 * group only contains propmethod declarations
+		 */
+		if (rnprops > 0) {
+			e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg],
+			    INV_PGRP_ALLPROPS, &props, &nprops);
+			if (rnprops != nprops) {
+				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+				    "recorded number of props %d does not "
+				    "match number of props recorded %d.\n",
+				    rnprops, nprops);
+			}
+			if (props_create(mp, ptn, gnm, props, nprops) < 0)
+				return (-1);
 		}
-		if (props_create(mp, ptn, gnm, props, nprops) < 0)
-			return (-1);
 	}
 	return (0);
 }
@@ -504,7 +529,7 @@
 	nvlist_t *pnvl = NULL;
 	xmlChar *pname;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval record\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval_record\n");
 	if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
 		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
 		    "propval lacks a name\n");
@@ -530,8 +555,176 @@
 	return (pnvl);
 }
 
+
+struct propmeth_data {
+	const char *pg_name;
+	const char *prop_name;
+	topo_type_t prop_type;
+	const char *meth_name;
+	topo_version_t meth_ver;
+	nvlist_t *arg_nvl;
+};
+
 static int
-pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tf_pad_t *rpad, int pi)
+register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth)
+{
+	int err;
+
+	if (topo_prop_method_version_register(ptn, meth->pg_name,
+	    meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver,
+	    meth->arg_nvl, &err) != 0) {
+
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register "
+		    "propmethod %s for property %s on node %s=%d (%s)\n",
+		    meth->meth_name, meth->prop_name,
+		    topo_node_name(ptn), topo_node_instance(ptn),
+		    topo_strerror(err));
+		return (-1);
+	}
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+	    "registered method %s on %s=%d\n",
+	    meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn));
+
+	return (0);
+}
+
+static int
+pmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn,
+    const char *rname, const char *ppgrp_name)
+{
+	nvlist_t *arg_nvl = NULL;
+	xmlNodePtr cn;
+	xmlChar *meth_name = NULL, *prop_name = NULL;
+	xmlChar *arg_name = NULL;
+	uint64_t meth_ver;
+	topo_type_t prop_type;
+	struct propmeth_data meth;
+	int ret = 0;
+	topo_type_t ptype;
+	tnode_t *tmp;
+
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pmeth_record\n");
+
+	/*
+	 * Get propmethod attribute values
+	 */
+	if ((meth_name = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+		    "propmethod element lacks a name attribute\n");
+		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
+	}
+	if (xmlattr_to_int(mp, xn, Version, &meth_ver) < 0) {
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+		    "propmethod element lacks version attribute\n");
+		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
+		goto pmr_done;
+	}
+	if ((prop_name = xmlGetProp(xn, (xmlChar *)Propname)) == NULL) {
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+		    "propmethod element lacks propname attribute\n");
+		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
+		goto pmr_done;
+	}
+	if ((prop_type = xmlattr_to_type(mp, xn, (xmlChar *)Proptype))
+	    == TOPO_TYPE_INVALID) {
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+		    "error decoding proptype attribute\n");
+		ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
+		goto pmr_done;
+	}
+
+	/*
+	 * Allocate method argument nvlist
+	 */
+	if (topo_mod_nvalloc(mp, &arg_nvl, NV_UNIQUE_NAME) < 0) {
+		ret = topo_mod_seterrno(mp, ETOPO_NOMEM);
+		goto pmr_done;
+	}
+
+	/*
+	 * Iterate through the argval nodes and build the argval nvlist
+	 */
+	for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
+		if (xmlStrcmp(cn->name, (xmlChar *)Argval) == 0) {
+			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+			    "found argval element\n");
+			if ((arg_name = xmlGetProp(cn, (xmlChar *)Name))
+			    == NULL) {
+				topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+				    "argval element lacks a name attribute\n");
+				ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
+				goto pmr_done;
+			}
+			if ((ptype = xmlattr_to_type(mp, cn, (xmlChar *)Type))
+			    == TOPO_TYPE_INVALID) {
+				ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
+				xmlFree(arg_name);
+				break;
+			}
+			if (xlate_common(mp, cn, ptype, arg_nvl,
+			    (const char *)arg_name) != 0) {
+				ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
+				xmlFree(arg_name);
+				break;
+			}
+		}
+		if (arg_name) {
+			xmlFree(arg_name);
+			arg_name = NULL;
+		}
+	}
+
+	if (ret != 0)
+		goto pmr_done;
+
+	/*
+	 * Register the prop method for all of the nodes in our range
+	 */
+	meth.pg_name = (const char *)pg_name;
+	meth.prop_name = (const char *)prop_name;
+	meth.prop_type = prop_type;
+	meth.meth_name = (const char *)meth_name;
+	meth.meth_ver = meth_ver;
+	meth.arg_nvl = arg_nvl;
+
+	/*
+	 * If the propgroup element is under a range element, we'll apply
+	 * the method to all of the topo nodes at this level with the same
+	 * range name.
+	 *
+	 * Otherwise, if the propgroup element is under a node element
+	 * then we'll simply register the method for this node.
+	 */
+	if (strcmp(ppgrp_name, Range) == 0) {
+		for (tmp = tn; tmp != NULL; tmp = topo_child_next(NULL, tmp)) {
+			if (strcmp(rname, topo_node_name(tmp)) == 0)
+				if (register_method(mp, tmp, &meth) != 0) {
+					ret = topo_mod_seterrno(mp,
+					    ETOPO_PRSR_REGMETH);
+					goto pmr_done;
+				}
+		}
+	} else {
+		if (register_method(mp, tn, &meth) != 0) {
+			ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH);
+			goto pmr_done;
+		}
+	}
+
+pmr_done:
+	if (meth_name)
+		xmlFree(meth_name);
+	if (prop_name)
+		xmlFree(prop_name);
+	if (arg_nvl)
+		nvlist_free(arg_nvl);
+	return (ret);
+}
+
+
+static int
+pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
+    tf_pad_t *rpad, int pi, const char *ppgrp_name)
 {
 	topo_stability_t nmstab, dstab;
 	uint64_t ver;
@@ -543,7 +736,7 @@
 	int ai = 0;
 	int e;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup record\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup_record\n");
 	if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) {
 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
 		    "propgroup lacks a name\n");
@@ -573,7 +766,9 @@
 
 	if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) {
 		xmlFree(name);
-		return (-1);
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+		    "failed to allocate propgroup nvlist\n");
+		return (topo_mod_seterrno(mp, ETOPO_NOMEM));
 	}
 
 	e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name);
@@ -581,12 +776,17 @@
 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab);
 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver);
 	e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt);
-	if (e != 0 ||
-	    (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *))) == NULL) {
-		xmlFree(name);
-		nvlist_free(pgnvl);
-		return (-1);
-	}
+	if (pcnt > 0)
+		if (e != 0 ||
+		    (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *)))
+		    == NULL) {
+			xmlFree(name);
+			nvlist_free(pgnvl);
+			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+			    "failed to allocate nvlist array for properties"
+			    "(e=%d)\n", e);
+			return (topo_mod_seterrno(mp, ETOPO_NOMEM));
+		}
 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
 		if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) {
 			if (ai < pcnt) {
@@ -594,33 +794,43 @@
 					break;
 			}
 			ai++;
+		} else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) {
+			if (pmeth_record(mp, (const char *)name, cn, tn, rname,
+			    ppgrp_name) < 0)
+				break;
 		}
 	}
 	xmlFree(name);
-	e |= (ai != pcnt);
-	e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl, pcnt);
-	for (ai = 0; ai < pcnt; ai++)
-		if (apl[ai] != NULL)
-			nvlist_free(apl[ai]);
-	topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *));
-	if (e != 0) {
-		nvlist_free(pgnvl);
-		return (-1);
+	if (pcnt > 0) {
+		e |= (ai != pcnt);
+		e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl,
+		    pcnt);
+		for (ai = 0; ai < pcnt; ai++)
+			if (apl[ai] != NULL)
+				nvlist_free(apl[ai]);
+		topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *));
+		if (e != 0) {
+			nvlist_free(pgnvl);
+			return (-1);
+		}
 	}
 	rpad->tpad_pgs[pi] = pgnvl;
 	return (0);
 }
 
 static int
-pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tf_pad_t *rpad)
+pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
+    tf_pad_t *rpad, const char *ppgrp)
 {
 	xmlNodePtr cn;
 	int pi = 0;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups record\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_record: pxn->name=%s\n",
+	    pxn->name);
 	for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
 		if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) {
-			if (pgroup_record(mp, cn, rpad, pi++) < 0)
+			if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp)
+			    < 0)
 				return (-1);
 		}
 	}
@@ -628,27 +838,124 @@
 }
 
 /*
+ * psn:	pointer to a "propset" XML node
+ * key: string to search the propset for
+ *
+ * returns: 1, if the propset contains key
+ *          0, otherwise
+ */
+static int
+propset_contains(topo_mod_t *mp, char *key, char *set)
+{
+	char *prod;
+	int rv = 0;
+
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "propset_contains(key = %s, "
+	    "set = %s)\n", key, set);
+
+	prod = strtok((char *)set, "|");
+	if (prod && (strncmp(key, prod, strlen(prod)) == 0))
+		return (1);
+
+	while ((prod = strtok(NULL, "|")))
+		if (strncmp(key, prod, strlen(prod)) == 0)
+			return (1);
+
+	return (rv);
+}
+
+
+/*
  * Process the property group and dependents xmlNode children of
  * parent xmlNode pxn.
  */
 static int
-pad_process(topo_mod_t *mp,
-    tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn, tf_pad_t **rpad)
+pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
+    tf_pad_t **rpad, const char *rname)
 {
-	xmlNodePtr cn;
+	xmlNodePtr cn, gcn, psn;
+	xmlNodePtr def_propset = NULL;
 	tf_pad_t *new = *rpad;
 	int pgcnt = 0;
 	int dcnt = 0;
+	int joined_propset = 0;
+	xmlChar *set;
+	char *key;
 
 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
-	    "pad process beneath %s\n", topo_node_name(ptn));
+	    "pad_process beneath %s\n", topo_node_name(ptn));
 	if (new == NULL) {
 		for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
+			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+			    "cn->name is %s \n", (char *)cn->name);
+			/*
+			 * We're iterating through the XML children looking for
+			 * three types of elements:
+			 *   1) dependents elements
+			 *   2) unconstrained pgroup elements
+			 *   3) pgroup elements constrained by propset elements
+			 */
 			if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0)
 				dcnt++;
 			else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0)
 				pgcnt++;
+			else if (xmlStrcmp(cn->name, (xmlChar *)Propset) == 0) {
+				set = xmlGetProp(cn, (xmlChar *)Set);
+
+				if (mp->tm_hdl->th_product)
+					key = mp->tm_hdl->th_product;
+				else
+					key = mp->tm_hdl->th_platform;
+
+				/*
+				 * If it's the default propset then we'll store
+				 * a pointer to it so that if none of the other
+				 * propsets apply to our product we can fall
+				 * back to this one.
+				 */
+				if (strcmp((char *)set, "default") == 0)
+					def_propset = cn;
+				else if (propset_contains(mp, key,
+				    (char *)set)) {
+					psn = cn;
+					joined_propset = 1;
+					for (gcn = cn->xmlChildrenNode;
+					    gcn != NULL; gcn = gcn->next) {
+						if (xmlStrcmp(gcn->name,
+						    (xmlChar *)Propgrp) == 0)
+							pgcnt++;
+					}
+				}
+				xmlFree(set);
+			}
 		}
+		/*
+		 * If we haven't found a propset that contains our product AND
+		 * a default propset exists, then we'll process it.
+		 */
+		if (!joined_propset && def_propset) {
+			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+			    "Falling back to default propset\n");
+			joined_propset = 1;
+			psn = def_propset;
+			for (gcn = psn->xmlChildrenNode; gcn != NULL;
+			    gcn = gcn->next) {
+				if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp)
+				    == 0)
+					pgcnt++;
+			}
+		}
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+		    "pad_process: dcnt=%d, pgcnt=%d, joined_propset=%d\n",
+		    dcnt, pgcnt, joined_propset);
+		/*
+		 * Here we allocate an element in an intermediate data structure
+		 * which keeps track property groups and dependents of the range
+		 * currently being processed.
+		 *
+		 * This structure is referenced in pgroups_record() to create
+		 * the actual property groups in the topo tree
+		 */
 		if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL)
 			return (-1);
 		if (dcnt == 0 && pgcnt == 0) {
@@ -661,11 +968,26 @@
 			    topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *));
 			if (new->tpad_pgs == NULL) {
 				tf_pad_free(mp, new);
-				return (NULL);
+				return (-1);
 			}
-			if (pgroups_record(mp, pxn, new) < 0) {
-				tf_pad_free(mp, new);
-				return (NULL);
+
+			if (joined_propset) {
+				/*
+				 * If the property groups are contained within a
+				 * propset then they will be one level lower in
+				 * the XML tree.
+				 */
+				if (pgroups_record(mp, psn, ptn, rname, new,
+				    (const char *)pxn->name) < 0) {
+					tf_pad_free(mp, new);
+					return (-1);
+				}
+			} else {
+				if (pgroups_record(mp, pxn, ptn, rname, new,
+				    (const char *)pxn->name) < 0) {
+					tf_pad_free(mp, new);
+					return (-1);
+				}
 			}
 		}
 		*rpad = new;
@@ -678,6 +1000,7 @@
 	if (new->tpad_pgcnt > 0)
 		if (pgroups_create(mp, new, ptn) < 0)
 			return (-1);
+
 	return (0);
 }
 
@@ -693,7 +1016,7 @@
 	int s = 0;
 
 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
-	    "node process %s\n", rd->rd_name);
+	    "node_process %s\n", rd->rd_name);
 
 	if (xmlattr_to_int(mp, nn, Instance, &ui) < 0)
 		goto nodedone;
@@ -727,15 +1050,16 @@
 
 	if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) {
 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-		    "tf_idata_new failed.\n");
+		    "node_process: tf_idata_new failed.\n");
 		goto nodedone;
 	}
 	if (tf_idata_insert(&rd->rd_instances, newi) < 0) {
 		topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-		    "tf_idata_insert failed.\n");
+		    "node_process: tf_idata_insert failed.\n");
 		goto nodedone;
 	}
-	if (pad_process(mp, rd->rd_finfo, nn, ntn, &newi->ti_pad) < 0)
+	if (pad_process(mp, rd->rd_finfo, nn, ntn, &newi->ti_pad, rd->rd_name)
+	    < 0)
 		goto nodedone;
 	rv = 0;
 nodedone:
@@ -750,7 +1074,7 @@
 	tf_edata_t *einfo;
 	uint64_t ui;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum attributes process\n");
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n");
 	if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) {
 		(void) topo_mod_seterrno(mp, ETOPO_NOMEM);
 		return (NULL);
@@ -791,6 +1115,7 @@
 	topo_hdl_t *thp = mp->tm_hdl;
 	int e = -1;
 
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n");
 	/*
 	 * Check if the enumerator module is already loaded.
 	 * Module loading is single-threaded at this point so there's
@@ -802,7 +1127,7 @@
 		if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name,
 		    rd->rd_einfo->te_vers)) == NULL) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
-			    "mod_load of %s failed: %s.\n",
+			    "enum_run: mod_load of %s failed: %s.\n",
 			    rd->rd_einfo->te_name,
 			    topo_strerror(topo_mod_errno(mp)));
 			(void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
@@ -828,20 +1153,45 @@
 	return (e);
 }
 
+
+int
+decorate_nodes(topo_mod_t *mp,
+    tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn, char *name, tf_pad_t **rpad)
+{
+	tnode_t *ctn;
+
+	ctn = topo_child_first(ptn);
+	while (ctn != NULL) {
+		/* Only care about instances within the range */
+		if (strcmp(topo_node_name(ctn), name) != 0) {
+			ctn = topo_child_next(ptn, ctn);
+			continue;
+		}
+		if (pad_process(mp, xinfo, pxn, ctn, rpad, name) < 0)
+			return (-1);
+		if (decorate_nodes(mp, xinfo, pxn, ctn, name, rpad) < 0)
+			return (-1);
+		ctn = topo_child_next(ptn, ctn);
+	}
+	return (0);
+}
+
 int
 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
 {
 	/*
 	 * The range may have several children xmlNodes, that may
 	 * represent the enumeration method, property groups,
-	 * dependents or nodes.
+	 * dependents, nodes or services.
 	 */
-	xmlNodePtr cn;
+	xmlNodePtr cn, enum_node = NULL, pmap_node = NULL;
+	xmlChar *pmap_name;
 	tnode_t *ct;
 	int e, ccnt = 0;
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "process %s range beneath %s\n",
-	    rd->rd_name, topo_node_name(rd->rd_pn));
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n"
+	    "process %s range beneath %s\n", rd->rd_name,
+	    topo_node_name(rd->rd_pn));
 	e = topo_node_range_create(mp,
 	    rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max);
 	if (e != 0 && topo_mod_errno(mp) != ETOPO_NODE_DUP) {
@@ -850,12 +1200,23 @@
 		    topo_strerror(topo_mod_errno(mp)));
 		return (-1);
 	}
+
+	/*
+	 * Before we process any of the other child xmlNodes, we iterate through
+	 * the children and looking for either enum-method or propmap elements.
+	 */
 	for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next)
 		if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0)
-			break;
+			enum_node = cn;
+		else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0)
+			pmap_node = cn;
 
-	if (cn != NULL) {
-		if ((rd->rd_einfo = enum_attributes_process(mp, cn)) == NULL)
+	/*
+	 * If we found an enum-method element, process it first
+	 */
+	if (enum_node != NULL) {
+		if ((rd->rd_einfo = enum_attributes_process(mp, enum_node))
+		    == NULL)
 			return (-1);
 		if (enum_run(mp, rd) < 0) {
 			/*
@@ -866,6 +1227,31 @@
 		}
 	}
 
+	/*
+	 * Next, check if a propmap element was found and if so, load it in
+	 * and parse it.
+	 */
+	if (pmap_node != NULL) {
+		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap "
+		    "element\n");
+		if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name))
+		    == NULL) {
+			topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+			    "propmap element missing name attribute.\n");
+		} else {
+			if (topo_file_load(mp, rd->rd_pn,
+			    (const char *)pmap_name,
+			    rd->rd_finfo->tf_scheme, 1) < 0) {
+
+				topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+				    "topo_xml_range_process: topo_file_load"
+				    "failed: %s.\n",
+				    topo_strerror(topo_mod_errno(mp)));
+			}
+			xmlFree(pmap_name);
+		}
+	}
+
 	/* Now look for nodes, i.e., hard instances */
 	for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) {
 		if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0)
@@ -876,31 +1262,45 @@
 				return (topo_mod_seterrno(mp,
 				    EMOD_PARTIAL_ENUM));
 			}
+			ccnt++;
 	}
 
-	/* Property groups and Dependencies */
-	ct = topo_child_first(rd->rd_pn);
-	while (ct != NULL) {
-		/* Only care about instances within the range */
-		if (strcmp(topo_node_name(ct), rd->rd_name) != 0) {
+	/*
+	 * Finally, process the property groups and dependents
+	 *
+	 * If the TF_PROPMAP flag is set for the XML file we're currently
+	 * processing, then this XML file was loaded via propmap.  In that case
+	 * we call a special routine to recursively apply the propgroup settings
+	 * to all of nodes in this range
+	 */
+	if (rd->rd_finfo->tf_flags & TF_PROPMAP)
+		(void) decorate_nodes(mp, rd->rd_finfo, rn, rd->rd_pn,
+		    rd->rd_name, &rd->rd_pad);
+	else {
+		ct = topo_child_first(rd->rd_pn);
+		while (ct != NULL) {
+			/* Only care about instances within the range */
+			if (strcmp(topo_node_name(ct), rd->rd_name) != 0) {
+				ct = topo_child_next(rd->rd_pn, ct);
+				continue;
+			}
+			if (pad_process(mp, rd->rd_finfo, rn, ct, &rd->rd_pad,
+			    rd->rd_name) < 0)
+				return (-1);
 			ct = topo_child_next(rd->rd_pn, ct);
-			continue;
+			ccnt++;
 		}
-		if (pad_process(mp, rd->rd_finfo, rn, ct, &rd->rd_pad) < 0)
+		if (ccnt == 0) {
+			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "no nodes "
+			    "processed for range %s\n", rd->rd_name);
+			topo_node_range_destroy(rd->rd_pn, rd->rd_name);
 			return (-1);
-		ct = topo_child_next(rd->rd_pn, ct);
-		ccnt++;
+		}
 	}
 
-	if (ccnt == 0) {
-		topo_node_range_destroy(rd->rd_pn, rd->rd_name);
-		topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "no nodes processed for "
-		    "range %s\n", rd->rd_name);
-		return (-1);
-	}
+	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end "
+	    "range process %s\n", rd->rd_name);
 
-	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "end range process %s\n",
-	    rd->rd_name);
 	return (0);
 }
 
@@ -913,7 +1313,7 @@
 
 	/*
 	 * What we're interested in are children xmlNodes of croot tagged
-	 * as 'ranges', these define topology nodes may exist, and need
+	 * as 'ranges'.  These define what topology nodes may exist, and need
 	 * to be verified.
 	 */
 	topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n");
@@ -921,12 +1321,13 @@
 	for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
 		if (curr->name == NULL) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
-			    "Ignoring nameless xmlnode\n");
+			    "topo_xml_walk: Ignoring nameless xmlnode\n");
 			continue;
 		}
 		if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0) {
 			topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
-			    "Ignoring non-range %s.\n", curr->name);
+			    "topo_xml_walk: Ignoring non-range %s.\n",
+			    curr->name);
 			continue;
 		}
 		if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) {
@@ -943,6 +1344,7 @@
 		}
 		rr->rd_cnt++;
 	}
+
 	return (rr);
 }
 
@@ -954,6 +1356,8 @@
 {
 	xmlNodePtr xroot;
 
+	topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n");
+
 	if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) {
 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
 		    "Couldn't get root xmlNode.\n");
@@ -985,6 +1389,9 @@
 	tf_info_t *r;
 	int e, validate = 0;
 
+	topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML,
+	    "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme);
+
 	/*
 	 * Since topologies can XInclude other topologies, and libxml2
 	 * doesn't do DTD-based validation with XInclude, by default
@@ -1009,7 +1416,7 @@
 
 	if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) {
 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
-		    "couldn't parse document.\n");
+		    "txml_file_parse: couldn't parse document.\n");
 		return (NULL);
 	}
 
@@ -1080,7 +1487,7 @@
 		document->extSubset = dtd;
 	}
 
-	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {;
+	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
 		xmlFree(scheme);
 		xmlFreeDoc(document);
 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
@@ -1117,22 +1524,15 @@
 	return (r);
 }
 
-static int
-txml_file_open(topo_mod_t *mp, const char *filename)
-{
-	int rfd;
-	if ((rfd = open(filename, O_RDONLY)) < 0)
-		return (topo_mod_seterrno(mp, ETOPO_PRSR_NOENT));
-	return (rfd);
-}
-
 tf_info_t *
 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme)
 {
 	int fd;
 	tf_info_t *tip;
 
-	if ((fd = txml_file_open(tmp, path)) < 0) {
+	if ((fd = open(path, O_RDONLY)) < 0) {
+		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
+		    "failed to open %s for reading\n", path);
 		return (NULL);
 	}
 	tip = txml_file_parse(tmp, fd, path, escheme);
--- a/usr/src/lib/fm/topo/maps/common/topology.dtd.1	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/maps/common/topology.dtd.1	Mon Sep 17 12:24:38 2007 -0700
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  CDDL HEADER START
@@ -61,21 +61,18 @@
 <!-- Properties and property groups -->
 
 <!--
-   propval
+  propval
 
-     This element is for a singly valued property within a property
-     group.
+ 	This element is for a singly valued property within a property group.
 
-     Its attributes are
+	Its attributes are
 
-	name	The name of this property.
-
-	type	The data type for this property.
+		name	The name of this property.
 
-	value	The value for this property.  Must match type
-		restriction of type attribute.
+		type	The data type for this property.
 
-	immutable This value remains unchanged for the lifetime of a snapshot.
+		value	The value for this property.  Must match type
+			restriction of type attribute.
 -->
 
 <!ELEMENT propval EMPTY >
@@ -85,26 +82,26 @@
 	type		( int32 | uint32 | int64 | uint64 |
 			  string | fmri ) #REQUIRED
 	value		CDATA #REQUIRED
-	immutable	( true | false ) "true" >
 
 <!--
   propgroup
 
-    This element is for a set of related properties on a topo node
-    It contains an optional stability element, as well as
-    zero or more property-containing elements.
+	This element is for a set of related properties on a topo node
+	It contains an optional stability element, as well as
+	zero or more property-containing elements.
+
+	Its attributes are
 
-    Its attributes are
-
-	name		The name of this property group.
-	name-stability	Stability level of the property group name
-	data-stability	Stability level of the property names and content
-	version		Version of the propery group definition
+		name		The name of this property group.
+		name-stability	Stability level of the property group name
+		data-stability	Stability level of the property names and
+				content
+		version		Version of the propery group definition
 
 -->
 
 <!ELEMENT propgroup
-	( propval* ) >
+	( propval*, propmethod* ) >
 
 <!ATTLIST propgroup
 	name		CDATA #REQUIRED
@@ -114,24 +111,92 @@
 	data-stability	( Private | Standard | Stable | Evolving | Unstable |
                         External | Obsolete ) #REQUIRED >
 
+<!--
+  propset
+	This element is for associating property groups according to a set type.
+
+	Its attributes are
+
+		type	The type of this property group set.  'product' is the
+			only set type currently supported.
+		set	The list of set types.
+
+-->
+
+<!ELEMENT propset
+	 ( propgroup* ) >
+
+<!ATTLIST propset
+	type	( product ) #REQUIRED
+	set	CDATA #REQUIRED >
+
+<!--
+  propmap
+	This element is for specifying an additional topo map file for
+	properties assigned to a given range.
+
+	Its attributes are
+
+		name		Name of map file
+-->
+
+<!ELEMENT propmap EMPTY >
+
+<!ATTLIST propmap
+	name		CDATA #REQUIRED >
+
 <!-- Methods -->
 
 <!--
+  argval
+ 
+	A propmethod argument. It has two attributes:
+ 
+		name    The name of the argument.
+		type    The data type of the argument.
+		value	The value of the arg
+-->
+
+<!ELEMENT argval EMPTY>
+
+<!ATTLIST argval
+        name            CDATA #REQUIRED
+        type            CDATA #REQUIRED
+        value           CDATA #REQUIRED >
+
+<!--
+   propmethod
+
+	This element is for properties that can only be determined dynamically
+	from a plugin.
+
+	Its attributes are
+
+      		name		Name of the method
+      		version		Version of the method API
+      		propname	Name of the property to create
+		proptype	Type of the property to create
+
+<!ELEMENT propmethod
+	( argval* ) >
+
+<!ATTLIST propmethod
+	name		CDATA #REQUIRED
+	version		CDATA #REQUIRED
+	propname	CDATA #REQUIRED
+	proptype	CDATA #REQUIRED>
+<!--
   enum-method
 
-    This element describes the enumeration method used to
-    populate a composition of topo nodes.  Its interpretation is
-    left to the enumerator to which a particular topo node is
-    assigned.  It contains a set of attributes, context, and an optional
-    stability element for the optional args that can be included.
+	This element describes the enumeration method used to
+	populate a composition of topo nodes for a given range of topology
+	nodes. 
 
-    Its attributes are
+	Its attributes are
 
-	name	Name of this method.  The method names are
-		usually a defined interface of the enumerator to which a
-		topo instance assigned.
+		name	Name of the module exporting an enumeration method.
 
-	version Version of the enumeration API
+		version Version of the libtopo API
 
 -->
 
@@ -141,42 +206,39 @@
 	name		CDATA #REQUIRED
 	version		CDATA #REQUIRED >
 
+
 <!--
   node
 
-    This element identifies a known topology node.
-
-    Its attributes are
+	This element identifies a topology node instance.
 
-	instance The instance number of the known node
+	Its attributes are
 
-	static	Boolean to determine if node is statically created
-		by the XML parser or an enumerator
+		instance The instance number of the node
 
 -->
 
 <!ELEMENT node
-	( propgroup*, dependents* ) >
+	( propgroup*, dependents*, propset* ) >
 
 <!ATTLIST node
-	instance	CDATA #REQUIRED
-	static          ( true | false ) "false" >
+	instance	CDATA #REQUIRED >
 
 <!--
   dependents
 
 	Ranges may have a number of "dependent" ranges, linked to
-	the original range hierarchically as children or siblings. 
+	the original range hierarchically as children or as a list, siblings. 
 
 	Its attribute is:
-		grouping	"children", "siblings"
+		grouping	children | siblings
 -->
 
 <!ELEMENT dependents 
 	( range | xi:include )+ >
 
 <!ATTLIST dependents 
-	grouping ( children | siblings ) #REQUIRED >
+	grouping ( children | siblings ) "children" #REQUIRED >
 
 <!--
   range
@@ -196,7 +258,8 @@
 -->
 
 <!ELEMENT range
-	( enum-method?, node*, propgroup*, dependents* ) >
+	( enum-method?, propmap?, node*, propgroup*, dependents*,
+	    propset* ) >
 
 <!ATTLIST range
 	name		CDATA #REQUIRED
@@ -210,7 +273,7 @@
 
 	Its attributes are:
 		name	topology name
-		scheme  "hc", "dev"
+		scheme 	( hc | dev  ) 
 -->
 
 <!ELEMENT topology
--- a/usr/src/lib/fm/topo/maps/i86pc/Makefile	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/maps/i86pc/Makefile	Mon Sep 17 12:24:38 2007 -0700
@@ -27,7 +27,7 @@
 ARCH = i86pc
 CLASS = arch
 DTDFILE = topology.dtd.1
-TOPOFILE = i86pc-hc-topology.xml
+TOPOFILE = i86pc-hc-topology.xml chip-hc-topology.xml
 SRCDIR = ../i86pc
 
 include ../Makefile.map
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml	Mon Sep 17 12:24:38 2007 -0700
@@ -0,0 +1,199 @@
+<?xml version="1.0"?>
+<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1">
+<!--
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ Use is subject to license terms.
+
+ 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
+
+    ident	"%Z%%M%	%I%	%E% SMI"
+-->
+
+<topology name='chip' scheme='hc'>
+
+    <range name='chip' min='0' max='100'>
+
+        <propset type='product'
+	    set='Sun-Fire-V20z|Sun-Fire-V40z|W1100z/2100z|Sun-Ultra-20-Workstation|Ultra20-M2|Sun-Ultra-40-M2-Workstation'>
+	    
+            <propgroup name='protocol' version='1'
+                name-stability='Private' data-stability='Private' >
+
+                <propmethod name='simple_chip_label' version='0'
+		            propname='label' proptype='string' >
+              
+                    <argval name='format' type='string' value='CPU %d' />
+                    <argval name='offset' type='uint32' value='0' />
+
+                </propmethod>
+
+            </propgroup>
+
+        </propset> 
+        <propset type='product'
+	    set='Sun-Fire(TM)-X2100|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E|Sun-Fire-X4500|X2100-M2'>
+	    
+            <propgroup name='protocol' version='1'
+                name-stability='Private' data-stability='Private' >
+
+                <propmethod name='simple_chip_label' version='0'
+		            propname='label' proptype='string' >
+              
+                    <argval name='format' type='string' value='CPU %d' />
+                    <argval name='offset' type='uint32' value='0' />
+
+                </propmethod>
+
+            </propgroup>
+
+        </propset> 
+        <propset type='product'
+	    set='Sun-Fire-X4100-M2|Sun-Fire-X4200-M2'>
+	    
+            <propgroup name='protocol' version='1'
+                name-stability='Private' data-stability='Private' >
+
+                <propmethod name='simple_chip_label' version='0'
+		            propname='label' proptype='string' >
+              
+                    <argval name='format' type='string' value='CPU %d' />
+                    <argval name='offset' type='uint32' value='1' />
+
+                </propmethod>
+
+            </propgroup>
+
+        </propset> 
+        <propset type='product'
+	    set='Sun-Fire-X4600|Sun-Fire-X4600-M2'>
+	    
+            <propgroup name='protocol' version='1'
+                name-stability='Private' data-stability='Private' >
+
+                <propmethod name='g4_chip_label' version='0'
+		            propname='label' proptype='string' >
+              
+                    <argval name='format' type='string' value='CPU %c' />
+
+                </propmethod>
+
+            </propgroup>
+
+        </propset> 
+
+    <dependents grouping='children'>
+
+        <range name='memory-controller' min='0' max='16'>
+        <dependents grouping='children'>
+
+            <range name='dimm' min='0' max='16'>
+
+                <propset type='product' set='Sun-Ultra-20-Workstation|Sun-Fire(TM)-X2100'>
+		    
+                    <propgroup name='protocol' version='1'
+                               name-stability='Private'
+			       data-stability='Private' >
+
+                        <propmethod name='simple_dimm_label' version='0'
+			            propname='label' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='DIMM %d' />
+                            <argval name='offset' type='uint32' value='1' />
+
+                        </propmethod>
+
+                    </propgroup>
+
+                </propset> 
+                <propset type='product' set='Sun-Fire-V20z|Sun-Fire-V40z|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E'>
+		    
+                    <propgroup name='protocol' version='1'
+                               name-stability='Private'
+			       data-stability='Private' >
+
+                        <propmethod name='simple_dimm_label_mp' version='0'
+			            propname='label' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='CPU %d DIMM %d' />
+                            <argval name='offset' type='uint32' value='0' />
+                            <argval name='order' type='string'
+			        value='forward' />
+                            <argval name='dimms_per_chip' type='uint32'
+			        value='4' />
+
+                        </propmethod>
+
+                    </propgroup>
+
+                </propset>
+                <propset type='product'
+		    set='Sun-Ultra-40-M2-Workstation'>
+		    
+                    <propgroup name='protocol' version='1'
+                               name-stability='Private'
+			       data-stability='Private' >
+
+                        <propmethod name='seq_dimm_label' version='0'
+			            propname='label' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='DIMM %d' />
+                            <argval name='offset' type='uint32' value='0' />
+                            <argval name='order' type='string'
+			        value='reverse' />
+
+                        </propmethod>
+
+                    </propgroup>
+
+               </propset>
+                <propset type='product'
+		    set='X2100-M2'>
+		    
+                    <propgroup name='protocol' version='1'
+                               name-stability='Private'
+			       data-stability='Private' >
+
+                        <propmethod name='seq_dimm_label' version='0'
+			            propname='label' proptype='string' >
+              
+                            <argval name='format' type='string'
+			        value='B0D%d' />
+                            <argval name='offset' type='uint32' value='0' />
+                            <argval name='order' type='string'
+			        value='reverse' />
+
+                        </propmethod>
+
+                    </propgroup>
+
+               </propset>
+
+            </range>
+
+        </dependents>
+        </range>
+
+    </dependents>
+    </range>
+
+</topology>
--- a/usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml	Mon Sep 17 12:24:38 2007 -0700
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1">
 <!--
- Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  Use is subject to license terms.
 
  CDDL HEADER START
@@ -41,6 +41,7 @@
     <dependents grouping='children'>
       <range name='chip' min='0' max='100'>
         <enum-method name='chip' version='1' />
+	<propmap name='chip' />
       </range>
       <range name='hostbridge' min='0' max='254'>
         <enum-method name='hostbridge' version='1' />
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/Makefile	Mon Sep 17 12:24:38 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# 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.
@@ -20,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -28,7 +27,7 @@
 MODULE = chip
 ARCH = i86pc
 CLASS = arch
-MODULESRCS = chip.c
+MODULESRCS = chip_label.c chip.c
 
 include ../../Makefile.plugin
 
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c	Mon Sep 17 12:24:38 2007 -0700
@@ -96,6 +96,24 @@
 	{ NULL }
 };
 
+const topo_method_t dimm_methods[] = {
+	{ SIMPLE_DIMM_LBL, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, simple_dimm_label},
+	{ SIMPLE_DIMM_LBL_MP, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, simple_dimm_label_mp},
+	{ SEQ_DIMM_LBL, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, seq_dimm_label},
+	{ NULL }
+};
+
+const topo_method_t chip_methods[] = {
+	{ SIMPLE_CHIP_LBL, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, simple_chip_label},
+	{ G4_CHIP_LBL, "Property method", 0,
+	    TOPO_STABILITY_INTERNAL, g4_chip_label},
+	{ NULL }
+};
+
 static nvlist_t *cs_fmri[MC_CHIP_NCS];
 
 static void
@@ -576,7 +594,7 @@
  *   also calls it directly to construct a "mem" scheme asru for a dimm node)
  * - if 'in' in addition includes an hc-specific member which specifies
  *   asru-physaddr or asru-offset then these are includes in the "mem" scheme
- *   asru as additional membersl physaddr and offset
+ *   asru as additional members physaddr and offset
  */
 static int
 mem_asru_create(topo_mod_t *mod, nvlist_t *fmri, nvlist_t **asru)
@@ -691,7 +709,7 @@
 	    &csnamearr, &ncsname) != 0 || ncs != ncsname) {
 		whinge(mod, &nerr, "rank_create: "
 		    "csnums/csnames extraction failed\n");
-		    return (nerr);
+		return (nerr);
 	}
 
 	if (topo_node_resource(pnode, &pfmri, &err) < 0) {
@@ -743,7 +761,7 @@
 			    "topo_method_register failed");
 
 		(void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]],
-			    TOPO_ASRU_COMPUTE, &err);
+		    TOPO_ASRU_COMPUTE, &err);
 
 		(void) topo_pgroup_create(ranknode, &rank_pgroup, &err);
 
@@ -806,6 +824,10 @@
 			continue;
 		}
 
+		if (topo_method_register(mod, dimmnode, dimm_methods) < 0)
+			whinge(mod, &nerr, "dimm_create: "
+			    "topo_method_register failed");
+
 		/*
 		 * Use the mem computation method directly to publish the asru
 		 * in the "mem" scheme.
@@ -1054,6 +1076,10 @@
 		}
 		BT_SET(chipmap, chipid);
 
+		if (topo_method_register(mod, cnode, chip_methods) < 0)
+			whinge(mod, &nerr, "chip_create: "
+			    "topo_method_register failed");
+
 		(void) topo_node_fru_set(cnode, fmri, 0, &err);
 
 		nvlist_free(fmri);
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.h	Mon Sep 17 12:24:38 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,12 +63,36 @@
 #define	CPU_CORE_ID	"core_id"
 #define	CPU_CLOG_ID	"clog_id"
 
+/*
+ * label property methods
+ */
+#define	SIMPLE_DIMM_LBL		"simple_dimm_label"
+#define	SIMPLE_DIMM_LBL_MP	"simple_dimm_label_mp"
+#define	SEQ_DIMM_LBL		"seq_dimm_label"
+#define	SIMPLE_CHIP_LBL		"simple_chip_label"
+#define	G4_CHIP_LBL		"g4_chip_label"
+
 typedef struct chip {
 	kstat_ctl_t *chip_kc;
 	kstat_t **chip_cpustats;
 	uint_t chip_ncpustats;
 } chip_t;
 
+extern int simple_dimm_label(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+
+extern int simple_dimm_label_mp(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+
+extern int seq_dimm_label(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+
+extern int simple_chip_label(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+
+extern int g4_chip_label(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+
 #ifdef __cplusplus
 }
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip_label.c	Mon Sep 17 12:24:38 2007 -0700
@@ -0,0 +1,474 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <strings.h>
+#include <libnvpair.h>
+#include <sys/types.h>
+#include <fm/topo_mod.h>
+
+#define	BUFSZ	128
+
+static char *
+get_fmtstr(topo_mod_t *mod, nvlist_t *in, int *err)
+{
+	char *fmtstr;
+	nvlist_t *args;
+
+	topo_mod_dprintf(mod, "get_fmtstr() called\n");
+
+	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+		    strerror(errno));
+		*err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		return (NULL);
+	}
+	if (nvlist_lookup_string(args, "format", &fmtstr) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
+		    strerror(errno));
+		*err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (NULL);
+	}
+	return (fmtstr);
+}
+
+static int
+store_prop_val(topo_mod_t *mod, char *buf, char *propname, nvlist_t **out)
+{
+	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) {
+		topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+	}
+	if (nvlist_add_string(*out, TOPO_PROP_VAL_NAME, propname) != 0) {
+		topo_mod_dprintf(mod, "Failed to set '%s'\n",
+		    TOPO_PROP_VAL_NAME);
+		nvlist_free(*out);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	if (nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_STRING)
+	    != 0) {
+		topo_mod_dprintf(mod, "Failed to set '%s'\n",
+		    TOPO_PROP_VAL_TYPE);
+		nvlist_free(*out);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	if (nvlist_add_string(*out, TOPO_PROP_VAL_VAL, buf) != 0) {
+		topo_mod_dprintf(mod, "Failed to set '%s'\n",
+		    TOPO_PROP_VAL_VAL);
+		nvlist_free(*out);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+	return (0);
+}
+
+/*
+ * This is a somewhat generic property method for labelling the dimm slots on
+ * uni-socket x86/x64 platforms.  This method assumes a direct linear
+ * correlation between the dimm topo node instance number and the dimm slot
+ * label number.  It takes the following two arguments:
+ *
+ * format:	a string containing a printf-like format with a single %d token
+ *              which this method computes
+ *
+ *              i.e.: DIMM %d
+ *
+ * offset:      a numeric offset that we'll number the dimms from.  This is to
+ *              allow for the fact that some systems number the dimm slots
+ *              from zero and others start from one (like the Ultra 20)
+ */
+/* ARGSUSED */
+int
+simple_dimm_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, buf[BUFSZ];
+	int err;
+	uint32_t offset;
+	nvlist_t *args;
+
+	topo_mod_dprintf(mod, "simple_dimm_label() called\n");
+	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		return (err);
+	}
+	if (nvlist_lookup_uint32(args, "offset", &offset) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (err);
+	}
+
+	if ((fmtstr = get_fmtstr(mod, in, &err)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to retrieve format arg\n");
+		nvlist_free(args);
+		return (err);
+	}
+
+	/* LINTED: E_SEC_PRINTF_VAR_FMT */
+	(void) snprintf(buf, BUFSZ, fmtstr,
+	    (topo_node_instance(node) + offset));
+
+	if ((err = store_prop_val(mod, buf, "label", out)) != 0) {
+		topo_mod_dprintf(mod, "Failed to set label\n");
+		nvlist_free(args);
+		return (err);
+	}
+
+	return (0);
+}
+
+
+/*
+ * This is a somewhat generic property method for labelling the dimm slots on
+ * multi-socket x86/x64 platforms.  It takes the following two arguments:
+ *
+ * format:	a string containing a printf-like format with a two %d tokens
+ *              for the cpu and dimm slot label numbers, which this method
+ *              computes
+ *
+ *              i.e.: CPU %d DIMM %d
+ *
+ * offset:      a numeric offset that we'll number the dimms from.  This is to
+ *              allow for the fact that some systems number the dimm slots
+ *              from zero while others may start from one
+ *
+ * order:	"reverse" or "forward" - sets the direction of the correlation
+ *              between dimm topo node instance number and DIMM slot number
+ *
+ * dimms_per_chip:  the number of DIMM slots per chip
+ */
+/* ARGSUSED */
+int
+simple_dimm_label_mp(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, *order, buf[BUFSZ];
+	tnode_t *chip;
+	int err;
+	uint32_t offset, dimms_per_chip;
+	nvlist_t *args;
+
+	topo_mod_dprintf(mod, "simple_dimm_label_mp() called\n");
+
+	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		return (err);
+	}
+	if (nvlist_lookup_uint32(args, "offset", &offset) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (err);
+	}
+	if (nvlist_lookup_uint32(args, "dimms_per_chip", &dimms_per_chip)
+	    != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'dimms_per_chip' arg "
+		    "(%s)\n", strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (err);
+	}
+	if (nvlist_lookup_string(args, "order", &order) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'order' arg (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (err);
+	}
+	if ((fmtstr = get_fmtstr(mod, in, &err)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
+		topo_mod_free(mod, order, BUFSZ);
+		nvlist_free(args);
+		return (err);
+	}
+
+	chip = topo_node_parent(topo_node_parent(node));
+
+	if (strcasecmp(order, "forward") == 0)
+		/* LINTED: E_SEC_PRINTF_VAR_FMT */
+		(void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip),
+		    (topo_node_instance(node) + offset));
+	else if (strcasecmp(order, "reverse") == 0)
+		/* LINTED: E_SEC_PRINTF_VAR_FMT */
+		(void) snprintf(buf, BUFSZ, fmtstr, topo_node_instance(chip),
+		    (((topo_node_instance(chip) + 1) * dimms_per_chip)
+		    - (topo_node_instance(node)) - 1 + offset));
+	else {
+		topo_mod_dprintf(mod, "Invalid value for order arg\n");
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		topo_mod_free(mod, order, BUFSZ);
+		nvlist_free(args);
+		return (err);
+	}
+
+	if ((err = store_prop_val(mod, buf, "label", out)) != 0) {
+		topo_mod_dprintf(mod, "Failed to set label\n");
+		topo_mod_free(mod, order, BUFSZ);
+		nvlist_free(args);
+		return (err);
+	}
+
+	return (0);
+}
+
+/*
+ * This method assumes a correspondence between the dimm topo node instance
+ * number and the dimm slot label number, but unlike simple_chip_label_mp, the
+ * slot numbers aren't reused between CPU's.  This method assumes there
+ * are 4 DIMM slots per chip.  It takes the following two arguments:
+ *
+ * format:	a string containing a printf-like format with a single %d token
+ *              which this method computes
+ *
+ *              i.e.: DIMM %d
+ *
+ * offset:      a numeric offset that we'll number the dimms from.  This is to
+ *              allow for the fact that some systems number the dimm slots
+ *              from zero and others may start from one
+ *
+ * order:	"reverse" or "forward" - sets the direction of the correlation
+ *              between dimm topo node instance number and DIMM slot number
+ */
+/* ARGSUSED */
+int
+seq_dimm_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, *order, buf[BUFSZ];
+	int err;
+	uint32_t offset;
+	nvlist_t *args;
+	tnode_t *chip;
+
+	topo_mod_dprintf(mod, "seq_dimm_label() called\n");
+	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		return (err);
+	}
+	if (nvlist_lookup_uint32(args, "offset", &offset) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (err);
+	}
+	if (nvlist_lookup_string(args, "order", &order) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'order' arg (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (err);
+	}
+
+	if ((fmtstr = get_fmtstr(mod, in, &err)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to retrieve 'fmtstr' arg\n");
+		topo_mod_free(mod, order, BUFSZ);
+		nvlist_free(args);
+		return (err);
+	}
+
+	chip = topo_node_parent(topo_node_parent(node));
+
+	if (strcasecmp(order, "forward") == 0)
+		/* LINTED: E_SEC_PRINTF_VAR_FMT */
+		(void) snprintf(buf, BUFSZ, fmtstr, ((topo_node_instance(node))
+		    + (topo_node_instance(chip) * 4) + offset));
+	else if (strcasecmp(order, "reverse") == 0)
+		/* LINTED: E_SEC_PRINTF_VAR_FMT */
+		(void) snprintf(buf, BUFSZ, fmtstr,
+		    (((topo_node_instance(chip) + 1) * 4)
+		    - (topo_node_instance(node)) - 1 + offset));
+	else {
+		topo_mod_dprintf(mod, "Invalid value for order arg\n");
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		topo_mod_free(mod, order, BUFSZ);
+		nvlist_free(args);
+		return (err);
+	}
+
+	if ((err = store_prop_val(mod, buf, "label", out)) != 0) {
+		topo_mod_dprintf(mod, "Failed to set label\n");
+		topo_mod_free(mod, order, BUFSZ);
+		nvlist_free(args);
+		return (err);
+	}
+
+	return (0);
+}
+
+
+/*
+ * This is a somewhat generic property method for labelling the CPU sockets on
+ * x86/x64 platforms.  This method assumes a correspondence between
+ * the chip topo node instance number and the CPU socket label number.  It takes
+ * the following two arguments:
+ *
+ * format:	a string containing a printf-like format with a single %d token
+ *              which this method computes
+ *
+ *              i.e.: CPU %d
+ *
+ * offset:      a numeric offset that we'll number the CPU's from.  This is to
+ *              allow for the fact that some systems number the CPU sockets
+ *              from zero and others start from one (like the X4X00-M2 systems)
+ */
+/* ARGSUSED */
+int
+simple_chip_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, buf[BUFSZ];
+	int err;
+	uint32_t offset;
+	nvlist_t *args;
+
+	topo_mod_dprintf(mod, "simple_chip_label() called\n");
+	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		return (err);
+	}
+	if (nvlist_lookup_uint32(args, "offset", &offset) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
+		    strerror(errno));
+		err = topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		nvlist_free(args);
+		return (err);
+	}
+
+	if ((fmtstr = get_fmtstr(mod, in, &err)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to retrieve format arg\n");
+		nvlist_free(args);
+		return (err);
+	}
+
+	/* LINTED: E_SEC_PRINTF_VAR_FMT */
+	(void) snprintf(buf, BUFSZ, fmtstr,
+	    (topo_node_instance(node) + offset));
+
+	if ((err = store_prop_val(mod, buf, "label", out)) != 0) {
+		topo_mod_dprintf(mod, "Failed to set label\n");
+		nvlist_free(args);
+		return (err);
+	}
+
+	return (0);
+}
+
+
+/*
+ * This is a custom property method for generating the CPU slot label for the
+ * Galaxy 4E/4F platforms.
+ *
+ * format:	a string containing a printf-like format with a single %c token
+ *              which this method computes
+ *
+ *              i.e.: CPU %c
+ */
+/* ARGSUSED */
+int
+g4_chip_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+    nvlist_t *in, nvlist_t **out)
+{
+	char *fmtstr, buf[BUFSZ], slot_id;
+	int err, htid, mapidx;
+	uint32_t num_nodes;
+	/*
+	 * G4 HT node ID to FRU label translation.  The g4map array
+	 * is indexed by (number of coherent nodes) / 2 - 1.
+	 * The value for a given number of nodes is a char array
+	 * indexed by node ID.
+	 */
+	const char *g4map[] = {
+	    "AB",	/* 2 nodes */
+	    "ADEH",	/* 4 nodes */
+	    "ABDEFH",	/* 6 nodes */
+	    "ACBDEFGH"	/* 8 nodes */
+	};
+
+	topo_mod_dprintf(mod, "g4_chip_label() called\n");
+	if ((fmtstr = get_fmtstr(mod, in, &err)) == NULL) {
+		topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
+		return (err);
+	}
+
+	if (topo_prop_get_uint32(node, "chip-properties", "CoherentNodes",
+	    &num_nodes, &err) != 0) {
+		topo_mod_dprintf(mod, "Failed to lookup 'CoherentNodes'"
+		    "property\n");
+		return (err);
+	}
+
+	mapidx = num_nodes / 2 - 1;
+	htid = topo_node_instance(node);
+
+	/* HT nodes must number 0 .. num_nodes - 1 */
+	if (htid >= num_nodes) {
+		topo_mod_dprintf(mod, "chip node instance range check failed:"
+		    "num_nodes=%d, instance=%d\n", num_nodes, htid);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+	switch (num_nodes) {
+		case (2):
+		case (4):
+		case (6):
+		case (8):
+			/* htid is already range-checked */
+			mapidx = num_nodes / 2 - 1;
+			slot_id = g4map[mapidx][htid];
+			break;
+		default:
+			topo_mod_dprintf(mod, "Invalid number of CoherentNodes:"
+			    " %d\n", num_nodes);
+			return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+	/* LINTED: E_SEC_PRINTF_VAR_FMT */
+	(void) snprintf(buf, BUFSZ, fmtstr, slot_id);
+
+	if ((err = store_prop_val(mod, buf, "label", out)) != 0) {
+		topo_mod_dprintf(mod, "Failed to set label\n");
+		return (err);
+	}
+
+	return (0);
+}
--- a/usr/src/lib/libipmi/Makefile.com	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/libipmi/Makefile.com	Mon Sep 17 12:24:38 2007 -0700
@@ -28,6 +28,7 @@
 VERS=		.1
 
 OBJECTS=	ipmi_bmc.o	\
+		ipmi_fru.o	\
 		ipmi_misc.o	\
 		ipmi_sdr.o	\
 		ipmi_sensor.o	\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipmi/common/ipmi_fru.c	Mon Sep 17 12:24:38 2007 -0700
@@ -0,0 +1,311 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <libipmi.h>
+#include <string.h>
+
+#include "ipmi_impl.h"
+
+/*
+ * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
+ * u, which must be an unsigned integer.
+ */
+#define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
+
+typedef struct ipmi_fru_read
+{
+	uint8_t		ifr_devid;
+	uint8_t		ifr_offset_lsb;
+	uint8_t		ifr_offset_msb;
+	uint8_t		ifr_count;
+} ipmi_fru_read_t;
+
+/*
+ * returns: size of FRU inventory data in bytes, on success
+ *          -1, otherwise
+ */
+int
+ipmi_fru_read(ipmi_handle_t *ihp, ipmi_sdr_fru_locator_t *fru_loc, char **buf)
+{
+	ipmi_cmd_t cmd, *resp;
+	uint8_t count, devid;
+	uint16_t sz, offset = 0;
+	ipmi_fru_read_t cmd_data_in;
+
+	devid = fru_loc->_devid_or_slaveaddr._logical._is_fl_devid;
+	/*
+	 * First we issue a command to retrieve the size of the specified FRU's
+	 * inventory area
+	 */
+	cmd.ic_netfn = IPMI_NETFN_STORAGE;
+	cmd.ic_cmd = IPMI_CMD_GET_FRU_INV_AREA;
+	cmd.ic_data = &devid;
+	cmd.ic_dlen = sizeof (uint8_t);
+	cmd.ic_lun = 0;
+
+	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+		return (-1);
+
+	if (resp->ic_dlen != 3) {
+		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
+		return (-1);
+	}
+
+	(void) memcpy(&sz, resp->ic_data, sizeof (uint16_t));
+	if ((*buf = malloc(sz)) == NULL) {
+		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
+		return (-1);
+	}
+
+	while (offset < sz) {
+		cmd_data_in.ifr_devid = devid;
+		cmd_data_in.ifr_offset_lsb = BITX(offset, 7, 0);
+		cmd_data_in.ifr_offset_msb = BITX(offset, 15, 8);
+		if ((sz - offset) < 128)
+			cmd_data_in.ifr_count = sz - offset;
+		else
+			cmd_data_in.ifr_count = 128;
+
+		cmd.ic_netfn = IPMI_NETFN_STORAGE;
+		cmd.ic_cmd = IPMI_CMD_READ_FRU_DATA;
+		cmd.ic_data = &cmd_data_in;
+		cmd.ic_dlen = sizeof (ipmi_fru_read_t);
+		cmd.ic_lun = 0;
+
+		if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+			return (-1);
+
+		(void) memcpy(&count, resp->ic_data, sizeof (uint8_t));
+		if (count != cmd_data_in.ifr_count) {
+			(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH,
+			    NULL);
+			return (-1);
+		}
+		(void) memcpy((*buf)+offset, (char *)(resp->ic_data)+1, count);
+		offset += count;
+	}
+	return (sz);
+}
+
+/*
+ * See Sect 12 of the IPMI Platform Management FRU Information Storage
+ * Definition (v1.1).
+ *
+ * The FRU Product Info Area contains a number of fields which encode
+ * both the type and length of various name fields into a single byte.
+ * The byte is a bitfield broken down as follows:
+ *
+ *   bits	descr
+ *   ----	-----
+ *   7:6	encoding:
+ *		11b = 8-bit ascii
+ *              10b = 6-bit packed ascii
+ *   5:0	length of data in bytes
+ *
+ * This function extracts the type and length and then copies the data into the
+ * supplied buffer.  If the type is 6-bit packed ASCII then it first converts
+ * the string to an 8-bit ASCII string
+ *
+ * The function returns the length of the data.
+ */
+static int
+ipmi_fru_decode_string(uint8_t typelen, char *data, char *buf)
+{
+	int i, j = 0, chunks, leftovers;
+	uint8_t tmp, lo, type, len;
+
+	type = typelen >> 6;
+	len = BITX(typelen, 5, 0);
+
+	if (len == 0) {
+		*buf = '\0';
+		return (len);
+	}
+	/*
+	 * If the type is 8-bit ASCII, we can simply copy the string and return
+	 */
+	if (type == 0x3) {
+		(void) strncpy(buf, data, len);
+		*(buf+len) = '\0';
+		return (len);
+	} else if (type == 0x1 || type == 0x0) {
+		/*
+		 * Yuck - they either used BCD plus encoding, which we don't
+		 * currently handle, or they used an unspecified encoding type.
+		 * In these cases we'll set buf to an empty string.  We still
+		 * need to return the length so that we can get to the next
+		 * record.
+		 */
+		*buf = '\0';
+		return (len);
+	}
+
+	/*
+	 * Otherwise, it's 6-bit packed ASCII, so we have to convert the
+	 * data first
+	 */
+	chunks = len / 3;
+	leftovers = len % 3;
+
+	/*
+	 * First we decode the 6-bit string in chunks of 3 bytes as far as
+	 * possible
+	 */
+	for (i = 0; i < chunks; i++) {
+		tmp = BITX(*(data+j), 5, 0);
+		*buf++ = (char)(tmp + 32);
+
+		lo = BITX(*(data+j++), 7, 6);
+		tmp = BITX(*(data+j), 3, 0);
+		tmp = (tmp << 2) | lo;
+		*buf++ = (char)(tmp + 32);
+
+		lo = BITX(*(data+j++), 7, 4);
+		tmp = BITX(*(data+j), 1, 0);
+		tmp = (tmp << 4) | lo;
+		*buf++ = (char)(tmp + 32);
+
+		tmp = BITX(*(data+j++), 7, 2);
+		*buf++ = (char)(tmp + 32);
+	}
+	switch (leftovers) {
+		case 1:
+			tmp = BITX(*(data+j), 5, 0);
+			*buf++ = (char)(tmp + 32);
+			break;
+		case 2:
+			tmp = BITX(*(data+j), 5, 0);
+			*buf++ = (char)(tmp + 32);
+
+			lo = BITX(*(data+j++), 7, 6);
+			tmp = BITX(*(data+j), 3, 0);
+			tmp = (tmp << 2) | lo;
+			*buf++ = (char)(tmp + 32);
+			break;
+	}
+	*buf = '\0';
+	return (len);
+}
+
+int
+ipmi_fru_parse_product(ipmi_handle_t *ihp, char *fru_area,
+    ipmi_fru_prod_info_t *buf)
+{
+	ipmi_fru_hdr_t fru_hdr;
+	char *tmp;
+	uint8_t len, typelen;
+
+	(void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t));
+
+	/*
+	 * We get the offset to the product info area from the FRU common
+	 * header which is at the start of the FRU inventory area.
+	 *
+	 * The product info area is optional, so if the offset is NULL,
+	 * indicating that it doesn't exist, then we return an error.
+	 */
+	if (!fru_hdr.ifh_product_info_off) {
+		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+		return (-1);
+	}
+
+	tmp = fru_area + (fru_hdr.ifh_product_info_off * 8) + 3;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_manuf_name);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_product_name);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_part_number);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_product_version);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_product_serial);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	(void) ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_asset_tag);
+
+	return (0);
+}
+
+
+/*
+ * The Board Info area is described in Sect 11 of the IPMI Platform Management
+ * FRU Information Storage Definition (v1.1).
+ */
+int
+ipmi_fru_parse_board(ipmi_handle_t *ihp, char *fru_area,
+    ipmi_fru_brd_info_t *buf)
+{
+	ipmi_fru_hdr_t fru_hdr;
+	char *tmp;
+	uint8_t len, typelen;
+
+	(void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t));
+
+	/*
+	 * We get the offset to the board info area from the FRU common
+	 * header which is at the start of the FRU inventory area.
+	 *
+	 * The board info area is optional, so if the offset is NULL,
+	 * indicating that it doesn't exist, then we return an error.
+	 */
+	if (!fru_hdr.ifh_board_info_off) {
+		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+		return (-1);
+	}
+	tmp = fru_area + (fru_hdr.ifh_board_info_off * 8) + 3;
+
+	(void) memcpy(buf->ifbi_manuf_date, tmp, 3);
+	tmp += 3;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_manuf_name);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_board_name);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_product_serial);
+	tmp += len + 1;
+
+	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
+	len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_part_number);
+
+	return (0);
+}
--- a/usr/src/lib/libipmi/common/libipmi.h	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/libipmi/common/libipmi.h	Mon Sep 17 12:24:38 2007 -0700
@@ -389,6 +389,62 @@
     ipmi_set_sensor_reading_t *);
 
 /*
+ * These IPMI message id/opcodes are documented in Appendix G in the IPMI spec.
+ *
+ * Payloads for these two commands are described in Sections 34.1 and 34.2 of
+ * the spec, respectively.
+ */
+#define	IPMI_CMD_GET_FRU_INV_AREA	0x10
+#define	IPMI_CMD_READ_FRU_DATA		0x11
+
+/*
+ * Structs to hold the FRU Common Header and the FRU Product Info Area, as
+ * described in the IPMI Platform Management FRU Information Storage
+ * Definition (v1.1).
+ */
+typedef struct ipmi_fru_hdr
+{
+	uint8_t		ifh_format;
+	uint8_t		ifh_int_use_off;
+	uint8_t		ifh_chassis_info_off;
+	uint8_t		ifh_board_info_off;
+	uint8_t		ifh_product_info_off;
+	uint8_t		ifh_multi_rec_off;
+	uint8_t		ifh_pad;
+	uint8_t		ifh_chksum;
+} ipmi_fru_hdr_t;
+
+/*
+ * Because only 6 bits are used to specify the length of each field in the FRU
+ * product and board info areas, the biggest string we would ever need to hold
+ * would be 63 chars plus a NULL.
+ */
+#define	FRU_INFO_MAXLEN	64
+
+typedef struct ipmi_fru_brd_info
+{
+	char	ifbi_manuf_date[3];
+	char	ifbi_manuf_name[FRU_INFO_MAXLEN];
+	char	ifbi_board_name[FRU_INFO_MAXLEN];
+	char	ifbi_product_serial[FRU_INFO_MAXLEN];
+	char	ifbi_part_number[FRU_INFO_MAXLEN];
+} ipmi_fru_brd_info_t;
+
+typedef struct ipmi_fru_prod_info
+{
+	char	ifpi_manuf_name[FRU_INFO_MAXLEN];
+	char	ifpi_product_name[FRU_INFO_MAXLEN];
+	char	ifpi_part_number[FRU_INFO_MAXLEN];
+	char	ifpi_product_version[FRU_INFO_MAXLEN];
+	char	ifpi_product_serial[FRU_INFO_MAXLEN];
+	char	ifpi_asset_tag[FRU_INFO_MAXLEN];
+} ipmi_fru_prod_info_t;
+
+int ipmi_fru_read(ipmi_handle_t *, ipmi_sdr_fru_locator_t *, char **);
+int ipmi_fru_parse_board(ipmi_handle_t *, char *, ipmi_fru_brd_info_t *);
+int ipmi_fru_parse_product(ipmi_handle_t *, char *, ipmi_fru_prod_info_t *);
+
+/*
  * The remaining functions are private to the implementation of the Sun ILOM
  * service processor.  These function first check the manufacturer from the IPMI
  * device ID, and will return EIPMI_NOT_SUPPORTED if attempted for non-Sun
--- a/usr/src/lib/libipmi/common/mapfile-vers	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/lib/libipmi/common/mapfile-vers	Mon Sep 17 12:24:38 2007 -0700
@@ -29,6 +29,9 @@
 	ipmi_close;
 	ipmi_errmsg;
 	ipmi_errno;
+	ipmi_fru_parse_board;
+	ipmi_fru_parse_product;
+	ipmi_fru_read;
 	ipmi_get_deviceid;
 	ipmi_get_sensor_reading;
 	ipmi_open;
--- a/usr/src/pkgdefs/SUNWfmd/prototype_i386	Mon Sep 17 11:32:50 2007 -0700
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_i386	Mon Sep 17 12:24:38 2007 -0700
@@ -74,5 +74,6 @@
 f none usr/platform/i86pc/lib/fm/topo/plugins/hostbridge.so 555 root bin
 f none usr/platform/i86pc/lib/fm/topo/plugins/pcibus.so 555 root bin
 d none usr/platform/i86pc/lib/fm/topo/maps 755 root bin
+f none usr/platform/i86pc/lib/fm/topo/maps/chip-hc-topology.xml 444 root bin
 f none usr/platform/i86pc/lib/fm/topo/maps/i86pc-hc-topology.xml 444 root bin
 f none usr/platform/i86pc/lib/fm/topo/maps/Sun-Fire-X4500-hc-topology.xml 444 root bin