changeset 4087:b986877655d2

6521594 fmtopo '[-Cdev]' usage doesn't make sense 6534608 libtopo walkers could be smarter 6534610 libtopo: need mechanism to call plugin methods to get/set properties 6537307 fmri_prop() is broken for anything but ASRU/FRU 6537759 fmtopo should have a way to execute is_present/is_unusable methods 6542241 fmtopo should support per-FMRI command line options 6545662 libtopo needs to be robust in the face of memory allocation failure 6547235 bad argument used to call TOPO_METH_CONTAINS in topo_fmri_contains 6547427 hc.c topo enumerator is riddled with potential SEGVs 6548245 Mucho memory leaks in XML parser error code paths
author cindi
date Mon, 23 Apr 2007 15:34:38 -0700
parents 5214f82452a7
children 9f37e7ee9af5
files usr/src/cmd/fm/fmtopo/common/fmtopo.c usr/src/cmd/mdb/common/modules/libtopo/libtopo.c usr/src/lib/fm/topo/libtopo/Makefile.com usr/src/lib/fm/topo/libtopo/common/hc.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/mkerror.sh usr/src/lib/fm/topo/libtopo/common/topo_error.h usr/src/lib/fm/topo/libtopo/common/topo_fmri.c usr/src/lib/fm/topo/libtopo/common/topo_method.c usr/src/lib/fm/topo/libtopo/common/topo_method.h usr/src/lib/fm/topo/libtopo/common/topo_mod.c usr/src/lib/fm/topo/libtopo/common/topo_mod.h usr/src/lib/fm/topo/libtopo/common/topo_mod.map usr/src/lib/fm/topo/libtopo/common/topo_module.c usr/src/lib/fm/topo/libtopo/common/topo_node.c usr/src/lib/fm/topo/libtopo/common/topo_prop.c usr/src/lib/fm/topo/libtopo/common/topo_prop.h usr/src/lib/fm/topo/libtopo/common/topo_protocol.c usr/src/lib/fm/topo/libtopo/common/topo_snap.c usr/src/lib/fm/topo/libtopo/common/topo_subr.h usr/src/lib/fm/topo/libtopo/common/topo_tree.h usr/src/lib/fm/topo/libtopo/common/topo_xml.c usr/src/lib/fm/topo/modules/i86pc/chip/chip.c
diffstat 24 files changed, 2824 insertions(+), 1125 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fm/fmtopo/common/fmtopo.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/cmd/fm/fmtopo/common/fmtopo.c	Mon Apr 23 15:34: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.
  */
 
@@ -29,10 +29,12 @@
 #include <sys/fm/protocol.h>
 #include <fm/libtopo.h>
 #include <ctype.h>
+#include <fnmatch.h>
 #include <limits.h>
 #include <strings.h>
 #include <stdio.h>
 #include <errno.h>
+#include <umem.h>
 #include <sys/param.h>
 
 #define	FMTOPO_EXIT_SUCCESS	0
@@ -44,63 +46,88 @@
 #define	ALL	"all"
 
 static const char *g_pname;
+static const char *g_fmri = NULL;
 
 static const char *opt_R = "/";
-static const char *opt_P = NULL;
 static const char *opt_s = FM_FMRI_SCHEME_HC;
+static const char optstr[] = "aCdeP:pR:s:StvVx";
 
 static int opt_e = 0;
 static int opt_d = 0;
 static int opt_V = 0;
 static int opt_p = 0;
+static int opt_S = 0;
+static int opt_t = 0;
 static int opt_x = 0;
+static int opt_all = 0;
+
+struct prop_args {
+	const char *group;
+	const char *prop;
+	const char *type;
+	const char *value;
+};
+
+static struct prop_args **pargs = NULL;
+static int pcnt = 0;
 
 static int
 usage(FILE *fp)
 {
 	(void) fprintf(fp,
-	    "Usage: %s [-edpvVx] [-Cdev] [-P properties] [-R root] "
-		    "[-s scheme]\n", g_pname);
+	    "Usage: %s [-CedpSVx] [-P group.property[=type:value]] "
+	    "[-R root] [-s scheme] [fmri]\n", g_pname);
 
 	(void) fprintf(fp,
 	    "\t-C  dump core after completing execution\n"
 	    "\t-d  set debug mode for libtopo modules\n"
 	    "\t-e  display FMRIs as paths using esc/eft notation\n"
-	    "\t-P  display of FMRI with the specified properties\n"
+	    "\t-P  get/set specified properties\n"
 	    "\t-p  display of FMRI protocol properties\n"
 	    "\t-R  set root directory for libtopo plug-ins and other files\n"
 	    "\t-s  display topology for the specified FMRI scheme\n"
+	    "\t-S  display FMRI status (present/usable)\n"
 	    "\t-V  set verbose mode\n"
 	    "\t-x  display a xml formatted topology\n");
 
 	return (FMTOPO_EXIT_USAGE);
 }
 
-static void
-print_fmri(topo_hdl_t *thp, tnode_t *node)
+static topo_type_t
+str2type(const char *tstr)
 {
-	int err;
-	char *name;
-	nvlist_t *fmri;
+	topo_type_t type;
+
+	if (tstr == NULL)
+		return (TOPO_TYPE_INVALID);
 
-	if (topo_node_resource(node, &fmri, &err) < 0) {
-		(void) fprintf(stderr, "%s: failed to get fmri for %s=%d: %s\n",
-		    g_pname, topo_node_name(node),
-		    topo_node_instance(node), topo_strerror(err));
-		return;
+	if (strcmp(tstr, "int32") == 0)
+		type = TOPO_TYPE_INT32;
+	else if (strcmp(tstr, "uint32") == 0)
+		type = TOPO_TYPE_UINT32;
+	else if (strcmp(tstr, "int64") == 0)
+		type = TOPO_TYPE_INT64;
+	else if (strcmp(tstr, "uint64") == 0)
+		type = TOPO_TYPE_UINT64;
+	else if (strcmp(tstr, "string") == 0)
+		type = TOPO_TYPE_STRING;
+	else if (strcmp(tstr, "fmri") == 0)
+		type = TOPO_TYPE_FMRI;
+	else {
+		type = TOPO_TYPE_INVALID;
 	}
 
-	if (topo_fmri_nvl2str(thp, fmri, &name, &err) < 0) {
-		(void) fprintf(stderr, "%s: failed to convert fmri for %s=%d "
-		    "to a string: %s\n", g_pname, topo_node_name(node),
-		    topo_node_instance(node), topo_strerror(err));
-		nvlist_free(fmri);
-		return;
-	}
+	return (type);
+}
 
-	(void) printf("%s\n", name);
+static void
+print_node(topo_hdl_t *thp, tnode_t *node, nvlist_t *nvl, const char *fmri)
+{
+	int err, ret;
 
-	if (opt_p) {
+	(void) printf("%s\n", (char *)fmri);
+
+	if (opt_p && !(pcnt > 0 || opt_V || opt_all)) {
 		char *aname = NULL, *fname = NULL, *lname = NULL;
 		nvlist_t *asru = NULL;
 		nvlist_t *fru = NULL;
@@ -131,9 +158,20 @@
 			(void) printf("\tLabel: -\n");
 		}
 	}
-	nvlist_free(fmri);
 
-	topo_hdl_strfree(thp, name);
+	if (opt_S) {
+		if ((ret = topo_fmri_present(thp, nvl, &err)) < 0)
+			(void) printf("\tPresent: -\n");
+		else
+			(void) printf("\tPresent: %s\n",
+			    ret ? "true" : "false");
+
+		if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0)
+			(void) printf("\tUnusable: -\n");
+		else
+			(void) printf("\tUnusable: %s\n",
+			    ret ? "true" : "false");
+	}
 }
 
 static void
@@ -191,7 +229,7 @@
 }
 
 static void
-print_prop_nameval(topo_hdl_t *thp, nvlist_t *nvl, int skip)
+print_prop_nameval(topo_hdl_t *thp, nvlist_t *nvl)
 {
 	int err;
 	topo_type_t type;
@@ -217,12 +255,12 @@
 	if ((pv_nvp = nvlist_next_nvpair(nvl, pv_nvp)) == NULL ||
 	    nvpair_name(pv_nvp) == NULL ||
 	    strcmp(nvpair_name(pv_nvp), TOPO_PROP_VAL_TYPE) != 0 ||
-	    nvpair_type(pv_nvp) != DATA_TYPE_INT32)  {
+	    nvpair_type(pv_nvp) != DATA_TYPE_UINT32)  {
 		(void) fprintf(stderr, "%s: malformed property type for %s\n",
 		    g_pname, propn);
 		return;
 	} else {
-		(void) nvpair_value_int32(pv_nvp, (int32_t *)&type);
+		(void) nvpair_value_uint32(pv_nvp, (uint32_t *)&type);
 	}
 
 	switch (type) {
@@ -242,8 +280,7 @@
 		default: tstr = "unknown type";
 	}
 
-	if (!skip)
-		printf("    %-17s %-8s ", propn, tstr);
+	printf("    %-17s %-8s ", propn, tstr);
 
 	/*
 	 * Get property value
@@ -255,9 +292,6 @@
 		return;
 	}
 
-	if (skip)
-		return;
-
 	switch (nvpair_type(pv_nvp)) {
 		case DATA_TYPE_INT32: {
 			int32_t val;
@@ -334,14 +368,27 @@
 }
 
 static void
-print_pgroup(char *pgn, char *dstab, char *nstab, int32_t version, int skip)
+print_pgroup(topo_hdl_t *thp, tnode_t *node, const char *pgn, char *dstab,
+    char *nstab, int32_t version)
 {
+	int err;
 	char buf[30];
+	topo_pgroup_info_t *pgi = NULL;
 
-	if (skip)
+	if (pgn == NULL)
 		return;
 
-	if (!opt_V && strlen(pgn) > 30) {
+	if (node != NULL && (dstab == NULL || nstab == NULL || version == -1)) {
+		if ((pgi = topo_pgroup_info(node, pgn, &err)) != NULL) {
+			dstab = (char *)topo_stability2name(pgi->tpi_datastab);
+			nstab = (char *)topo_stability2name(pgi->tpi_namestab);
+			version = pgi->tpi_version;
+		}
+	}
+
+	if (dstab == NULL || nstab == NULL || version == -1) {
+		printf("  group: %-30s version: - stability: -/-\n", pgn);
+	} else if (!opt_V && strlen(pgn) > 30) {
 		(void) snprintf(buf, 26, "%s", pgn);
 		(void) snprintf(&buf[27], 4, "%s", DOTS);
 		printf("  group: %-30s version: %-3d stability: %s/%s\n",
@@ -350,70 +397,22 @@
 		printf("  group: %-30s version: %-3d stability: %s/%s\n",
 		    pgn, version, nstab, dstab);
 	}
-}
 
-static int
-cmp_name(const char *props, char *pgn)
-{
-	char buf[MAXNAMELEN];
-	size_t count;
-	char *begin, *end, *value, *next;
-	char *np;
-
-	if (props == NULL)
-		return (0);
-
-	if (strcmp(props, ALL) == 0)
-		return (0);
-
-
-	value = np = strdup(props);
-
-	for (end = np; *end != '\0'; value = next) {
-		end = strchr(value, ',');
-		if (end != NULL)
-			next = end + 1; /* skip the comma */
-		else
-			next = end = value + strlen(value);
-
-		/*
-		 * Eat up white space at beginning or end of the
-		 * property group name
-		 */
-		begin = value;
-		while (begin < end && isspace(*begin))
-			begin++;
-		while (begin < end && isspace(*(end - 1)))
-			end--;
-
-		if (begin >= end)
-			return (1);
-
-		count = end - begin;
-		count += 1;
-
-		if (count > sizeof (buf))
-			return (1);
-
-		(void) snprintf(buf, count, "%s", begin);
-		if (strcmp(pgn, buf) == 0) {
-			free(np);
-			return (0);
-		}
+	if (pgi != NULL) {
+		topo_hdl_strfree(thp, (char *)pgi->tpi_name);
+		topo_hdl_free(thp, pgi, sizeof (topo_pgroup_info_t));
 	}
-
-	free(np);
-	return (1);
 }
 
 static void
-print_props(topo_hdl_t *thp, nvlist_t *p_nv, const char *props)
+print_all_props(topo_hdl_t *thp, tnode_t *node, nvlist_t *p_nv,
+    const char *group)
 {
 	char *pgn = NULL, *dstab = NULL, *nstab = NULL;
-	int32_t version = 0;
+	int32_t version;
 	nvlist_t *pg_nv, *pv_nv;
 	nvpair_t *nvp, *pg_nvp;
-	int pg_done = 0, skip = 0;
+	int pg_done, match, all = strcmp(group, ALL) == 0;
 
 	for (nvp = nvlist_next_nvpair(p_nv, NULL); nvp != NULL;
 	    nvp = nvlist_next_nvpair(p_nv, nvp)) {
@@ -421,6 +420,10 @@
 		    nvpair_type(nvp) != DATA_TYPE_NVLIST)
 			continue;
 
+		nstab = NULL;
+		dstab = NULL;
+		version = -1;
+		pg_done = match = 0;
 		(void) nvpair_value_nvlist(nvp, &pg_nv);
 		for (pg_nvp = nvlist_next_nvpair(pg_nv, NULL); pg_nvp != NULL;
 		    pg_nvp = nvlist_next_nvpair(pg_nv, pg_nvp)) {
@@ -430,70 +433,325 @@
 			if (strcmp(TOPO_PROP_GROUP_NAME, nvpair_name(pg_nvp))
 			    == 0 && nvpair_type(pg_nvp) == DATA_TYPE_STRING) {
 				(void) nvpair_value_string(pg_nvp, &pgn);
+				match = strcmp(group, pgn) == 0;
+				continue;
+			}
 
-				skip = cmp_name(props, pgn);
-
-			} else if (strcmp(TOPO_PROP_GROUP_NSTAB,
+			if (strcmp(TOPO_PROP_GROUP_NSTAB,
 			    nvpair_name(pg_nvp)) == 0 &&
 			    nvpair_type(pg_nvp) == DATA_TYPE_STRING) {
 				(void) nvpair_value_string(pg_nvp, &nstab);
-			} else if (strcmp(TOPO_PROP_GROUP_DSTAB,
+				continue;
+			}
+
+			if (strcmp(TOPO_PROP_GROUP_DSTAB,
 			    nvpair_name(pg_nvp)) == 0 &&
 			    nvpair_type(pg_nvp) == DATA_TYPE_STRING) {
 				(void) nvpair_value_string(pg_nvp, &dstab);
-			} else if (strcmp(TOPO_PROP_GROUP_VERSION,
+				continue;
+			}
+
+			if (strcmp(TOPO_PROP_GROUP_VERSION,
 			    nvpair_name(pg_nvp)) == 0 &&
 			    nvpair_type(pg_nvp) == DATA_TYPE_INT32) {
 				(void) nvpair_value_int32(pg_nvp, &version);
+				continue;
+			}
+
+			if ((match || all) && !pg_done) {
+				print_pgroup(thp, node, pgn, dstab, nstab,
+				    version);
+				pg_done++;
+			}
+
+			/*
+			 * Print property group and property name-value pair
+			 */
+			if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp))
+			    == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) {
+				(void) nvpair_value_nvlist(pg_nvp, &pv_nv);
+				if ((match || all) && pg_done) {
+					print_prop_nameval(thp, pv_nv);
+				}
+
 			}
 
-			if (!pg_done) {
-				if (pgn && dstab && nstab && version) {
-					print_pgroup(pgn, dstab, nstab,
-					    version, skip);
-					pg_done++;
+		}
+		if (match && !all)
+			return;
+	}
+}
+
+static void
+set_prop(topo_hdl_t *thp, tnode_t *node, nvlist_t *fmri, struct prop_args *pp)
+{
+	int ret, err = 0;
+	topo_type_t type;
+	nvlist_t *nvl, *f = NULL;
+	char *end;
+
+	if (pp->prop == NULL || pp->type == NULL || pp->value == NULL)
+		return;
+
+	if ((type = str2type(pp->type)) == TOPO_TYPE_INVALID) {
+		(void) fprintf(stderr, "%s: invalid property type %s for %s\n",
+		    g_pname, pp->type, pp->prop);
+		return;
+	}
+
+	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
+		(void) fprintf(stderr, "%s: nvlist allocation failed for "
+		    "%s=%s:%s\n", g_pname, pp->prop, pp->type, pp->value);
+		return;
+	}
+	ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pp->prop);
+	ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
+	if (ret != 0) {
+		(void) fprintf(stderr, "%s: invalid property type %s for %s\n",
+		    g_pname, pp->type, pp->prop);
+		nvlist_free(nvl);
+		return;
+	}
+
+	errno = 0;
+	switch (type) {
+		case TOPO_TYPE_INT32:
+		{
+			int32_t val;
+
+			val = strtol(pp->value, &end, 0);
+			if (errno == ERANGE) {
+				ret = -1;
+				break;
+			}
+			ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val);
+			break;
+		}
+		case TOPO_TYPE_UINT32:
+		{
+			uint32_t val;
+
+			val = strtoul(pp->value, &end, 0);
+			if (errno == ERANGE) {
+				ret = -1;
+				break;
+			}
+			ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val);
+			break;
+		}
+		case TOPO_TYPE_INT64:
+		{
+			int64_t val;
+
+			val = strtoll(pp->value, &end, 0);
+			if (errno == ERANGE) {
+				ret = -1;
+				break;
+			}
+			ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val);
+			break;
+		}
+		case TOPO_TYPE_UINT64:
+		{
+			uint64_t val;
+
+			val = strtoull(pp->value, &end, 0);
+			if (errno == ERANGE) {
+				ret = -1;
+				break;
+			}
+			ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val);
+			break;
+		}
+		case TOPO_TYPE_STRING:
+		{
+			ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
+			    pp->value);
+			break;
+		}
+		case TOPO_TYPE_FMRI:
+		{
+			if ((ret = topo_fmri_str2nvl(thp, pp->value, &f, &err))
+			    < 0)
+				break;
+
+			if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
+			    f)) != 0)
+				err = ETOPO_PROP_NVL;
+			break;
+		}
+		default:
+			ret = -1;
+	}
+
+	if (ret != 0) {
+		(void) fprintf(stderr, "%s: unable to set property value for "
+		    "%s: %s\n", g_pname, pp->prop,  topo_strerror(err));
+		nvlist_free(nvl);
+		return;
+	}
+
+	if (node != NULL) {
+		if (topo_prop_setprop(node, pp->group, nvl, TOPO_PROP_MUTABLE,
+		    f, &ret) < 0) {
+			(void) fprintf(stderr, "%s: unable to set property "
+			    "value for " "%s=%s:%s: %s\n", g_pname, pp->prop,
+			    pp->type, pp->value, topo_strerror(ret));
+			nvlist_free(nvl);
+			nvlist_free(f);
+			return;
+		}
+	} else {
+		if (topo_fmri_setprop(thp, fmri,  pp->group, nvl,
+		    TOPO_PROP_MUTABLE, f, &ret) < 0) {
+			(void) fprintf(stderr, "%s: unable to set property "
+			    "value for " "%s=%s:%s: %s\n", g_pname, pp->prop,
+			    pp->type, pp->value, topo_strerror(ret));
+			nvlist_free(nvl);
+			nvlist_free(f);
+			return;
+		}
+	}
+
+	nvlist_free(nvl);
+
+	/*
+	 * Now, get the property back for printing
+	 */
+	if (node != NULL) {
+		if (topo_prop_getprop(node, pp->group, pp->prop, f, &nvl,
+		    &err) < 0) {
+			(void) fprintf(stderr, "%s: failed to get %s.%s: %s\n",
+			    g_pname, pp->group, pp->prop, topo_strerror(err));
+			nvlist_free(f);
+			return;
+		}
+	} else {
+		if (topo_fmri_getprop(thp, fmri, pp->group, pp->prop,
+		    f, &nvl, &err) < 0) {
+			(void) fprintf(stderr, "%s: failed to get %s.%s: %s\n",
+			    g_pname, pp->group, pp->prop, topo_strerror(err));
+			nvlist_free(f);
+			return;
+		}
+	}
+
+	print_pgroup(thp, node, pp->group, NULL, NULL, 0);
+	print_prop_nameval(thp, nvl);
+	nvlist_free(nvl);
+
+	nvlist_free(f);
+}
+
+static void
+print_props(topo_hdl_t *thp, tnode_t *node)
+{
+	int i, err;
+	nvlist_t *nvl;
+	struct prop_args *pp;
+
+	if (pcnt == 0)
+		return;
+
+	for (i = 0; i < pcnt; ++i) {
+		pp = pargs[i];
+
+		if (pp->group == NULL)
+			continue;
+
+		/*
+		 * If we have a valid value, this is a request to
+		 * set a property.  Otherwise, just print the property
+		 * group and any specified properties.
+		 */
+		if (pp->value == NULL) {
+			if (pp->prop == NULL) {
+
+				/*
+				 * Print all properties in this group
+				 */
+				if ((nvl = topo_prop_getprops(node, &err))
+				    == NULL) {
+					(void) fprintf(stderr, "%s: failed to "
+					    "get %s: %s\n", g_pname,
+					    pp->group,
+					    topo_strerror(err));
+					continue;
 				} else {
+					print_all_props(thp, node, nvl,
+					    pp->group);
+					nvlist_free(nvl);
 					continue;
 				}
-			/*
-			 * Print property name-value pair
-			 */
-			} else if (strcmp(TOPO_PROP_VAL, nvpair_name(pg_nvp))
-			    == 0 && nvpair_type(pg_nvp) == DATA_TYPE_NVLIST) {
-				(void) nvpair_value_nvlist(pg_nvp, &pv_nv);
-				print_prop_nameval(thp, pv_nv, skip);
-
 			}
+			if (topo_prop_getprop(node, pp->group, pp->prop,
+			    NULL, &nvl, &err) < 0) {
+				(void) fprintf(stderr, "%s: failed to get "
+				    "%s.%s: %s\n", g_pname,
+				    pp->group, pp->prop,
+				    topo_strerror(err));
+				continue;
+			} else {
+				print_pgroup(thp, node, pp->group, NULL,
+				    NULL, 0);
+				print_prop_nameval(thp, nvl);
+				nvlist_free(nvl);
+			}
+		} else {
+			set_prop(thp, node, NULL, pp);
 		}
-		pg_done = 0;
-		skip = 0;
 	}
 }
 
 /*ARGSUSED*/
 static int
-print_tnode(topo_hdl_t *thp, tnode_t *node, void *arg)
+walk_node(topo_hdl_t *thp, tnode_t *node, void *arg)
 {
 	int err;
 	nvlist_t *nvl;
+	nvlist_t *rsrc;
+	char *s;
 
 	if (opt_e && strcmp(opt_s, FM_FMRI_SCHEME_HC) == 0) {
 		print_everstyle(node);
 		return (TOPO_WALK_NEXT);
 	}
 
-	print_fmri(thp, node);
+	if (topo_node_resource(node, &rsrc, &err) < 0) {
+		(void) fprintf(stderr, "%s: failed to get resource: "
+		    "%s", g_pname, topo_strerror(err));
+		return (TOPO_WALK_NEXT);
+	}
+	if (topo_fmri_nvl2str(thp, rsrc, &s, &err) < 0) {
+		(void) fprintf(stderr, "%s: failed to convert "
+		    "resource to FMRI string: %s", g_pname,
+		    topo_strerror(err));
+		nvlist_free(rsrc);
+		return (TOPO_WALK_NEXT);
+	}
 
-	if (opt_V || opt_P) {
+	if (g_fmri != NULL && fnmatch(g_fmri, s, 0) != 0) {
+			nvlist_free(rsrc);
+			topo_hdl_strfree(thp, s);
+			return (TOPO_WALK_NEXT);
+	}
+
+	print_node(thp, node, rsrc, s);
+	topo_hdl_strfree(thp, s);
+	nvlist_free(rsrc);
+
+	if (opt_V || opt_all) {
 		if ((nvl = topo_prop_getprops(node, &err)) == NULL) {
 			(void) fprintf(stderr, "%s: failed to get "
 			    "properties for %s=%d: %s\n", g_pname,
 			    topo_node_name(node), topo_node_instance(node),
 			    topo_strerror(err));
 		} else {
-			print_props(thp, nvl, opt_P);
+			print_all_props(thp, node, nvl, ALL);
 			nvlist_free(nvl);
 		}
+	} else if (pcnt > 0) {
+		print_props(thp, node);
 	}
 
 	printf("\n");
@@ -501,100 +759,93 @@
 	return (TOPO_WALK_NEXT);
 }
 
-int
-main(int argc, char *argv[])
+static void
+get_pargs(int argc, char *argv[])
 {
-	topo_hdl_t *thp;
-	topo_walk_t *twp;
-	char *uuid;
-	int c, err = 0;
-
-	g_pname = argv[0];
+	struct prop_args *pp;
+	char c, *s, *p;
+	int i = 0;
 
-	while (optind < argc) {
-		while ((c = getopt(argc, argv, "aCdeP:pR:s:vVx")) != -1) {
-			switch (c) {
-			case 'C':
-				atexit(abort);
-				break;
-			case 'd':
-				opt_d++;
-				break;
-			case 'e':
-				opt_e++;
-				break;
-			case 'P':
-				opt_P = optarg;
+	if ((pargs = malloc(sizeof (struct prop_args *) * pcnt)) == NULL) {
+		(void) fprintf(stderr, "%s: failed to allocate property "
+		    "arguments\n", g_pname);
+		return;
+	}
+
+	for (optind = 1; (c = getopt(argc, argv, optstr)) != EOF; ) {
+		if (c == 'P') {
+
+			if (strcmp(optarg, ALL) == 0) {
+				opt_all++;
 				break;
-			case 'p':
-				opt_p++;
-				break;
-			case 'V':
-				opt_V++;
-				break;
-			case 'R':
-				opt_R = optarg;
-				break;
-			case 's':
-				opt_s = optarg;
+			}
+
+			if ((pp = pargs[i] = malloc(sizeof (struct prop_args)))
+			    == NULL) {
+				(void) fprintf(stderr, "%s: failed to "
+				    "allocate propertyarguments\n", g_pname);
+				return;
+			}
+			++i;
+			pp->group = NULL;
+			pp->prop = NULL;
+			pp->type = NULL;
+			pp->value = NULL;
+
+			p = optarg;
+			if ((s = strchr(p, '.')) != NULL) {
+				*s++ = '\0'; /* strike out delimiter */
+				pp->group = p;
+				p = s;
+				if ((s = strchr(p, '=')) != NULL) {
+					*s++ = '\0'; /* strike out delimiter */
+					pp->prop = p;
+					p = s;
+					if ((s = strchr(p, ':')) != NULL) {
+						*s++ = '\0';
+						pp->type = p;
+						pp->value = s;
+					} else {
+						(void) fprintf(stderr, "%s: "
+						    "property type not "
+						    "specified for assignment "
+						    " of %s.%s\n", g_pname,
+						    pp->group, pp->prop);
+						break;
+					}
+				} else {
+					pp->prop = p;
+				}
+			} else {
+				pp->group = p;
+			}
+			if (i >= pcnt)
 				break;
-			case 'x':
-				opt_x++;
-				break;
-			default:
-				return (usage(stderr));
-			}
-		}
-
-		if (optind < argc) {
-			(void) fprintf(stderr, "%s: illegal argument -- %s\n",
-			    g_pname, argv[optind]);
-			return (FMTOPO_EXIT_USAGE);
 		}
 	}
 
-	if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) {
-		(void) fprintf(stderr, "%s: failed to open topology tree: %s\n",
-		    g_pname, topo_strerror(err));
-		return (FMTOPO_EXIT_ERROR);
-	}
-
-	if (opt_d)
-		topo_debug_set(thp, "module", "stderr");
+	if (opt_all > 0) {
+		int j;
 
-	if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) {
-		(void) fprintf(stderr, "%s: failed to snapshot topology: %s\n",
-		    g_pname, topo_strerror(err));
-		topo_close(thp);
-		return (FMTOPO_EXIT_ERROR);
-	} else if (err != 0) {
-		(void) fprintf(stderr, "%s: topology snapshot incomplete\n",
-		    g_pname);
+		for (j = 0; j < i; ++j)
+			free(pargs[i]);
+		free(pargs);
+		pargs = NULL;
 	}
-
+}
 
-	if (opt_x) {
-		err = 0;
-		if (topo_xml_print(thp, stdout, opt_s, &err) < 0)
-			(void) fprintf(stderr, "%s: failed to print xml "
-			    "formatted topology:%s",  g_pname,
-			    topo_strerror(err));
+static int
+walk_topo(topo_hdl_t *thp, char *uuid)
+{
+	int err;
+	topo_walk_t *twp;
 
-		topo_hdl_strfree(thp, uuid);
-		topo_snap_release(thp);
-		topo_close(thp);
-		return (err ? FMTOPO_EXIT_ERROR : FMTOPO_EXIT_SUCCESS);
-	}
-	if ((twp = topo_walk_init(thp, opt_s, print_tnode, NULL, &err))
+	if ((twp = topo_walk_init(thp, opt_s, walk_node, NULL, &err))
 	    == NULL) {
 		(void) fprintf(stderr, "%s: failed to walk %s topology:"
 		    " %s\n", g_pname, opt_s, topo_strerror(err));
 
-		topo_hdl_strfree(thp, uuid);
-		topo_snap_release(thp);
-		topo_close(thp);
-
-		return (err ? FMTOPO_EXIT_ERROR : FMTOPO_EXIT_SUCCESS);
+		return (-1);
 	}
 
 	/*
@@ -610,20 +861,311 @@
 		(void) printf("\n");
 	}
 
-	topo_hdl_strfree(thp, uuid);
-
 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
 		(void) fprintf(stderr, "%s: failed to walk topology\n",
 		    g_pname);
 		topo_walk_fini(twp);
-		topo_snap_release(thp);
-		topo_close(thp);
-		return (FMTOPO_EXIT_ERROR);
+		return (-1);
 	}
 
 	topo_walk_fini(twp);
-	topo_snap_release(thp);
-	topo_close(thp);
+
+	return (0);
+}
+
+static void
+print_fmri_pgroup(topo_hdl_t *thp, const char *pgn, nvlist_t *nvl)
+{
+	char *dstab = NULL, *nstab = NULL;
+	int32_t version = -1;
+	nvlist_t *pnvl;
+	nvpair_t *pnvp;
+
+	(void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_NSTAB, &nstab);
+	(void) nvlist_lookup_string(nvl, TOPO_PROP_GROUP_DSTAB, &dstab);
+	(void) nvlist_lookup_int32(nvl, TOPO_PROP_GROUP_VERSION, &version);
+
+	print_pgroup(thp, NULL, pgn, dstab, nstab, version);
+
+	for (pnvp = nvlist_next_nvpair(nvl, NULL); pnvp != NULL;
+	    pnvp = nvlist_next_nvpair(nvl, pnvp)) {
+
+		/*
+		 * Print property group and property name-value pair
+		 */
+		if (strcmp(TOPO_PROP_VAL, nvpair_name(pnvp))
+		    == 0 && nvpair_type(pnvp) == DATA_TYPE_NVLIST) {
+			(void) nvpair_value_nvlist(pnvp, &pnvl);
+				print_prop_nameval(thp, pnvl);
+
+		}
+
+	}
+}
+
+static void
+print_fmri_props(topo_hdl_t *thp, nvlist_t *nvl)
+{
+	int i, err;
+	struct prop_args *pp;
+	nvlist_t *pnvl;
+
+	for (i = 0; i < pcnt; ++i) {
+		pp = pargs[i];
+
+		if (pp->group == NULL)
+			continue;
+
+		pnvl = NULL;
+
+		/*
+		 * If we have a valid value, this is a request to
+		 * set a property.  Otherwise, just print the property
+		 * group and any specified properties.
+		 */
+		if (pp->value == NULL) {
+			if (pp->prop == NULL) {
+
+				/*
+				 * Print all properties in this group
+				 */
+				if (topo_fmri_getpgrp(thp, nvl, pp->group,
+				    &pnvl, &err) < 0) {
+					(void) fprintf(stderr, "%s: failed to "
+					    "get group %s: %s\n", g_pname,
+					    pp->group, topo_strerror(err));
+					continue;
+				} else {
+					print_fmri_pgroup(thp, pp->group, pnvl);
+					nvlist_free(pnvl);
+					continue;
+				}
+			}
+			if (topo_fmri_getprop(thp, nvl, pp->group, pp->prop,
+			    NULL, &pnvl, &err) < 0) {
+				(void) fprintf(stderr, "%s: failed to get "
+				    "%s.%s: %s\n", g_pname,
+				    pp->group, pp->prop,
+				    topo_strerror(err));
+				continue;
+			} else {
+				print_fmri_pgroup(thp, pp->group, pnvl);
+				print_prop_nameval(thp, pnvl);
+				nvlist_free(nvl);
+			}
+		} else {
+			set_prop(thp, NULL, nvl, pp);
+		}
+	}
+}
+
+void
+print_fmri(topo_hdl_t *thp, char *uuid)
+{
+	int ret, err;
+	nvlist_t *nvl;
+	char buf[32];
+	time_t tod = time(NULL);
+
+	if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
+		(void) fprintf(stderr, "%s: failed to convert %s to nvlist: "
+		    "%s\n", g_pname, g_fmri, topo_strerror(err));
+		return;
+	}
+
+	printf("TIME                 UUID\n");
+	(void) strftime(buf, sizeof (buf), "%b %d %T", localtime(&tod));
+	(void) printf("%-15s %-32s\n", buf, uuid);
+	(void) printf("\n");
+
+	(void) printf("%s\n", (char *)g_fmri);
+
+	if (opt_p && !(pcnt > 0 || opt_V || opt_all)) {
+		char *aname = NULL, *fname = NULL, *lname = NULL;
+		nvlist_t *asru = NULL;
+		nvlist_t *fru = NULL;
+
+		if (topo_fmri_asru(thp, nvl, &asru, &err) == 0)
+		    (void) topo_fmri_nvl2str(thp, asru, &aname, &err);
+		if (topo_fmri_fru(thp, nvl, &fru, &err) == 0)
+		    (void) topo_fmri_nvl2str(thp, fru, &fname, &err);
+		(void) topo_fmri_label(thp, nvl, &lname, &err);
+
+		nvlist_free(fru);
+		nvlist_free(asru);
+
+		if (aname != NULL) {
+			(void) printf("\tASRU: %s\n", aname);
+			topo_hdl_strfree(thp, aname);
+		} else {
+			(void) printf("\tASRU: -\n");
+		}
+		if (fname != NULL) {
+			(void) printf("\tFRU: %s\n", fname);
+			topo_hdl_strfree(thp, fname);
+		} else {
+			(void) printf("\tFRU: -\n");
+		}
+		if (lname != NULL) {
+			(void) printf("\tLabel: %s\n", lname);
+			topo_hdl_strfree(thp, lname);
+		} else {
+			(void) printf("\tLabel: -\n");
+		}
+	}
+
+	if (opt_S) {
+		if (topo_fmri_str2nvl(thp, g_fmri, &nvl, &err) < 0) {
+			(void) printf("\tPresent: -\n");
+			(void) printf("\tUnusable: -\n");
+			return;
+		}
+
+		if ((ret = topo_fmri_present(thp, nvl, &err)) < 0)
+			(void) printf("\tPresent: -\n");
+		else
+			(void) printf("\tPresent: %s\n",
+			    ret ? "true" : "false");
+
+		if ((ret = topo_fmri_unusable(thp, nvl, &err)) < 0)
+			(void) printf("\tUnusable: -\n");
+		else
+			(void) printf("\tUnusable: %s\n",
+			    ret ? "true" : "false");
+
+		nvlist_free(nvl);
+	}
+
+	if (pcnt > 0)
+		print_fmri_props(thp, nvl);
+}
+
+int
+fmtopo_exit(topo_hdl_t *thp, char *uuid, int err)
+{
+	if (uuid != NULL)
+		topo_hdl_strfree(thp, uuid);
+
+	if (thp != NULL) {
+		topo_snap_release(thp);
+		topo_close(thp);
+	}
+
+	if (pargs) {
+		int i;
+		for (i = 0; i < pcnt; ++i)
+			free(pargs[i]);
+		free(pargs);
+	}
+
+	return (err);
+}
+
+int
+main(int argc, char *argv[])
+{
+	topo_hdl_t *thp = NULL;
+	char *uuid = NULL;
+	int c, err = 0;
+
+	g_pname = argv[0];
+
+	while (optind < argc) {
+		while ((c = getopt(argc, argv, optstr)) != -1) {
+			switch (c) {
+			case 'C':
+				atexit(abort);
+				break;
+			case 'd':
+				opt_d++;
+				break;
+			case 'e':
+				opt_e++;
+				break;
+			case 'P':
+				pcnt++;
+				break;
+			case 'p':
+				opt_p++;
+				break;
+			case 'V':
+				opt_V++;
+				break;
+			case 'R':
+				opt_R = optarg;
+				break;
+			case 's':
+				opt_s = optarg;
+				break;
+			case 'S':
+				opt_S++;
+				break;
+			case 't':
+				opt_t++;
+				break;
+			case 'x':
+				opt_x++;
+				break;
+			default:
+				return (usage(stderr));
+			}
+		}
+
+		if (optind < argc) {
+			if (g_fmri != NULL) {
+				(void) fprintf(stderr, "%s: illegal argument "
+				    "-- %s\n", g_pname, argv[optind]);
+				return (FMTOPO_EXIT_USAGE);
+			} else {
+				g_fmri = argv[optind++];
+			}
+		}
+	}
+
+	if (pcnt > 0)
+		get_pargs(argc, argv);
+
+	if ((thp = topo_open(TOPO_VERSION, opt_R, &err)) == NULL) {
+		(void) fprintf(stderr, "%s: failed to open topology tree: %s\n",
+		    g_pname, topo_strerror(err));
+		return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
+	}
+
+	if (opt_d)
+		topo_debug_set(thp, "module", "stderr");
+
+	if ((uuid = topo_snap_hold(thp, NULL, &err)) == NULL) {
+		(void) fprintf(stderr, "%s: failed to snapshot topology: %s\n",
+		    g_pname, topo_strerror(err));
+		return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
+	} else if (err != 0) {
+		(void) fprintf(stderr, "%s: topology snapshot incomplete\n",
+		    g_pname);
+	}
+
+
+	if (opt_x) {
+		err = 0;
+		if (topo_xml_print(thp, stdout, opt_s, &err) < 0)
+			(void) fprintf(stderr, "%s: failed to print xml "
+			    "formatted topology:%s",  g_pname,
+			    topo_strerror(err));
+
+		return (fmtopo_exit(thp, uuid, err ? FMTOPO_EXIT_ERROR :
+		    FMTOPO_EXIT_SUCCESS));
+	}
+
+	if (opt_t || walk_topo(thp, uuid) < 0) {
+		if (g_fmri != NULL)
+			/*
+			 * Try getting some useful information
+			 */
+			print_fmri(thp, uuid);
+
+		return (fmtopo_exit(thp, uuid, FMTOPO_EXIT_ERROR));
+	}
+
+	topo_hdl_strfree(thp, uuid);
 
 	return (FMTOPO_EXIT_SUCCESS);
 }
--- a/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c	Mon Apr 23 15:34: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.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -332,6 +332,19 @@
 	return (WALK_NEXT);
 }
 
+static void
+dump_propmethod(uintptr_t addr)
+{
+	topo_propmethod_t pm;
+
+	if (mdb_vread(&pm, sizeof (pm), addr) != sizeof (pm)) {
+		mdb_warn("failed to read topo_propmethod at %p", addr);
+		return;
+	}
+
+	mdb_printf("       method: %-32s version: %-16s args: %p\n",
+	    pm.tpm_name, pm.tpm_version, pm.tpm_args);
+}
 
 /*
  * Dump the given property value. For the actual property values
@@ -373,6 +386,10 @@
 		default: type = "unknown type";
 	}
 	mdb_printf("    %-32s %-16s value: %p\n", name, type, pval.tp_val);
+
+	if (pval.tp_method != NULL)
+		dump_propmethod((uintptr_t)pval.tp_method);
+
 	return (WALK_NEXT);
 }
 
--- a/usr/src/lib/fm/topo/libtopo/Makefile.com	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/Makefile.com	Mon Apr 23 15:34:38 2007 -0700
@@ -105,6 +105,8 @@
 	sh ../common/mkerror.sh liberrors < ../common/topo_error.h > $@
 	sh ../common/mkerror.sh properrors < ../common/libtopo.h >> $@
 	sh ../common/mkerror.sh methoderrors < ../common/libtopo.h >> $@
+	sh ../common/mkerror.sh fmrierrors < ../common/libtopo.h >> $@
+	sh ../common/mkerror.sh hdlerrors < ../common/libtopo.h >> $@
 	sh ../common/mkerror.sh moderrors < ../common/topo_mod.h >> $@
 
 include ../../../../Makefile.targ
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c	Mon Apr 23 15:34:38 2007 -0700
@@ -21,7 +21,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,6 +45,7 @@
 
 #include <topo_method.h>
 #include <topo_subr.h>
+#include <topo_prop.h>
 #include <hc.h>
 
 static int hc_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
@@ -56,8 +57,18 @@
     nvlist_t *, nvlist_t **);
 static int hc_compare(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
     nvlist_t **);
+static int hc_fmri_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
+    nvlist_t **);
+static int hc_fmri_unusable(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
+    nvlist_t **);
 static int hc_fmri_create_meth(topo_mod_t *, tnode_t *, topo_version_t,
     nvlist_t *, nvlist_t **);
+static int hc_fmri_prop_get(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+static int hc_fmri_prop_set(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
+static int hc_fmri_pgrp_get(topo_mod_t *, tnode_t *, topo_version_t,
+    nvlist_t *, nvlist_t **);
 
 static nvlist_t *hc_fmri_create(topo_mod_t *, nvlist_t *, int, const char *,
     topo_instance_t inst, const nvlist_t *, const char *, const char *,
@@ -70,8 +81,22 @@
 	    TOPO_STABILITY_INTERNAL, hc_fmri_str2nvl },
 	{ TOPO_METH_COMPARE, TOPO_METH_COMPARE_DESC, TOPO_METH_COMPARE_VERSION,
 	    TOPO_STABILITY_INTERNAL, hc_compare },
+	{ TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC, TOPO_METH_PRESENT_VERSION,
+	    TOPO_STABILITY_INTERNAL, hc_fmri_present },
+	{ TOPO_METH_UNUSABLE, TOPO_METH_UNUSABLE_DESC,
+	    TOPO_METH_UNUSABLE_VERSION, TOPO_STABILITY_INTERNAL,
+	    hc_fmri_unusable },
 	{ TOPO_METH_FMRI, TOPO_METH_FMRI_DESC, TOPO_METH_FMRI_VERSION,
 	    TOPO_STABILITY_INTERNAL, hc_fmri_create_meth },
+	{ TOPO_METH_PROP_GET, TOPO_METH_PROP_GET_DESC,
+	    TOPO_METH_PROP_GET_VERSION, TOPO_STABILITY_INTERNAL,
+	    hc_fmri_prop_get },
+	{ TOPO_METH_PROP_SET, TOPO_METH_PROP_SET_DESC,
+	    TOPO_METH_PROP_SET_VERSION, TOPO_STABILITY_INTERNAL,
+	    hc_fmri_prop_set },
+	{ TOPO_METH_PGRP_GET, TOPO_METH_PGRP_GET_DESC,
+	    TOPO_METH_PGRP_GET_VERSION, TOPO_STABILITY_INTERNAL,
+	    hc_fmri_pgrp_get },
 	{ NULL }
 };
 
@@ -272,24 +297,14 @@
 	topo_method_unregister_all(mp, node);
 }
 
-/*ARGSUSED*/
 static int
-hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version,
-    nvlist_t *in, nvlist_t **out)
+fmri_compare(topo_mod_t *mod, nvlist_t *nv1, nvlist_t *nv2)
 {
 	uint8_t v1, v2;
-	nvlist_t *nv1, *nv2;
 	nvlist_t **hcp1, **hcp2;
 	int err, i;
 	uint_t nhcp1, nhcp2;
 
-	if (version > TOPO_METH_COMPARE_VERSION)
-		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
-
-	if (nvlist_lookup_nvlist(in, "nv1", &nv1) != 0 ||
-	    nvlist_lookup_nvlist(in, "nv2", &nv2) != 0)
-		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
-
 	if (nvlist_lookup_uint8(nv1, FM_VERSION, &v1) != 0 ||
 	    nvlist_lookup_uint8(nv2, FM_VERSION, &v2) != 0 ||
 	    v1 > FM_HC_SCHEME_VERSION || v2 > FM_HC_SCHEME_VERSION)
@@ -325,6 +340,38 @@
 	return (1);
 }
 
+/*ARGSUSED*/
+static int
+hc_compare(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	int ret;
+	uint32_t compare;
+	nvlist_t *nv1, *nv2;
+
+	if (version > TOPO_METH_COMPARE_VERSION)
+		return (topo_mod_seterrno(mod, EMOD_VER_NEW));
+
+	if (nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv1) != 0 ||
+	    nvlist_lookup_nvlist(in, TOPO_METH_FMRI_ARG_NV1, &nv2) != 0)
+		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+
+	ret = fmri_compare(mod, nv1, nv2);
+	if (ret < 0)
+		return (-1);
+
+	compare = ret;
+	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) == 0) {
+		if (nvlist_add_uint32(*out, TOPO_METH_COMPARE_RET,
+		    compare) == 0)
+			return (0);
+		else
+			nvlist_free(*out);
+	}
+
+	return (-1);
+}
+
 static ssize_t
 fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen)
 {
@@ -518,12 +565,12 @@
 	char *hc, *fromstr;
 	char *starti, *startn, *endi, *endi2;
 	char *ne, *ns;
-	char *cname;
+	char *cname = NULL;
 	char *find;
-	char *cid;
+	char *cid = NULL;
 	int nslashes = 0;
 	int npairs = 0;
-	int i, e;
+	int i;
 
 	if ((hc = topo_mod_strdup(mod, fmri + 5)) == NULL)
 		return (NULL);
@@ -561,7 +608,11 @@
 
 	find = fromstr;
 
-	pa = topo_mod_alloc(mod, npairs * sizeof (nvlist_t *));
+	if ((pa = topo_mod_alloc(mod, npairs * sizeof (nvlist_t *))) == NULL) {
+		topo_mod_strfree(mod, hc);
+		return (NULL);
+	}
+
 	/*
 	 * We go through a pretty complicated procedure to find the
 	 * name and id for each pair.  That's because, unfortunately,
@@ -581,7 +632,8 @@
 		if (starti == NULL)
 			break;
 		*starti = '\0';
-		cname = topo_mod_strdup(mod, startn);
+		if ((cname = topo_mod_strdup(mod, startn)) == NULL)
+			break;
 		*starti++ = '=';
 		endi = strchr(starti, '=');
 		if (endi != NULL) {
@@ -591,33 +643,34 @@
 				break;
 			*endi = '=';
 			*endi2 = '\0';
-			cid = topo_mod_strdup(mod, starti);
+			if ((cid = topo_mod_strdup(mod, starti)) == NULL)
+				break;
 			*endi2 = '/';
 			find = endi2;
 		} else {
-			cid = topo_mod_strdup(mod, starti);
+			if ((cid = topo_mod_strdup(mod, starti)) == NULL)
+				break;
 			find = starti + strlen(starti);
 		}
-		if ((e = topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME)) != 0) {
-			topo_mod_strfree(mod, cname);
-			topo_mod_strfree(mod, cid);
+		if (topo_mod_nvalloc(mod, &pa[i], NV_UNIQUE_NAME) < 0)
 			break;
-		}
 
-		e = nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname);
-		e |= nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid);
+		if (nvlist_add_string(pa[i], FM_FMRI_HC_NAME, cname) ||
+		    nvlist_add_string(pa[i], FM_FMRI_HC_ID, cid))
+			break;
 
 		topo_mod_strfree(mod, cname);
 		topo_mod_strfree(mod, cid);
+		cname = NULL;
+		cid = NULL;
+	}
 
-		if (e != 0) {
-			break;
-		}
-	}
+	topo_mod_strfree(mod, cname);
+	topo_mod_strfree(mod, cid);
+
 	if (i < npairs) {
 		while (i >= 0)
-			if (pa[i--] != NULL)
-				nvlist_free(pa[i + 1]);
+			nvlist_free(pa[i + 1]);
 		topo_mod_free(mod, pa, npairs * sizeof (nvlist_t *));
 		topo_mod_strfree(mod, hc);
 		return (NULL);
@@ -966,3 +1019,465 @@
 		return (-1);
 	return (0);
 }
+
+struct hc_walk {
+	topo_mod_walk_cb_t hcw_cb;
+	void *hcw_priv;
+	topo_walk_t *hcw_wp;
+	nvlist_t **hcw_list;
+	uint_t hcw_index;
+	uint_t hcw_end;
+};
+
+/*
+ * Generic walker for the hc-scheme topo tree.  This function uses the
+ * hierachical nature of the hc-scheme to step through efficiently through
+ * the topo hc tree.  Node lookups are done by topo_walk_byid() at each
+ * component level to avoid unnecessary traversal of the tree.
+ *
+ */
+static int
+hc_walker(topo_mod_t *mod, tnode_t *node, void *pdata)
+{
+	int i, err;
+	struct hc_walk *hwp = (struct hc_walk *)pdata;
+	char *name, *id;
+	topo_instance_t inst;
+
+	i = hwp->hcw_index;
+	if (i > hwp->hcw_end) {
+		(void) topo_mod_seterrno(mod, ETOPO_PROP_NOENT);
+		return (TOPO_WALK_TERMINATE);
+	}
+
+	err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
+	err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
+
+	if (err != 0) {
+		(void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+		return (TOPO_WALK_ERR);
+	}
+
+	inst = atoi(id);
+	topo_mod_dprintf(mod, "hc_walker: walking node:%s=%d for hc:"
+	    "%s=%d at %d, end at %d \n", topo_node_name(node),
+	    topo_node_instance(node), name, inst, i, hwp->hcw_end);
+	if (i == hwp->hcw_end) {
+		/*
+		 * We are at the end of the hc-list.  Verify that
+		 * the last node contains the name/instance we are looking for.
+		 */
+		if (strcmp(topo_node_name(node), name) == 0 &&
+		    inst == topo_node_instance(node)) {
+			if ((err = hwp->hcw_cb(mod, node, hwp->hcw_priv))
+			    != 0) {
+				(void) topo_mod_seterrno(mod, err);
+				topo_mod_dprintf(mod, "hc_walker: callback "
+				    "failed: %s\n ", topo_mod_errmsg(mod));
+				return (TOPO_WALK_ERR);
+			}
+			topo_mod_dprintf(mod, "hc_walker: callback "
+			    "complete: terminate walk\n");
+			return (TOPO_WALK_TERMINATE);
+		} else {
+			topo_mod_dprintf(mod, "hc_walker: %s=%d\n "
+			    "not found\n", name, inst);
+			return (TOPO_WALK_TERMINATE);
+		}
+	}
+
+	hwp->hcw_index = ++i;
+	err = nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_NAME, &name);
+	err |= nvlist_lookup_string(hwp->hcw_list[i], FM_FMRI_HC_ID, &id);
+	if (err != 0) {
+		(void) topo_mod_seterrno(mod, err);
+		return (TOPO_WALK_ERR);
+	}
+	inst = atoi(id);
+
+	topo_mod_dprintf(mod, "hc_walker: walk byid of %s=%d \n", name,
+	    inst);
+	return (topo_walk_byid(hwp->hcw_wp, name, inst));
+
+}
+
+static struct hc_walk *
+hc_walk_init(topo_mod_t *mod, tnode_t *node, nvlist_t *rsrc,
+    topo_mod_walk_cb_t cb, void *pdata)
+{
+	int err;
+	uint_t sz;
+	struct hc_walk *hwp;
+	topo_walk_t *wp;
+
+	if ((hwp = topo_mod_alloc(mod, sizeof (struct hc_walk))) == NULL)
+		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
+
+	if (nvlist_lookup_nvlist_array(rsrc, FM_FMRI_HC_LIST, &hwp->hcw_list,
+	    &sz) != 0) {
+		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
+		(void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
+		return (NULL);
+	}
+
+	hwp->hcw_end = sz - 1;
+	hwp->hcw_index = 0;
+	hwp->hcw_priv = pdata;
+	hwp->hcw_cb = cb;
+	if ((wp = topo_mod_walk_init(mod, node, hc_walker, (void *)hwp, &err))
+	    == NULL) {
+		topo_mod_free(mod, hwp, sizeof (struct hc_walk));
+		(void) topo_mod_seterrno(mod, err);
+		return (NULL);
+	}
+
+	hwp->hcw_wp = wp;
+
+	return (hwp);
+}
+
+struct prop_lookup {
+	const char *pl_pgroup;
+	const char *pl_pname;
+	int pl_flag;
+	nvlist_t *pl_args;
+	nvlist_t *pl_rsrc;
+	nvlist_t *pl_prop;
+};
+
+/*ARGSUSED*/
+static int
+hc_prop_get(topo_mod_t *mod, tnode_t *node, void *pdata)
+{
+	int err = 0;
+
+	struct prop_lookup *plp = (struct prop_lookup *)pdata;
+
+	(void) topo_prop_getprop(node, plp->pl_pgroup, plp->pl_pname,
+	    plp->pl_args, &plp->pl_prop, &err);
+
+	return (err);
+}
+
+static int
+hc_fmri_prop_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	int err;
+	struct hc_walk *hwp;
+	struct prop_lookup *plp;
+
+	if (version > TOPO_METH_PROP_GET_VERSION)
+		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
+
+	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
+	    (char **)&plp->pl_pgroup);
+	err |= nvlist_lookup_string(in, TOPO_PROP_VAL_NAME,
+	    (char **)&plp->pl_pname);
+	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
+	if (err != 0) {
+		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
+		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+	}
+
+	/*
+	 * Private args to prop method are optional
+	 */
+	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
+	    != 0) {
+		if (err != ENOENT) {
+			topo_mod_free(mod, plp, sizeof (struct prop_lookup));
+			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+		} else {
+			plp->pl_args = NULL;
+		}
+	}
+
+	plp->pl_prop = NULL;
+	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_get,
+	    (void *)plp)) != NULL) {
+		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
+		    TOPO_WALK_ERR)
+			err = -1;
+		else
+			err = 0;
+		topo_walk_fini(hwp->hcw_wp);
+	} else {
+		err = -1;
+	}
+
+	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
+
+	if (plp->pl_prop != NULL)
+		*out = plp->pl_prop;
+
+	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
+
+	return (err);
+}
+
+/*ARGSUSED*/
+static int
+hc_pgrp_get(topo_mod_t *mod, tnode_t *node, void *pdata)
+{
+	int err = 0;
+
+	struct prop_lookup *plp = (struct prop_lookup *)pdata;
+
+	(void) topo_prop_getpgrp(node, plp->pl_pgroup, &plp->pl_prop, &err);
+
+	return (err);
+}
+
+static int
+hc_fmri_pgrp_get(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	int err;
+	struct hc_walk *hwp;
+	struct prop_lookup *plp;
+
+	if (version > TOPO_METH_PGRP_GET_VERSION)
+		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
+
+	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
+	    (char **)&plp->pl_pgroup);
+	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
+	if (err != 0) {
+		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
+		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+	}
+
+	plp->pl_prop = NULL;
+	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_pgrp_get,
+	    (void *)plp)) != NULL) {
+		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
+		    TOPO_WALK_ERR)
+			err = -1;
+		else
+			err = 0;
+		topo_walk_fini(hwp->hcw_wp);
+	} else {
+		err = -1;
+	}
+
+	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
+
+	if (plp->pl_prop != NULL)
+		*out = plp->pl_prop;
+
+	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
+
+	return (err);
+}
+
+/*ARGSUSED*/
+static int
+hc_prop_setprop(topo_mod_t *mod, tnode_t *node, void *pdata)
+{
+	int err = 0;
+
+	struct prop_lookup *plp = (struct prop_lookup *)pdata;
+
+	(void) topo_prop_setprop(node, plp->pl_pgroup, plp->pl_prop,
+	    plp->pl_flag, plp->pl_args, &err);
+
+	return (err);
+}
+
+/*ARGSUSED*/
+static int
+hc_fmri_prop_set(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	int err;
+	struct hc_walk *hwp;
+	struct prop_lookup *plp;
+
+	if (version > TOPO_METH_PROP_SET_VERSION)
+		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
+
+	if ((plp = topo_mod_alloc(mod, sizeof (struct prop_lookup))) == NULL)
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+	err = nvlist_lookup_string(in, TOPO_PROP_GROUP,
+	    (char **)&plp->pl_pgroup);
+	err |= nvlist_lookup_nvlist(in, TOPO_PROP_RESOURCE, &plp->pl_rsrc);
+	err |= nvlist_lookup_nvlist(in, TOPO_PROP_VAL, &plp->pl_prop);
+	err |= nvlist_lookup_int32(in, TOPO_PROP_FLAG, &plp->pl_flag);
+	if (err != 0) {
+		topo_mod_free(mod, plp, sizeof (struct prop_lookup));
+		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+	}
+
+	/*
+	 * Private args to prop method are optional
+	 */
+	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &plp->pl_args))
+	    != 0) {
+		if (err != ENOENT)
+			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+		else
+			plp->pl_args = NULL;
+	}
+
+	if ((hwp = hc_walk_init(mod, node, plp->pl_rsrc, hc_prop_setprop,
+	    (void *)plp)) != NULL) {
+		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
+		    TOPO_WALK_ERR)
+			err = -1;
+		else
+			err = 0;
+		topo_walk_fini(hwp->hcw_wp);
+	} else {
+		err = -1;
+	}
+
+	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
+	topo_mod_free(mod, plp, sizeof (struct prop_lookup));
+
+	return (err);
+}
+
+struct hc_args {
+	nvlist_t *ha_fmri;
+	nvlist_t *ha_nvl;
+};
+
+static int
+hc_is_present(topo_mod_t *mod, tnode_t *node, void *pdata)
+{
+	int err;
+	struct hc_args *hap = (struct hc_args *)pdata;
+
+	/*
+	 * check with the enumerator that created this FMRI
+	 * (topo node)
+	 */
+	if (topo_method_invoke(node, TOPO_METH_PRESENT,
+	    TOPO_METH_PRESENT_VERSION, hap->ha_fmri, &hap->ha_nvl,
+	    &err) < 0) {
+
+		/*
+		 * Err on the side of caution and return present
+		 */
+		if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0)
+			if (nvlist_add_uint32(hap->ha_nvl,
+			    TOPO_METH_PRESENT_RET, 1) == 0)
+				return (0);
+
+		return (ETOPO_PROP_NVL);
+	}
+
+	return (err);
+}
+
+static int
+hc_fmri_present(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	int err;
+	struct hc_walk *hwp;
+	struct hc_args *hap;
+
+	if (version > TOPO_METH_PRESENT_VERSION)
+		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
+
+	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+	hap->ha_fmri = in;
+	hap->ha_nvl = NULL;
+	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_is_present,
+	    (void *)hap)) != NULL) {
+		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
+		    TOPO_WALK_ERR)
+			err = -1;
+		else
+			err = 0;
+		topo_walk_fini(hwp->hcw_wp);
+	} else {
+		err = -1;
+	}
+
+	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
+
+	if (hap->ha_nvl != NULL)
+		*out = hap->ha_nvl;
+
+	topo_mod_free(mod, hap, sizeof (struct hc_args));
+
+	return (err);
+}
+
+static int
+hc_unusable(topo_mod_t *mod, tnode_t *node, void *pdata)
+{
+	int err;
+	struct hc_args *hap = (struct hc_args *)pdata;
+
+	/*
+	 * check with the enumerator that created this FMRI
+	 * (topo node)
+	 */
+	if (topo_method_invoke(node, TOPO_METH_UNUSABLE,
+	    TOPO_METH_UNUSABLE_VERSION, hap->ha_fmri, &hap->ha_nvl,
+	    &err) < 0) {
+
+		/*
+		 * Err on the side of caution and return usable
+		 */
+		if (topo_mod_nvalloc(mod, &hap->ha_nvl, NV_UNIQUE_NAME) == 0)
+			if (nvlist_add_uint32(hap->ha_nvl,
+			    TOPO_METH_UNUSABLE_RET, 0) == 0)
+				return (0);
+
+		return (ETOPO_PROP_NVL);
+	}
+
+	return (err);
+}
+
+static int
+hc_fmri_unusable(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	int err;
+	struct hc_walk *hwp;
+	struct hc_args *hap;
+
+	if (version > TOPO_METH_UNUSABLE_VERSION)
+		return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
+
+	if ((hap = topo_mod_alloc(mod, sizeof (struct hc_args))) == NULL)
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+
+	hap->ha_fmri = in;
+	hap->ha_nvl = NULL;
+	if ((hwp = hc_walk_init(mod, node, hap->ha_fmri, hc_unusable,
+	    (void *)hap)) != NULL) {
+		if (topo_walk_step(hwp->hcw_wp, TOPO_WALK_CHILD) ==
+		    TOPO_WALK_ERR)
+			err = -1;
+		else
+			err = 0;
+		topo_walk_fini(hwp->hcw_wp);
+	} else {
+		err = -1;
+	}
+
+	topo_mod_free(mod, hwp, sizeof (struct hc_walk));
+
+	if (hap->ha_nvl != NULL)
+		*out = hap->ha_nvl;
+
+	topo_mod_free(mod, hap, sizeof (struct hc_args));
+
+	return (err);
+}
--- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h	Mon Apr 23 15:34:38 2007 -0700
@@ -45,60 +45,13 @@
 typedef uint32_t topo_version_t;
 
 /*
- * Topo stability attributes
- *
- * Each topology node advertises the name and data stability of each of its
- * modules and properties. (see attributes(5))
+ * The following functions, error codes and data structures are private
+ * to libtopo snapshot consumers and enumerator modules.
  */
-
-typedef enum topo_stability {
-	TOPO_STABILITY_UNKNOWN = 0,	/* private to libtopo */
-	TOPO_STABILITY_INTERNAL,	/* private to libtopo */
-	TOPO_STABILITY_PRIVATE,		/* private to Sun */
-	TOPO_STABILITY_OBSOLETE,	/* scheduled for removal */
-	TOPO_STABILITY_EXTERNAL,	/* not controlled by Sun */
-	TOPO_STABILITY_UNSTABLE,	/* new or rapidly changing */
-	TOPO_STABILITY_EVOLVING,	/* less rapidly changing */
-	TOPO_STABILITY_STABLE,		/* mature interface from Sun */
-	TOPO_STABILITY_STANDARD		/* industry standard */
-} topo_stability_t;
-
-#define	TOPO_STABILITY_MAX	TOPO_STABILITY_STANDARD	/* max valid stab */
-
-typedef enum {
-	TOPO_TYPE_INVALID = 0,
-	TOPO_TYPE_BOOLEAN,	/* boolean */
-	TOPO_TYPE_INT32,	/* int32_t */
-	TOPO_TYPE_UINT32,	/* uint32_t */
-	TOPO_TYPE_INT64,	/* int64_t */
-	TOPO_TYPE_UINT64,	/* uint64_t */
-	TOPO_TYPE_STRING,	/* const char* */
-	TOPO_TYPE_TIME,		/* uint64_t */
-	TOPO_TYPE_SIZE,		/* uint64_t */
-	TOPO_TYPE_FMRI,		/* nvlist_t */
-	TOPO_TYPE_INT32_ARRAY,	/* array of int32_t */
-	TOPO_TYPE_UINT32_ARRAY,	/* array of uint32_t */
-	TOPO_TYPE_INT64_ARRAY,	/* array of int64_t */
-	TOPO_TYPE_UINT64_ARRAY,	/* array of uint64_t */
-	TOPO_TYPE_STRING_ARRAY,	/* array of const char* */
-	TOPO_TYPE_FMRI_ARRAY	/* array of nvlist_t */
-} topo_type_t;
-
-typedef struct topo_pgroup_info {
-	const char *tpi_name;		/* property group name */
-	topo_stability_t tpi_namestab;	/* stability of group name */
-	topo_stability_t tpi_datastab;	/* stability of all property values */
-	topo_version_t tpi_version;	/* version of pgroup definition */
-} topo_pgroup_info_t;
-
-extern topo_stability_t topo_name2stability(const char *);
-extern const char *topo_stability2name(topo_stability_t);
-
 extern topo_hdl_t *topo_open(int, const char *, int *);
 extern void topo_close(topo_hdl_t *);
 extern char *topo_snap_hold(topo_hdl_t *, const char *, int *);
 extern void topo_snap_release(topo_hdl_t *);
-extern int topo_xml_print(topo_hdl_t *, FILE *, const char *scheme, int *);
 
 /*
  * Snapshot walker support
@@ -110,10 +63,16 @@
 extern int topo_walk_step(topo_walk_t *, int);
 extern void topo_walk_fini(topo_walk_t *);
 
+/*
+ * Walk status returned from walker
+ */
 #define	TOPO_WALK_ERR		-1
 #define	TOPO_WALK_NEXT		0
 #define	TOPO_WALK_TERMINATE	1
 
+/*
+ * Types of walks: depth-first (child) or breadth-first (sibling)
+ */
 #define	TOPO_WALK_CHILD		0x0001
 #define	TOPO_WALK_SIBLING	0x0002
 
@@ -131,8 +90,6 @@
     int *);
 extern int topo_fmri_label(topo_hdl_t *, nvlist_t *, char **, int *);
 extern int topo_fmri_compare(topo_hdl_t *, nvlist_t *, nvlist_t *, int *);
-extern int topo_fmri_invoke(topo_hdl_t *, nvlist_t *, topo_walk_cb_t, void *,
-    int *);
 
 /*
  * Topo node utilities: callable from topo_walk_step() callback or module
@@ -148,9 +105,6 @@
 extern int topo_method_invoke(tnode_t *node, const char *, topo_version_t,
     nvlist_t *, nvlist_t **, int *);
 
-extern int topo_pgroup_create(tnode_t *, const topo_pgroup_info_t *, int *);
-extern void topo_pgroup_destroy(tnode_t *, const char *);
-extern topo_pgroup_info_t *topo_pgroup_info(tnode_t *, const char *, int *);
 extern int topo_prop_get_int32(tnode_t *, const char *, const char *,
     int32_t *, int *);
 extern int topo_prop_get_uint32(tnode_t *, const char *, const char *,
@@ -175,32 +129,6 @@
     char ***, uint_t *, int *);
 extern int topo_prop_get_fmri_array(tnode_t *, const char *, const char *,
     nvlist_t ***, uint_t *, int *);
-extern int topo_prop_set_int32(tnode_t *, const char *, const char *, int,
-    int32_t, int *);
-extern int topo_prop_set_uint32(tnode_t *, const char *, const char *, int,
-    uint32_t, int *);
-extern int topo_prop_set_int64(tnode_t *, const char *, const char *,
-    int, int64_t, int *);
-extern int topo_prop_set_uint64(tnode_t *, const char *, const char *,
-    int, uint64_t, int *);
-extern int topo_prop_set_string(tnode_t *, const char *, const char *,
-    int, const char *, int *);
-extern int topo_prop_set_fmri(tnode_t *, const char *, const char *,
-    int, const nvlist_t *, int *);
-extern int topo_prop_set_int32_array(tnode_t *, const char *, const char *, int,
-    int32_t *, uint_t, int *);
-extern int topo_prop_set_uint32_array(tnode_t *, const char *, const char *,
-    int, uint32_t *, uint_t, int *);
-extern int topo_prop_set_int64_array(tnode_t *, const char *, const char *,
-    int, int64_t *, uint_t, int *);
-extern int topo_prop_set_uint64_array(tnode_t *, const char *, const char *,
-    int, uint64_t *, uint_t, int *);
-extern int topo_prop_set_string_array(tnode_t *, const char *, const char *,
-    int, const char **, uint_t, int *);
-extern int topo_prop_set_fmri_array(tnode_t *, const char *, const char *,
-    int, const nvlist_t **, uint_t, int *);
-extern nvlist_t *topo_prop_getprops(tnode_t *, int *err);
-extern int topo_prop_inherit(tnode_t *, const char *, const char *, int *);
 
 #define	TOPO_PROP_IMMUTABLE	0
 #define	TOPO_PROP_MUTABLE	1
@@ -221,6 +149,135 @@
 #define	TOPO_PROP_ISA		"isa"
 #define	TOPO_PROP_MACHINE	"machine"
 
+/*
+ * These enum definitions are used to define a set of error tags associated with
+ * libtopo error conditions occuring during the adminstration of
+ * properties, invocation of methods and fmri-based queries.  The shell script
+ * mkerror.sh is used to parse this file and create a corresponding topo_error.c
+ * source file.
+ *
+ * If you do something other than add a new error tag here, you may need to
+ * update the mkerror shell script as it is based upon simple regexps.
+ */
+typedef enum topo_prop_errno {
+    ETOPO_PROP_UNKNOWN = 3000, /* unknown topo prop error */
+    ETOPO_PROP_NOENT,   /* undefined property or property group */
+    ETOPO_PROP_DEFD,    /* static property already defined */
+    ETOPO_PROP_NOMEM,   /* memory limit exceeded during property allocation */
+    ETOPO_PROP_TYPE,    /* invalid property type */
+    ETOPO_PROP_NAME,    /* invalid property name */
+    ETOPO_PROP_NOINHERIT, /* can not inherit property */
+    ETOPO_PROP_NVL,	/* malformed property nvlist */
+    ETOPO_PROP_METHOD,	/* get property method failed */
+    ETOPO_PROP_END	/* end of prop errno list (to ease auto-merge) */
+} topo_prop_errno_t;
+
+typedef enum topo_method_errno {
+    ETOPO_METHOD_UNKNOWN = 3100, /* unknown topo method error */
+    ETOPO_METHOD_INVAL,		/* invalid method registration */
+    ETOPO_METHOD_NOTSUP,	/* method not supported */
+    ETOPO_METHOD_FAIL,		/* method failed */
+    ETOPO_METHOD_VEROLD,	/* app is compiled to use obsolete method */
+    ETOPO_METHOD_VERNEW,	/* app is compiled to use obsolete method */
+    ETOPO_METHOD_NOMEM,		/* memory limit exceeded during method op */
+    ETOPO_METHOD_DEFD,		/* method op already defined */
+    ETOPO_METHOD_END		/* end of method errno list */
+} topo_method_errno_t;
+
+typedef enum topo_fmri_errno {
+    ETOPO_FMRI_UNKNOWN = 3200, /* unknown topo fmri error */
+    ETOPO_FMRI_NVL,		/* nvlist allocation failure for FMRI */
+    ETOPO_FMRI_VERSION,		/* invalid FMRI scheme version */
+    ETOPO_FMRI_MALFORM,		/* malformed FMRI */
+    ETOPO_FMRI_NOMEM,		/* memory limit exceeded */
+    ETOPO_FMRI_END		/* end of fmri errno list */
+} topo_fmri_errno_t;
+
+typedef enum topo_hdl_errno {
+    ETOPO_HDL_UNKNOWN = 3300,	/* unknown topo handle error */
+    ETOPO_HDL_ABIVER,		/* handle opened with invalid ABI version */
+    ETOPO_HDL_SNAP,		/* snapshot already taken */
+    ETOPO_HDL_INVAL,		/* invalid argument specified */
+    ETOPO_HDL_UUID,		/* uuid already set */
+    ETOPO_HDL_NOMEM,		/* memory limit exceeded */
+    ETOPO_HDL_END		/* end of handle errno list */
+} topo_hdl_errno_t;
+
+extern const char *topo_strerror(int);
+extern void topo_hdl_strfree(topo_hdl_t *, char *);
+extern void topo_debug_set(topo_hdl_t *, const char *, const char *);
+
+/*
+ * The following functions and data structures to support property
+ * observability are private to the fmtopo command.
+ */
+
+/*
+ * Each topology node advertises the name and data stability of each of its
+ * modules and properties. (see attributes(5)).
+ */
+
+/*
+ * Topo stability attributes
+ */
+typedef enum topo_stability {
+	TOPO_STABILITY_UNKNOWN = 0,	/* private to libtopo */
+	TOPO_STABILITY_INTERNAL,	/* private to libtopo */
+	TOPO_STABILITY_PRIVATE,		/* private to Sun */
+	TOPO_STABILITY_OBSOLETE,	/* scheduled for removal */
+	TOPO_STABILITY_EXTERNAL,	/* not controlled by Sun */
+	TOPO_STABILITY_UNSTABLE,	/* new or rapidly changing */
+	TOPO_STABILITY_EVOLVING,	/* less rapidly changing */
+	TOPO_STABILITY_STABLE,		/* mature interface from Sun */
+	TOPO_STABILITY_STANDARD		/* industry standard */
+} topo_stability_t;
+
+#define	TOPO_STABILITY_MAX	TOPO_STABILITY_STANDARD	/* max valid stab */
+
+typedef struct topo_pgroup_info {
+	const char *tpi_name;		/* property group name */
+	topo_stability_t tpi_namestab;	/* stability of group name */
+	topo_stability_t tpi_datastab;	/* stability of all property values */
+	topo_version_t tpi_version;	/* version of pgroup definition */
+} topo_pgroup_info_t;
+
+extern topo_stability_t topo_name2stability(const char *);
+extern const char *topo_stability2name(topo_stability_t);
+extern void topo_pgroup_destroy(tnode_t *, const char *);
+extern topo_pgroup_info_t *topo_pgroup_info(tnode_t *, const char *, int *);
+
+typedef enum {
+	TOPO_TYPE_INVALID = 0,
+	TOPO_TYPE_BOOLEAN,	/* boolean */
+	TOPO_TYPE_INT32,	/* int32_t */
+	TOPO_TYPE_UINT32,	/* uint32_t */
+	TOPO_TYPE_INT64,	/* int64_t */
+	TOPO_TYPE_UINT64,	/* uint64_t */
+	TOPO_TYPE_STRING,	/* const char* */
+	TOPO_TYPE_TIME,		/* uint64_t */
+	TOPO_TYPE_SIZE,		/* uint64_t */
+	TOPO_TYPE_FMRI,		/* nvlist_t */
+	TOPO_TYPE_INT32_ARRAY,	/* array of int32_t */
+	TOPO_TYPE_UINT32_ARRAY,	/* array of uint32_t */
+	TOPO_TYPE_INT64_ARRAY,	/* array of int64_t */
+	TOPO_TYPE_UINT64_ARRAY,	/* array of uint64_t */
+	TOPO_TYPE_STRING_ARRAY,	/* array of const char* */
+	TOPO_TYPE_FMRI_ARRAY	/* array of nvlist_t */
+} topo_type_t;
+
+extern nvlist_t *topo_prop_getprops(tnode_t *, int *err);
+extern int topo_prop_getprop(tnode_t *, const char *, const char *,
+    nvlist_t *, nvlist_t **, int *);
+extern int topo_prop_getpgrp(tnode_t *, const char *, nvlist_t **, int *);
+extern int topo_prop_setprop(tnode_t *, const char *, nvlist_t *,
+    int, nvlist_t *, int *);
+extern int topo_fmri_getprop(topo_hdl_t *, nvlist_t *, const char *,
+    const char *, nvlist_t *,  nvlist_t **, int *);
+extern int topo_fmri_getpgrp(topo_hdl_t *, nvlist_t *, const char *,
+    nvlist_t **, int *);
+extern int topo_fmri_setprop(topo_hdl_t *, nvlist_t *, const char *,
+    nvlist_t *, int, nvlist_t *, int *);
+
 /* Property node NVL names used in topo_prop_getprops */
 #define	TOPO_PROP_GROUP		"property-group"
 #define	TOPO_PROP_GROUP_NAME	"property-group-name"
@@ -231,47 +288,22 @@
 #define	TOPO_PROP_VAL_NAME	"property-name"
 #define	TOPO_PROP_VAL_VAL	"property-value"
 #define	TOPO_PROP_VAL_TYPE	"property-type"
+#define	TOPO_PROP_FLAG		"property-flag"
 
 /*
- * This enum definition is used to define a set of error tags associated with
- * the libtopo various error conditions occuring during the adminstration of
- * properties.  The shell script mkerror.sh is
- * used to parse this file and create a corresponding topo_error.c source file.
- * If you do something other than add a new error tag here, you may need to
- * update the mkerror shell script as it is based upon simple regexps.
+ * ARGS list used in topo property methods
  */
-typedef enum topo_prop_errno {
-    ETOPO_PROP_UNKNOWN = 3000, /* unknown topo prop error */
-    ETOPO_PROP_NOENT,   /* undefined property or property group */
-    ETOPO_PROP_DEFD,    /* static property already defined */
-    ETOPO_PROP_NOMEM,   /* memory limit exceeded during property allocation */
-    ETOPO_PROP_TYPE,    /* invalid property type */
-    ETOPO_PROP_NOINHERIT, /* can not inherit property */
-    ETOPO_PROP_NVL,	/* malformed property nvlist */
-    ETOPO_PROP_END	/* end of prop errno list (to ease auto-merge) */
-} topo_prop_errno_t;
+#define	TOPO_PROP_ARGS	"args"
+#define	TOPO_PROP_PARGS	"private-args"
 
-/*
- * Similar to the above, this enum defines a set of errors associated with node
- * methods.
- */
-typedef enum topo_method_errno {
-    ETOPO_METHOD_UNKNOWN = 4000, /* unknown topo method error */
-    ETOPO_METHOD_INVAL, /* invalid method registration */
-    ETOPO_METHOD_NOTSUP, /* method not supported */
-    ETOPO_METHOD_FAIL  /* method failed */
-} topo_method_errno_t;
+extern int topo_xml_print(topo_hdl_t *, FILE *, const char *scheme, int *);
 
-
-extern const char *topo_strerror(int);
-extern void topo_debug_set(topo_hdl_t *, const char *, const char *);
 extern void *topo_hdl_alloc(topo_hdl_t *, size_t);
 extern void *topo_hdl_zalloc(topo_hdl_t *, size_t);
 extern void topo_hdl_free(topo_hdl_t *, void *, size_t);
 extern int topo_hdl_nvalloc(topo_hdl_t *, nvlist_t **, uint_t);
 extern int topo_hdl_nvdup(topo_hdl_t *, nvlist_t *, nvlist_t **);
 extern char *topo_hdl_strdup(topo_hdl_t *, const char *);
-extern void topo_hdl_strfree(topo_hdl_t *, char *);
 
 #ifdef __cplusplus
 }
--- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers	Mon Apr 23 15:34: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.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -35,10 +35,12 @@
 	topo_fmri_create;
 	topo_fmri_expand;
 	topo_fmri_fru;
-	topo_fmri_invoke;
+	topo_fmri_getpgrp;
+	topo_fmri_getprop;
 	topo_fmri_label;
 	topo_fmri_nvl2str;
 	topo_fmri_present;
+	topo_fmri_setprop;
 	topo_fmri_str2nvl;
 	topo_fmri_unusable;
 	topo_hdl_alloc;
@@ -104,6 +106,7 @@
 	topo_open;
 	topo_pgroup_create;
 	topo_pgroup_destroy;
+	topo_pgroup_info;
 	topo_prop_get_fmri;
 	topo_prop_get_int32;
 	topo_prop_get_int64;
@@ -116,8 +119,11 @@
 	topo_prop_get_uint64_array;
 	topo_prop_get_string_array;
 	topo_prop_get_fmri_array;
+	topo_prop_getprop;
 	topo_prop_getprops;
 	topo_prop_inherit;
+	topo_prop_method_register;
+	topo_prop_method_unregister;
 	topo_prop_set_fmri;
 	topo_prop_set_int32;
 	topo_prop_set_int64;
@@ -130,6 +136,7 @@
 	topo_prop_set_uint64_array;
 	topo_prop_set_string_array;
 	topo_prop_set_fmri_array;
+	topo_prop_setprop;
 	topo_name2stability;
 	topo_stability2name;
 	topo_snap_hold;
--- a/usr/src/lib/fm/topo/libtopo/common/mkerror.sh	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/mkerror.sh	Mon Apr 23 15:34:38 2007 -0700
@@ -34,7 +34,7 @@
 if [ $1 = "liberrors" ] ; then
 echo "\
 /*\n\
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.\n\
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.\n\
  * Use is subject to license terms.\n\
  */\n\
 \n\
@@ -111,6 +111,41 @@
 \n\
 static const int _topo_nmethoderrstrs =\n\
     sizeof (_topo_methoderrstrs) / sizeof (_topo_methoderrstrs[0]);"
+
+elif [ $1 = "fmrierrors" ] ; then
+
+echo "\
+\n\
+static const char *const _topo_fmrierrstrs[] = {"
+
+pattern='^[ ]*ETOPO_FMRI_[A-Z0-9_]*.*\* \(.*\) \*.*'
+replace='	"\1",'
+
+echo "$input" | sed -n "s/$pattern/$replace/p" || exit 1
+
+echo "\
+};\n\
+\n\
+static const int _topo_nfmrierrstrs =\n\
+    sizeof (_topo_fmrierrstrs) / sizeof (_topo_fmrierrstrs[0]);"
+
+elif [ $1 = "hdlerrors" ] ; then
+
+echo "\
+\n\
+static const char *const _topo_hdlerrstrs[] = {"
+
+pattern='^[ ]*ETOPO_HDL_[A-Z0-9_]*.*\* \(.*\) \*.*'
+replace='	"\1",'
+
+echo "$input" | sed -n "s/$pattern/$replace/p" || exit 1
+
+echo "\
+};\n\
+\n\
+static const int _topo_nhdlerrstrs =\n\
+    sizeof (_topo_hdlerrstrs) / sizeof (_topo_hdlerrstrs[0]);"
+
 else
 
 echo "\
@@ -162,7 +197,13 @@
 		s = _topo_properrstrs[err - ETOPO_PROP_UNKNOWN];
 	else if (err >= ETOPO_METHOD_UNKNOWN && (err - ETOPO_METHOD_UNKNOWN) <
 	    _topo_nmethoderrstrs)
-		s = _topo_methoderrstrs[err - ETOPO_METHOD_UNKNOWN];
+		s = _topo_methoderrstrs[err - ETOPO_PROP_UNKNOWN];
+	else if (err >= ETOPO_HDL_UNKNOWN && (err - ETOPO_HDL_UNKNOWN) <
+	    _topo_nhdlerrstrs)
+		s = _topo_hdlerrstrs[err - ETOPO_PROP_UNKNOWN];
+	else if (err >= ETOPO_FMRI_UNKNOWN && (err - ETOPO_FMRI_UNKNOWN) <
+	    _topo_nfmrierrstrs)
+		s = _topo_fmrierrstrs[err - ETOPO_PROP_UNKNOWN];
 	else
 		s = _topo_errstrs[0];
 
--- a/usr/src/lib/fm/topo/libtopo/common/topo_error.h	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_error.h	Mon Apr 23 15:34:38 2007 -0700
@@ -46,10 +46,6 @@
     ETOPO_UNKNOWN = 1000, /* unknown libtopo error */
     ETOPO_NOMEM,	/* memory limit exceeded */
     ETOPO_MODULE,	/* module detected or caused an error */
-    ETOPO_HDL_ABIVER,	/* handle opened with invalid ABI version */
-    ETOPO_HDL_SNAP,	/* snapshot already taken */
-    ETOPO_HDL_INVAL,	/* invalid argument specified */
-    ETOPO_HDL_UUID,	/* uuid already set */
     ETOPO_MOD_INIT,	/* failed to initialize module */
     ETOPO_MOD_FINI,	/* failed to uninitialize module */
     ETOPO_MOD_LOADED,	/* specified module is already loaded */
@@ -81,9 +77,6 @@
     ETOPO_ENUM_NOMAP,	/* no topology map file for enumeration */
     ETOPO_ENUM_FATAL,	/* fatal enumeration error */
     ETOPO_ENUM_RECURS,	/* recursive enumertation detected */
-    ETOPO_FMRI_NVL,	/* nvlist allocation failure for FMRI */
-    ETOPO_FMRI_VERSION, /* invalid FMRI scheme version */
-    ETOPO_FMRI_MALFORM,	/* malformed FMRI */
     ETOPO_NVL_INVAL,	/* invalid nvlist function argument */
     ETOPO_FILE_NOENT,	/* no topology file found */
     ETOPO_PRSR_BADGRP,	/* unrecognized grouping */
--- a/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_fmri.c	Mon Apr 23 15:34:38 2007 -0700
@@ -36,6 +36,35 @@
 #include <topo_subr.h>
 #include <topo_string.h>
 
+/*
+ * Topology node properties and method operations may be accessed by FMRI.
+ * The FMRI used to perform property look-ups and method operations is
+ * the FMRI contained in the matching topology node's protocol property
+ * grouping for the resource property. The full range of fmd(1M)
+ * scheme plugin operations are supported as long as a backend method is
+ * supplied by a scheme-specific enumerator or the enumerator module that
+ * created the matching topology node.  Support for fmd scheme operations
+ * include:
+ *
+ *	- expand
+ *	- present
+ *	- contains
+ *	- unusable
+ *	- nvl2str
+ *
+ * In addition, the following operations are supported per-FMRI:
+ *
+ *	- str2nvl: convert string-based FMRI to nvlist
+ *	- compare: compare two FMRIs
+ *	- asru: lookup associated ASRU property by FMRI
+ *	- fru: lookup associated FRU by FMRI
+ *	- create: an FMRI nvlist by scheme type
+ *	- propery lookup
+ *
+ * These routines may only be called by consumers of a topology snapshot.
+ * They may not be called by libtopo enumerator or method modules.
+ */
+
 /*ARGSUSED*/
 static int
 set_error(topo_hdl_t *thp, int err, int *errp, char *method, nvlist_t *nvlp)
@@ -138,41 +167,14 @@
 	return (0);
 }
 
-/* ARGSUSED */
-static int
-is_present(topo_hdl_t *thp, tnode_t *node, void *data)
-{
-	int err;
-	uint32_t present = 0;
-	nvlist_t *out = NULL;
-	nvlist_t *fmri = (nvlist_t *)data;
-
-	if (topo_method_invoke(node, TOPO_METH_PRESENT,
-	    TOPO_METH_PRESENT_VERSION, fmri, &out, &err) < 0) {
-		if (out != NULL)
-			nvlist_free(out);
-		return (present);
-	}
-
-	(void) nvlist_lookup_uint32(out, TOPO_METH_PRESENT_RET, &present);
-
-	nvlist_free(out);
-
-	return (present);
-}
-
 int
 topo_fmri_present(topo_hdl_t *thp, nvlist_t *fmri, int *err)
 {
-	int ret = 0;
 	uint32_t present = 0;
 	char *scheme;
 	nvlist_t *out = NULL;
 	tnode_t *rnode;
 
-	if (topo_fmri_invoke(thp, fmri, is_present, fmri, &ret) == 0)
-		return (ret);
-
 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
 		    TOPO_METH_PRESENT, out));
@@ -196,37 +198,43 @@
 int
 topo_fmri_contains(topo_hdl_t *thp, nvlist_t *fmri, nvlist_t *subfmri, int *err)
 {
-	int rc;
+	uint32_t contains;
 	char *scheme;
-	nvlist_t *in, *out = NULL;
+	nvlist_t *in = NULL, *out = NULL;
 	tnode_t *rnode;
 
 	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0)
 		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
-		    TOPO_METH_CONTAINS, out));
+		    TOPO_METH_CONTAINS, NULL));
 
 	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
 		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
-		    TOPO_METH_CONTAINS, out));
+		    TOPO_METH_CONTAINS, NULL));
 
 	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
-		    out));
+		    NULL));
 
-	if (nvlist_add_nvlist(in, "fmri", fmri) != 0 ||
-	    nvlist_add_nvlist(in, "subfmri", subfmri) != 0)
+	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_FMRI, fmri) != 0 ||
+	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_SUBFMRI, subfmri) != 0)
 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
-		    out));
+		    in));
 
 	if (topo_hdl_nvalloc(thp, &out, NV_UNIQUE_NAME) != 0)
 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_CONTAINS,
 		    out));
 
-	if ((rc = topo_method_invoke(rnode, TOPO_METH_CONTAINS,
-	    TOPO_METH_CONTAINS_VERSION, fmri, &out, err)) < 0)
-		return (set_error(thp, *err, err, TOPO_METH_CONTAINS, out));
+	if (topo_method_invoke(rnode, TOPO_METH_CONTAINS,
+	    TOPO_METH_CONTAINS_VERSION, in, &out, err) < 0) {
+		nvlist_free(out);
+		return (set_error(thp, *err, err, TOPO_METH_CONTAINS, in));
+	}
 
-	return (rc);
+	(void) nvlist_lookup_uint32(out, TOPO_METH_CONTAINS_RET, &contains);
+	nvlist_free(in);
+	nvlist_free(out);
+
+	return (contains);
 }
 
 int
@@ -277,175 +285,220 @@
 	return (0);
 }
 
-struct prop_lookup {
-	int pl_err;
-	topo_type_t pl_type;
-	const char *pl_group;
-	const char *pl_name;
-	nvlist_t **pl_prop;
-	nvlist_t *pl_resource;
-};
-
 static int
-prop_lookup(topo_hdl_t *thp, tnode_t *node, void *pdata)
+fmri_prop(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
+    const char *pname, nvlist_t *args, nvlist_t **prop,
+    int *err)
 {
-	int rc;
-	nvlist_t *r1;
-	struct prop_lookup *plp = (struct prop_lookup *)pdata;
-
-	if (topo_node_resource(node, &r1, &plp->pl_err) != 0)
-		return (TOPO_WALK_ERR);
+	int rv;
+	nvlist_t *in = NULL;
+	tnode_t *rnode;
+	char *scheme;
 
-	rc = topo_fmri_compare(thp, r1, plp->pl_resource, &plp->pl_err);
-	nvlist_free(r1);
-	if (rc == 0)
-		return (TOPO_WALK_NEXT);
-	if (rc < 0)
-		return (TOPO_WALK_ERR);
+	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
+		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
+		    TOPO_METH_PROP_GET, in));
 
-	/*
-	 * Special case for dynamically created ASRU and FRU
-	 */
-	if (strcmp(plp->pl_group, TOPO_PGROUP_PROTOCOL) == 0) {
-		if (strcmp(plp->pl_name, TOPO_PROP_ASRU) == 0) {
-			if (topo_node_asru(node, plp->pl_prop, plp->pl_resource,
-			    &plp->pl_err) < 0) {
-				return (TOPO_WALK_ERR);
-			}
-			return (0);
-		} else if (strcmp(plp->pl_name, TOPO_PROP_FRU) == 0) {
-			if (topo_node_fru(node, plp->pl_prop, plp->pl_resource,
-			    &plp->pl_err) < 0) {
-				return (TOPO_WALK_ERR);
-			}
-			return (0);
-		}
-	}
+	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
+		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
+		    TOPO_METH_PROP_GET, in));
 
-	switch (plp->pl_type) {
-		case TOPO_TYPE_STRING:
-		{
-			char *str;
-			if (topo_prop_get_string(node, plp->pl_group,
-			    plp->pl_name, &str, &plp->pl_err) < 0)
-				return (TOPO_WALK_ERR);
+	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
+		return (set_error(thp, ETOPO_FMRI_NVL, err,
+		    TOPO_METH_PROP_GET, in));
 
-			if (nvlist_add_string(*plp->pl_prop, "prop", str)
-			    != 0) {
-				topo_hdl_strfree(thp, str);
-				plp->pl_err = ETOPO_PROP_NVL;
-				return (TOPO_WALK_ERR);
-			}
-			topo_hdl_strfree(thp, str);
-			return (TOPO_WALK_TERMINATE);
-		}
-		default:
-			plp->pl_err = ETOPO_PROP_TYPE;
-			return (TOPO_WALK_ERR);
-	}
-
-}
-
-static int
-fmri_prop(topo_hdl_t *thp, nvlist_t *resource, const char *pgname,
-    const char *pname, topo_type_t type, nvlist_t **prop, int *err)
-{
-	int rc;
-	topo_walk_t *wp;
-	char *scheme;
-	struct prop_lookup pl;
-
-	if (nvlist_lookup_string(resource, FM_FMRI_SCHEME, &scheme)   != 0)
-		return (set_error(thp, ETOPO_METHOD_INVAL, err,
-		    "fmri_prop", NULL));
+	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
+	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
+	rv |= nvlist_add_string(in, TOPO_PROP_VAL_NAME, pname);
+	if (args != NULL)
+		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
+	if (rv != 0)
+		return (set_error(thp, ETOPO_FMRI_NVL, err,
+		    TOPO_METH_PROP_GET, in));
 
 	*prop = NULL;
-	pl.pl_resource = resource;
-	pl.pl_err = 0;
-	pl.pl_type = type;
-	pl.pl_group = pgname;
-	pl.pl_name = pname;
-	pl.pl_prop = prop;
-	if ((wp = topo_walk_init(thp, scheme, prop_lookup, &pl, err)) == NULL)
-		return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL));
+	rv = topo_method_invoke(rnode, TOPO_METH_PROP_GET,
+	    TOPO_METH_PROP_GET_VERSION, in, prop, err);
 
-	rc = topo_walk_step(wp, TOPO_WALK_CHILD);
-	topo_walk_fini(wp);
+	nvlist_free(in);
 
-	if (rc == TOPO_WALK_ERR) {
-		return (set_error(thp, pl.pl_err, err, "fmri_prop", NULL));
-	}
+	if (rv != 0)
+		return (-1); /* *err is set for us */
 
-	/*
-	 * Walk terminated without finding resource or property
-	 */
 	if (*prop == NULL)
-		return (set_error(thp, ETOPO_PROP_NOENT, err, "fmri_prop",
-		    NULL));
-
+		return (set_error(thp, ETOPO_PROP_NOENT, err,
+		    TOPO_METH_PROP_GET, NULL));
 	return (0);
 }
 
 int
 topo_fmri_asru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **asru, int *err)
 {
+	nvlist_t *ap, *prop = NULL;
 
 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU,
-	    TOPO_TYPE_FMRI, asru, err) < 0)
+	    nvl, &prop, err) < 0)
 		return (set_error(thp, *err, err, "topo_fmri_asru", NULL));
 
+	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0)
+		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_asru",
+		    prop));
+
+	if (topo_hdl_nvdup(thp, ap, asru) < 0)
+		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_asru",
+		    prop));
+
+	nvlist_free(prop);
+
 	return (0);
 }
 
 int
 topo_fmri_fru(topo_hdl_t *thp, nvlist_t *nvl, nvlist_t **fru, int *err)
 {
+	nvlist_t *fp, *prop = NULL;
 
 	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
-	    TOPO_TYPE_FMRI, fru, err) < 0)
+	    nvl, fru, err) < 0)
 		return (set_error(thp, *err, err, "topo_fmri_fru", NULL));
 
+	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0)
+		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_fru",
+		    prop));
+
+	if (topo_hdl_nvdup(thp, fp, fru) < 0)
+		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_fru",
+		    prop));
+
+	nvlist_free(prop);
+
 	return (0);
 }
 
 int
-topo_fmri_label(topo_hdl_t *thp, nvlist_t *fmri, char **label, int *err)
+topo_fmri_label(topo_hdl_t *thp, nvlist_t *nvl, char **label, int *err)
 {
-	nvlist_t *nvl, *fru;
-	char *str;
+	nvlist_t *prop = NULL;
+	char *lp;
 
-	if (topo_fmri_fru(thp, fmri, &fru, err) < 0)
+	if (fmri_prop(thp, nvl, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
+	    NULL, &prop, err) < 0)
 		return (set_error(thp, *err, err, "topo_fmri_label", NULL));
 
-	if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0)
+	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_VAL, &lp) != 0)
 		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
-		    NULL));
+		    prop));
+
+	if ((*label = topo_hdl_strdup(thp, lp)) == NULL)
+		return (set_error(thp, ETOPO_PROP_NOMEM, err, "topo_fmri_label",
+		    prop));
+
+	nvlist_free(prop);
+
+	return (0);
+}
+
+int topo_fmri_getprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
+    const char *pname, nvlist_t *args,  nvlist_t **prop,
+    int *err)
+{
+	*prop = NULL;
+
+	return (fmri_prop(thp, nvl, pg, pname, args, prop, err));
+}
 
-	if (fmri_prop(thp, fru, TOPO_PGROUP_PROTOCOL, TOPO_PROP_LABEL,
-	    TOPO_TYPE_STRING, &nvl, err) < 0) {
-		nvlist_free(fru);
-		return (set_error(thp, *err, err, "topo_fmri_label", nvl));
-	}
+int topo_fmri_setprop(topo_hdl_t *thp, nvlist_t *nvl, const char *pg,
+    nvlist_t *prop, int flag, nvlist_t *args, int *err)
+{
+	int rv;
+	nvlist_t *in = NULL, *out = NULL;
+	tnode_t *rnode;
+	char *scheme;
+
+	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme) != 0)
+		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
+		    TOPO_METH_PROP_SET, in));
+
+	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
+		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
+		    TOPO_METH_PROP_SET, in));
+
+	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
+		return (set_error(thp, ETOPO_FMRI_NVL, err,
+		    TOPO_METH_PROP_SET, in));
+
+	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, nvl);
+	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pg);
+	rv |= nvlist_add_nvlist(in, TOPO_PROP_VAL, prop);
+	rv |= nvlist_add_int32(in, TOPO_PROP_FLAG, (int32_t)flag);
+	if (args != NULL)
+		rv |= nvlist_add_nvlist(in, TOPO_PROP_PARGS, args);
+	if (rv != 0)
+		return (set_error(thp, ETOPO_FMRI_NVL, err,
+		    TOPO_METH_PROP_SET, in));
 
-	nvlist_free(fru);
+	rv = topo_method_invoke(rnode, TOPO_METH_PROP_SET,
+	    TOPO_METH_PROP_SET_VERSION, in, &out, err);
+
+	nvlist_free(in);
+
+	/* no return values */
+	if (out != NULL)
+		nvlist_free(out);
+
+	if (rv)
+		return (-1);
 
-	if (nvlist_lookup_string(nvl, "prop", &str) != 0)
-		return (set_error(thp, ETOPO_PROP_NVL, err, "topo_fmri_label",
-		    nvl));
+	return (0);
+
+}
+
+int
+topo_fmri_getpgrp(topo_hdl_t *thp, nvlist_t *rsrc, const char *pgname,
+    nvlist_t **pgroup, int *err)
+{
+	int rv;
+	nvlist_t *in = NULL;
+	tnode_t *rnode;
+	char *scheme;
 
-	if ((*label = topo_hdl_strdup(thp, str)) == NULL)
-		return (set_error(thp, ETOPO_PROP_NOMEM, err,
-		    "topo_fmri_label", nvl));
+	if (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &scheme) != 0)
+		return (set_error(thp, ETOPO_FMRI_MALFORM, err,
+		    TOPO_METH_PROP_GET, in));
+
+	if ((rnode = topo_hdl_root(thp, scheme)) == NULL)
+		return (set_error(thp, ETOPO_METHOD_NOTSUP, err,
+		    TOPO_METH_PROP_GET, in));
+
+	if (topo_hdl_nvalloc(thp, &in, NV_UNIQUE_NAME) != 0)
+		return (set_error(thp, ETOPO_FMRI_NVL, err,
+		    TOPO_METH_PROP_GET, in));
 
-	nvlist_free(nvl);
+	rv = nvlist_add_nvlist(in, TOPO_PROP_RESOURCE, rsrc);
+	rv |= nvlist_add_string(in, TOPO_PROP_GROUP, pgname);
+	if (rv != 0)
+		return (set_error(thp, ETOPO_FMRI_NVL, err,
+		    TOPO_METH_PROP_GET, in));
 
+	*pgroup = NULL;
+	rv = topo_method_invoke(rnode, TOPO_METH_PGRP_GET,
+	    TOPO_METH_PGRP_GET_VERSION, in, pgroup, err);
+
+	nvlist_free(in);
+
+	if (rv != 0)
+		return (-1); /* *err is set for us */
+
+	if (*pgroup == NULL)
+		return (set_error(thp, ETOPO_PROP_NOENT, err,
+		    TOPO_METH_PROP_GET, NULL));
 	return (0);
 }
 
 int
 topo_fmri_compare(topo_hdl_t *thp, nvlist_t *f1, nvlist_t *f2, int *err)
 {
-	int rc;
+	uint32_t compare;
 	char *scheme1, *scheme2;
 	nvlist_t *in;
 	nvlist_t *out = NULL;
@@ -469,80 +522,20 @@
 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
 		    NULL));
 
-	if (nvlist_add_nvlist(in, "nv1", f1) != 0 ||
-	    nvlist_add_nvlist(in, "nv2", f2) != 0)
+	if (nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV1, f1) != 0 ||
+	    nvlist_add_nvlist(in, TOPO_METH_FMRI_ARG_NV2, f2) != 0)
 		return (set_error(thp, ETOPO_FMRI_NVL, err, TOPO_METH_COMPARE,
 		    in));
 
-	if ((rc = topo_method_invoke(rnode, TOPO_METH_COMPARE,
-	    TOPO_METH_COMPARE_VERSION, in, &out, err)) < 0)
+	if (topo_method_invoke(rnode, TOPO_METH_COMPARE,
+	    TOPO_METH_COMPARE_VERSION, in, &out, err) < 0)
 		return (set_error(thp, *err, err, TOPO_METH_COMPARE, in));
 
+	(void) nvlist_lookup_uint32(out, TOPO_METH_COMPARE_RET, &compare);
+	nvlist_free(out);
 	nvlist_free(in);
 
-	return (rc);
-}
-
-struct topo_invoke {
-	nvlist_t *tl_resource;
-	topo_walk_cb_t tl_func;
-	int tl_ret;
-	void *tl_pdata;
-};
-
-static int
-walk_invoke(topo_hdl_t *thp, tnode_t *node, void *pdata)
-{
-	int rc;
-	struct topo_invoke *tlp = (struct topo_invoke *)pdata;
-	nvlist_t *r1, *r2 = tlp->tl_resource;
-
-	if (topo_node_resource(node, &r1, &tlp->tl_ret) != 0)
-		return (TOPO_WALK_ERR);
-
-	rc = topo_fmri_compare(thp, r1, r2, &tlp->tl_ret);
-	nvlist_free(r1);
-	if (rc == 0)
-		return (TOPO_WALK_NEXT);
-	else if (rc == -1)
-		return (TOPO_WALK_ERR);
-
-	tlp->tl_ret = tlp->tl_func(thp, node, tlp->tl_pdata);
-
-	return (TOPO_WALK_TERMINATE);
-}
-
-int
-topo_fmri_invoke(topo_hdl_t *thp, nvlist_t *nvl, topo_walk_cb_t cb_f,
-    void *pdata, int *ret)
-{
-	int err;
-	topo_walk_t *wp;
-	char *scheme;
-	struct topo_invoke tl;
-
-	if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &scheme)   != 0)
-		return (set_error(thp, ETOPO_METHOD_INVAL, ret,
-		    "topo_fmri_invoke", NULL));
-
-	tl.tl_resource = nvl;
-	tl.tl_func = cb_f;
-	tl.tl_pdata = pdata;
-	tl.tl_ret = 0;
-	if ((wp = topo_walk_init(thp, scheme, walk_invoke, &tl, &err)) == NULL)
-		return (set_error(thp, err, ret, "topo_fmri_invoke", NULL));
-
-	err = topo_walk_step(wp, TOPO_WALK_CHILD);
-	topo_walk_fini(wp);
-
-	if (err == TOPO_WALK_ERR) {
-		*ret = err;
-		return (-1);
-	}
-
-	*ret = tl.tl_ret;
-
-	return (0);
+	return (compare);
 }
 
 /*
--- a/usr/src/lib/fm/topo/libtopo/common/topo_method.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_method.c	Mon Apr 23 15:34: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.
  */
 
@@ -42,12 +42,11 @@
 #include <topo_subr.h>
 #include <topo_tree.h>
 
-static topo_imethod_t *
+topo_imethod_t *
 topo_method_lookup(tnode_t *node, const char *name)
 {
 	topo_imethod_t *mp;
 
-	topo_node_lock(node);
 	for (mp = topo_list_next(&node->tn_methods); mp != NULL;
 	    mp = topo_list_next(mp)) {
 		if (strcmp(name, mp->tim_name) == 0) {
@@ -55,7 +54,6 @@
 			return (mp);
 		}
 	}
-	topo_node_unlock(node);
 
 	return (NULL);
 }
@@ -99,6 +97,8 @@
 		topo_mod_free(mod, mp, sizeof (topo_imethod_t));
 	}
 
+	topo_node_unlock(node);
+
 	topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
 	    "method registration failed for %s: %s\n",
 	    mod->tm_name, topo_strerror(err));
@@ -117,8 +117,11 @@
 	 */
 	for (meth = &mp[0]; meth->tm_name != NULL; meth++) {
 
-		if (topo_method_lookup(node, meth->tm_name) != NULL)
+		topo_node_lock(node);
+		if (topo_method_lookup(node, meth->tm_name) != NULL) {
+			topo_node_unlock(node);
 			continue;
+		}
 
 		if (meth->tm_stability < TOPO_STABILITY_INTERNAL ||
 		    meth->tm_stability > TOPO_STABILITY_MAX ||
@@ -129,17 +132,17 @@
 		imp = topo_mod_zalloc(mod, sizeof (topo_imethod_t));
 		if (imp == NULL)
 			return (set_methregister_error(mod, node, imp,
-			    ETOPO_NOMEM));
+			    ETOPO_METHOD_NOMEM));
 
 		if ((imp->tim_name = topo_mod_strdup(mod, meth->tm_name))
 		    == NULL)
 			return (set_methregister_error(mod, node, imp,
-			    ETOPO_NOMEM));
+			    ETOPO_METHOD_NOMEM));
 
 		if ((imp->tim_desc = topo_mod_strdup(mod, meth->tm_desc))
 		    == NULL)
 			return (set_methregister_error(mod, node, imp,
-			    ETOPO_NOMEM));
+			    ETOPO_METHOD_NOMEM));
 
 
 		imp->tim_stability = meth->tm_stability;
@@ -147,7 +150,6 @@
 		imp->tim_func = meth->tm_func;
 		imp->tim_mod = mod;
 
-		topo_node_lock(node);
 		topo_list_append(&node->tn_methods, imp);
 		topo_node_unlock(node);
 
@@ -208,25 +210,22 @@
 
 
 int
-topo_method_invoke(tnode_t *node, const char *method,
+topo_method_call(tnode_t *node, const char *method,
     topo_version_t version, nvlist_t *in, nvlist_t **out, int *err)
 {
 	int rc;
 	topo_imethod_t *mp;
 
-	topo_node_hold(node);
 	for (mp = topo_list_next(&node->tn_methods); mp != NULL;
 	    mp = topo_list_next(mp)) {
 		if (strcmp(method, mp->tim_name) != 0)
 			continue;
 
 		if (version < mp->tim_version) {
-			*err = ETOPO_VER_NEW;
-			topo_node_rele(node);
+			*err = ETOPO_METHOD_VERNEW;
 			return (-1);
 		} else if (version > mp->tim_version) {
-			*err = ETOPO_VER_OLD;
-			topo_node_rele(node);
+			*err = ETOPO_METHOD_VEROLD;
 			return (-1);
 		}
 
@@ -240,14 +239,23 @@
 		}
 		topo_method_exit(mp);
 
-		topo_node_rele(node);
-
 		return (rc);
 
 	}
-	topo_node_rele(node);
 
 	*err = ETOPO_METHOD_NOTSUP;
-
 	return (-1);
 }
+
+int
+topo_method_invoke(tnode_t *node, const char *method,
+    topo_version_t version, nvlist_t *in, nvlist_t **out, int *err)
+{
+	int rc;
+
+	topo_node_hold(node);
+	rc = topo_method_call(node, method, version, in, out, err);
+	topo_node_rele(node);
+
+	return (rc);
+}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_method.h	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_method.h	Mon Apr 23 15:34:38 2007 -0700
@@ -33,6 +33,28 @@
 extern "C" {
 #endif
 
+#include <topo_list.h>
+
+typedef struct topo_imethod {
+	topo_list_t tim_list;		/* next/prev pointers */
+	pthread_mutex_t tim_lock;	/* method entry lock */
+	pthread_cond_t  tim_cv;		/* method entry cv */
+	uint_t tim_busy;		/* method entry busy indicator */
+	char *tim_name;			/* Method name */
+	topo_version_t tim_version;	/* Method version */
+	topo_stability_t tim_stability;	/* SMI stability of method */
+	char *tim_desc;			/* Method description */
+	topo_method_f *tim_func;	/* Method function */
+	struct topo_mod *tim_mod;	/* Ptr to controlling module */
+} topo_imethod_t;
+
+extern int topo_method_call(tnode_t *, const char *, topo_version_t, nvlist_t *,
+    nvlist_t **, int *);
+extern topo_imethod_t *topo_method_lookup(tnode_t *, const char *);
+extern int topo_prop_method_version_register(tnode_t *, const char *,
+    const char *, topo_type_t, const char *, topo_version_t, const nvlist_t *,
+    int *);
+
 /*
  * FMRI methods
  */
@@ -43,6 +65,9 @@
 #define	TOPO_METH_STR2NVL		"topo_str2nvl"
 #define	TOPO_METH_CONTAINS		"topo_contains"
 #define	TOPO_METH_COMPARE		"topo_compare"
+#define	TOPO_METH_PROP_GET		"topo_prop_get"
+#define	TOPO_METH_PGRP_GET		"topo_pgrp_get"
+#define	TOPO_METH_PROP_SET		"topo_prop_set"
 
 #define	TOPO_METH_FMRI_VERSION			0
 #define	TOPO_METH_FRU_COMPUTE_VERSION		0
@@ -51,14 +76,23 @@
 #define	TOPO_METH_STR2NVL_VERSION		0
 #define	TOPO_METH_CONTAINS_VERSION		0
 #define	TOPO_METH_COMPARE_VERSION		0
+#define	TOPO_METH_PROP_GET_VERSION		0
+#define	TOPO_METH_PGRP_GET_VERSION		0
+#define	TOPO_METH_PROP_SET_VERSION		0
 
-#define	TOPO_METH_ASRU_COMPUTE_DESC		"Dynamic ASRU constructor"
-#define	TOPO_METH_FRU_COMPUTE_DESC		"Dynamic FRU constructor"
-#define	TOPO_METH_FMRI_DESC			"Dynamic FMRI constructor"
-#define	TOPO_METH_NVL2STR_DESC			"FMRI to string"
-#define	TOPO_METH_STR2NVL_DESC			"string to FMRI"
-#define	TOPO_METH_CONTAINS_DESC			"FMRI contains sub-FMRI"
-#define	TOPO_METH_COMPARE_DESC			"compare two FMRIs"
+#define	TOPO_METH_ASRU_COMPUTE_DESC	"Dynamic ASRU constructor"
+#define	TOPO_METH_FRU_COMPUTE_DESC	"Dynamic FRU constructor"
+#define	TOPO_METH_FMRI_DESC		"Dynamic FMRI constructor"
+#define	TOPO_METH_NVL2STR_DESC		"FMRI to string"
+#define	TOPO_METH_STR2NVL_DESC		"string to FMRI"
+#define	TOPO_METH_CONTAINS_DESC		"FMRI contains sub-FMRI"
+#define	TOPO_METH_COMPARE_DESC		"compare two FMRIs"
+#define	TOPO_METH_PROP_GET_DESC		"get properties for FMRI"
+#define	TOPO_METH_PGRP_GET_DESC		"get property group for FMRI"
+#define	TOPO_METH_PROP_SET_DESC		"set properties for FMRI"
+
+#define	TOPO_METH_COMPARE_RET		"contains-return"
+#define	TOPO_METH_CONTAINS_RET		"contains-return"
 
 #define	TOPO_METH_FMRI_ARG_NAME		"child-name"
 #define	TOPO_METH_FMRI_ARG_INST		"child-inst"
@@ -69,6 +103,10 @@
 #define	TOPO_METH_FMRI_ARG_REV		"rev"
 #define	TOPO_METH_FMRI_ARG_SER		"serial"
 #define	TOPO_METH_FMRI_ARG_HCS		"hc-specific"
+#define	TOPO_METH_FMRI_ARG_FMRI		"fmri"
+#define	TOPO_METH_FMRI_ARG_SUBFMRI	"sub-fmri"
+#define	TOPO_METH_FMRI_ARG_NV1		"nv1"
+#define	TOPO_METH_FMRI_ARG_NV2		"nv2"
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c	Mon Apr 23 15:34: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.
  */
 
@@ -29,11 +29,15 @@
  * Topology Plugin Modules
  *
  * Topology plugin modules are shared libraries that are dlopen'd and
- * used to enumerate resources in the system.
- * They are loaded by our builtin scheme-specific plugins or other modules
- * to enumerate and create nodes for resources that are present in the system.
- * They may also export a set of resource (node) specific methods that can be
- * called on node-by-node basis.
+ * used to enumerate resources in the system and export per-node method
+ * operations.
+ *
+ * They are loaded by our builtin scheme-specific plugins, other modules or
+ * by processing a topo map XML file to enumerate and create nodes for
+ * resources that are present in the system.  They may also export a set of
+ * topology node specific methods that can be invoked directly via
+ * topo_method_invoke() or indirectly via the
+ * topo_prop_get* family of functions to access dynamic property data.
  *
  * Module Plugin API
  *
@@ -45,20 +49,39 @@
  *
  * In its enumeration callback routine, the module should search for resources
  * within its realm of resposibility and create any node ranges,
- * topo_node_range_create() or nodes, topo_node_bind().  The Enumerator
+ * topo_node_range_create() and nodes, topo_node_bind().  The Enumerator
  * module is handed a node to which it may begin attaching additional
- * topology nodes.
+ * topology nodes.  The enumerator may only access those nodes within its
+ * current scope of operation: the node passed into its enumeration op and
+ * any nodes it creates during enumeration.  If the enumerator requires walker-
+ * style access to these nodes, it must use
+ * topo_mod_walk_init()/topo_walk_step()/topo_walk_fini().
  *
  * If additional helper modules need to be loaded to complete the enumeration
  * the module may do so by calling topo_mod_load().  Enumeration may then
  * continue with the module handing off enumeration to its helper module
- * by calling topo_mod_enumerate().
+ * by calling topo_mod_enumerate().  Similarly, a module may call
+ * topo_mod_enummap() to kick-off enumeration according to a given XML
+ * topology map file.  A module *may* not cause re-entrance to itself
+ * via either of these interfaces.  If re-entry is detected an error
+ * will be returned (ETOPO_ENUM_RECURS).
  *
  * If the module registers a release callback, it will be called on a node
  * by node basis during topo_snap_rele().  Any private node data may be
  * deallocated or methods unregistered at that time.  Global module data
- * should be clean-up before or at the time that the module _topo_fini
+ * should be cleaned up before or at the time that the module _topo_fini
  * entry point is called.
+ *
+ * Module entry points and method invocations are guaranteed to be
+ * single-threaded for a given snapshot handle.  Applications may have
+ * more than one topology snapshot open at a time.  This means that the
+ * module operations and methods may be called for different module handles
+ * (topo_mod_t) asynchronously.  The enumerator should not use static or
+ * global data structures that may become inconsistent in this situation.
+ * Method operations may be re-entrant if the module invokes one of its own
+ * methods directly or via dynamic property access.  Caution should be
+ * exercised with method operations to insure that data remains consistent
+ * within the module and that deadlocks can not occur.
  */
 
 #include <pthread.h>
@@ -157,7 +180,7 @@
 	if (version != TOPO_VERSION)
 		return (set_register_error(mod, EMOD_VER_ABI));
 
-	if ((mod->tm_info = topo_mod_alloc(mod, sizeof (topo_imodinfo_t)))
+	if ((mod->tm_info = topo_mod_zalloc(mod, sizeof (topo_imodinfo_t)))
 	    == NULL)
 		return (set_register_error(mod, EMOD_NOMEM));
 	if ((mod->tm_info->tmi_ops = topo_mod_alloc(mod,
@@ -725,3 +748,17 @@
 
 	return (auth);
 }
+
+topo_walk_t *
+topo_mod_walk_init(topo_mod_t *mod, tnode_t *node, topo_mod_walk_cb_t cb_f,
+    void *pdata, int *errp)
+{
+	topo_walk_t *wp;
+	topo_hdl_t *thp = mod->tm_hdl;
+
+	if ((wp = topo_node_walk_init(thp, mod, node, (int (*)())cb_f, pdata,
+	    errp)) == NULL)
+		return (NULL);
+
+	return (wp);
+}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h	Mon Apr 23 15:34:38 2007 -0700
@@ -97,6 +97,14 @@
 extern int topo_mod_str2nvl(topo_mod_t *, const char *,  nvlist_t **);
 
 /*
+ * Snapshot walker support
+ */
+typedef int (*topo_mod_walk_cb_t)(topo_mod_t *, tnode_t *, void *);
+
+extern topo_walk_t *topo_mod_walk_init(topo_mod_t *, tnode_t *,
+    topo_mod_walk_cb_t, void *, int *);
+
+/*
  * Flags for topo_mod_memfmri
  */
 #define	TOPO_MEMFMRI_PA		0x0001	/* Valid physical address */
@@ -114,20 +122,20 @@
  * FMRI methods
  */
 #define	TOPO_METH_LABEL			"topo_label"
-#define	TOPO_METH_LABEL_DESC		"Dynamic label discovery"
+#define	TOPO_METH_LABEL_DESC		"label constructor"
 #define	TOPO_METH_LABEL_VERSION0	0
 #define	TOPO_METH_LABEL_VERSION		TOPO_METH_LABEL_VERSION0
 #define	TOPO_METH_LABEL_ARG_NVL	"label-specific"
 #define	TOPO_METH_LABEL_RET_STR	"label-string"
 
 #define	TOPO_METH_PRESENT		"topo_present"
-#define	TOPO_METH_PRESENT_DESC		"Dynamic label discovery"
+#define	TOPO_METH_PRESENT_DESC		"presence indicator"
 #define	TOPO_METH_PRESENT_VERSION0	0
 #define	TOPO_METH_PRESENT_VERSION	TOPO_METH_PRESENT_VERSION0
 #define	TOPO_METH_PRESENT_RET		"present-ret"
 
 #define	TOPO_METH_UNUSABLE		"topo_unusable"
-#define	TOPO_METH_UNUSABLE_DESC		"FMRI is unusable"
+#define	TOPO_METH_UNUSABLE_DESC		"unusable indicator"
 #define	TOPO_METH_UNUSABLE_VERSION0	0
 #define	TOPO_METH_UNUSABLE_VERSION	TOPO_METH_UNUSABLE_VERSION0
 #define	TOPO_METH_UNUSABLE_RET		"unusable-ret"
@@ -178,6 +186,43 @@
 #define	TOPO_FRU_COMPUTE	0x0002	/* Compute FRU dynamically */
 
 /*
+ * Topo property set functions
+ */
+extern int topo_prop_set_int32(tnode_t *, const char *, const char *, int,
+    int32_t, int *);
+extern int topo_prop_set_uint32(tnode_t *, const char *, const char *, int,
+    uint32_t, int *);
+extern int topo_prop_set_int64(tnode_t *, const char *, const char *,
+    int, int64_t, int *);
+extern int topo_prop_set_uint64(tnode_t *, const char *, const char *,
+    int, uint64_t, int *);
+extern int topo_prop_set_string(tnode_t *, const char *, const char *,
+    int, const char *, int *);
+extern int topo_prop_set_fmri(tnode_t *, const char *, const char *,
+    int, const nvlist_t *, int *);
+extern int topo_prop_set_int32_array(tnode_t *, const char *, const char *, int,
+    int32_t *, uint_t, int *);
+extern int topo_prop_set_uint32_array(tnode_t *, const char *, const char *,
+    int, uint32_t *, uint_t, int *);
+extern int topo_prop_set_int64_array(tnode_t *, const char *, const char *,
+    int, int64_t *, uint_t, int *);
+extern int topo_prop_set_uint64_array(tnode_t *, const char *, const char *,
+    int, uint64_t *, uint_t, int *);
+extern int topo_prop_set_string_array(tnode_t *, const char *, const char *,
+    int, const char **, uint_t, int *);
+extern int topo_prop_set_fmri_array(tnode_t *, const char *, const char *,
+    int, const nvlist_t **, uint_t, int *);
+extern int topo_prop_inherit(tnode_t *, const char *, const char *, int *);
+extern int topo_pgroup_create(tnode_t *, const topo_pgroup_info_t *, int *);
+
+/*
+ * Topo property method registration
+ */
+extern int topo_prop_method_register(tnode_t *, const char *, const char *,
+    topo_type_t, const char *, const nvlist_t *, int *);
+extern void topo_prop_method_unregister(tnode_t *, const char *, const char *);
+
+/*
  * This enum definition is used to define a set of error tags associated with
  * the module api error conditions.  The shell script mkerror.sh is
  * used to parse this file and create a corresponding topo_error.c source file.
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.map	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.map	Mon Apr 23 15:34:38 2007 -0700
@@ -1,5 +1,5 @@
 #
-# 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
@@ -70,4 +70,21 @@
 	topo_method_unregister_all = FUNCTION extern;
 	topo_method_invoke = FUNCTION extern;
 
+	topo_prop_method_register = FUNCTION extern;
+	topo_prop_method_unregister = FUNCTION extern;
+	topo_prop_set_int32 = FUNCTION extern;
+	topo_prop_set_uint32 = FUNCTION extern;
+	topo_prop_set_int64 = FUNCTION extern;
+	topo_prop_set_uint64 = FUNCTION extern;
+	topo_prop_set_string = FUNCTION extern;
+	topo_prop_set_fmri = FUNCTION extern;
+	topo_prop_set_int32_array = FUNCTION extern;
+	topo_prop_set_uint32_array = FUNCTION extern;
+	topo_prop_set_int64_array = FUNCTION extern;
+	topo_prop_set_uint64_array = FUNCTION extern;
+	topo_prop_set_string_array = FUNCTION extern;
+	topo_prop_set_fmri_array = FUNCTION extern;
+	topo_prop_inherit = FUNCTION extern;
+	topo_pgroup_create = FUNCTION extern;
+
 };
--- a/usr/src/lib/fm/topo/libtopo/common/topo_module.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_module.c	Mon Apr 23 15:34: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.
  */
 
@@ -223,6 +223,8 @@
 	if ((mod = topo_hdl_zalloc(thp, sizeof (topo_mod_t))) == NULL)
 		return (set_create_error(thp, mod, path, ETOPO_NOMEM));
 
+	mod->tm_hdl = thp;
+
 	(void) pthread_mutex_init(&mod->tm_lock, NULL);
 
 	mod->tm_name = topo_hdl_strdup(thp, name);
@@ -233,7 +235,6 @@
 		return (set_create_error(thp, mod, path, ETOPO_NOMEM));
 
 	mod->tm_mops = (topo_imodops_t *)ops;
-	mod->tm_hdl = thp;
 	mod->tm_alloc = thp->th_alloc;
 
 	/*
@@ -376,6 +377,9 @@
 	topo_modhash_t *mhp = thp->th_modhash;
 	topo_mod_t *mp, **pp;
 
+	if (mhp == NULL)
+		return;
+
 	topo_modhash_lock(mhp);
 	for (i = 0; i < TOPO_HASH_BUCKETS; ++i) {
 		pp = &mhp->mh_hash[i];
--- a/usr/src/lib/fm/topo/libtopo/common/topo_node.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_node.c	Mon Apr 23 15:34: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.
  */
 
@@ -39,17 +39,23 @@
  * may change at anytime and are protected by a per-property locking
  * strategy.
  *
- * Enumerator plugin modules may also safely access node data.  Enumeration
- * occurs only during topo_snap_hold() where a per-topo_hdl_t lock prevents
- * multi-threaded access to the topology trees.
+ * Enumerator plugin modules may also safely access topology nodes within their
+ * scope of operation: the parent node passed into the enumeration op or those
+ * nodes created by the enumerator.  Enumeration occurs only during
+ * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access
+ * to the topology trees.
  *
- * Like tree walking functions, method plugin modules have access to read-only
- * node data but may make changes to property information.
+ * Enumerator method operation functions may safely access and change topology
+ * node property data, and contruct or destroy child nodes for the node
+ * on which the operation applies.  The method may also be called to destroy
+ * the node for which the method operation is called.  This permits
+ * dynamic topology tree snapshots and partial enumerations for branches that
+ * may not be needed right away.
  *
  * Node Interfaces
  *
- * Nodes are created when an enumerator calls topo_node_bind().  Prior to the
- * call to topo_node_bind(), the caller should have reserved a range of
+ * Nodes are created when an enumerator calls topo_node_bind().  Prior to
+ * calling topo_node_bind(), the enumerator should have reserved a range of
  * node instances with topo_node_range_create().  topo_node_range_create()
  * does not allocate any node resources but creates the infrastruture
  * required for a fully populated topology level.  This allows enumerators
@@ -58,19 +64,36 @@
  * plugin.  Only when the resource has been confirmed to exist should
  * the node be bound.
  *
- * Node range and node linkage is only performed during enumeration when it
- * is safe to change node hash lists and next pointers. Nodes and node ranges
- * are deallocated when all references to the node have been released:
+ * Node range and node linkage and unlinkage is performed during enumeration and
+ * method operations when it is safe to change node hash lists. Nodes and node
+ * ranges are deallocated when all references to the node have been released:
  * last walk completes and topo_snap_rele() is called.
  *
  * Node Hash/Ranges
  *
  * Each parent node may have one or more ranges of child nodes.  Each range
- * serves as a hash list of like sibling nodes all with the same name but
+ * is uniquely named and serves as a hash list of like sibling nodes with
  * different instance numbers.  A parent may have more than one node hash
  * (child range). If that is the case, the hash lists are strung together to
  * form sibling relationships between ranges.  Hash/Ranges are sparsely
  * populated with only nodes that have represented resources in the system.
+ *
+ *	_________________
+ *	|		|
+ *      |   tnode_t	|    -----------------------------
+ *      |      tn_phash ---> |  topo_nodehash_t          |
+ *      |     (children)|    |     th_nodearr (instances)|
+ *      -----------------    |     -------------------   |
+ *                           |  ---| 0 | 1  | ...| N |   |
+ *                           |  |  -------------------   |  -------------------
+ *                           |  |  th_list (siblings) ----->| topo_nodehash_t |
+ *                           |  |                        |  -------------------
+ *                           ---|-------------------------
+ *                              |
+ *                              v
+ *                           -----------
+ *                           | tnode_t |
+ *                           -----------
  */
 
 #include <assert.h>
@@ -516,3 +539,49 @@
 {
 	return (0);
 }
+
+topo_walk_t *
+topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node,
+    int (*cb_f)(), void *pdata, int *errp)
+{
+	tnode_t *child;
+	topo_walk_t *wp;
+
+	topo_node_hold(node);
+
+	if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) {
+		*errp = ETOPO_NOMEM;
+		topo_node_rele(node);
+		return (NULL);
+	}
+
+	/*
+	 * If this is the root of the scheme tree, start with the first
+	 * child
+	 */
+	topo_node_lock(node);
+	if (node->tn_state & TOPO_NODE_ROOT) {
+		if ((child = topo_child_first(node)) == NULL) {
+			/* Nothing to walk */
+			*errp = ETOPO_WALK_EMPTY;
+			topo_node_unlock(node);
+			topo_node_rele(node);
+			return (NULL);
+		}
+		topo_node_unlock(node);
+		topo_node_hold(child);
+		wp->tw_node = child;
+	} else {
+		topo_node_unlock(node);
+		topo_node_hold(child);
+		wp->tw_node = node;
+	}
+
+	wp->tw_root = node;
+	wp->tw_cb = cb_f;
+	wp->tw_pdata = pdata;
+	wp->tw_thp = thp;
+	wp->tw_mod = mod;
+
+	return (wp);
+}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_prop.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.c	Mon Apr 23 15:34: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.
  */
 
@@ -32,6 +32,47 @@
 #include <topo_string.h>
 #include <topo_alloc.h>
 #include <topo_error.h>
+#include <topo_method.h>
+
+/*
+ * Topology nodes are permitted to contain property information.
+ * Property information is organized according to property grouping.
+ * Each property group defines a name, a stability level for that name,
+ * a stability level for all underlying property data (name, type, values),
+ * a version for the property group definition and and a list of uniquely
+ * defined properties.  Property group versions are incremented when one of
+ * the following changes occurs:
+ *	- a property name changes
+ *	- a property type changes
+ *	- a property definition is removed from the group
+ * Compatible changes such as new property definitions in the group do
+ * not require version changes.
+ *
+ * Each property defines a unique (within the group) name, a type and
+ * a value.  Properties may be statically defined as int32, uint32, int64,
+ * uint64, fmri, string or arrays of each type.  Properties may also be
+ * dynamically exported via module registered methods.  For example, a module
+ * may register a method to export an ASRU property that is dynamically
+ * contructed when a call to topo_node_fmri() is invoked for a particular
+ * topology node.
+ *
+ * Static properties are persistently attached to topology nodes during
+ * enumeration by an enumeration module or as part of XML statements in a
+ * toplogy map file using the topo_prop_set* family of routines.  Similarly,
+ * property methods are registered during enumeration or as part of
+ * statements in topololgy map files.  Set-up of property methods is performed
+ * by calling topo_prop_method_register().
+ *
+ * All properties, whether statically persisted in a snapshot or dynamically
+ * obtained, may be read via the topo_prop_get* family of interfaces.
+ * Callers wishing to receive all property groups and properties for a given
+ * node may use topo_prop_getall().  This routine returns a nested nvlist
+ * of all groupings and property (name, type, value) sets.  Groupings
+ * are defined by TOPO_PROP_GROUP (name, data stability, name stability and
+ * version) and a nested nvlist of properties (TOPO_PROP_VAL).  Each property
+ * value is defined by its name, type and value.
+ */
+static void topo_propval_destroy(topo_propval_t *);
 
 static topo_pgroup_t *
 pgroup_get(tnode_t *node, const char *pgname)
@@ -55,6 +96,9 @@
 {
 	topo_proplist_t *pvl;
 
+	if (pg == NULL)
+		return (NULL);
+
 	for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
 	    pvl = topo_list_next(pvl)) {
 		if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
@@ -64,254 +108,79 @@
 	return (NULL);
 }
 
+static int
+method_geterror(nvlist_t *nvl, int err, int *errp)
+{
+	if (nvl != NULL)
+		nvlist_free(nvl);
+
+	*errp = err;
+
+	return (-1);
+}
+
+static int
+prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm,
+    nvlist_t *pargs, int *err)
+{
+	int ret;
+	nvlist_t *args, *nvl;
+	char *name;
+	topo_type_t type;
+
+	if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 ||
+	    nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0)
+		return (method_geterror(NULL, ETOPO_PROP_NVL, err));
+
+	if (pargs != NULL)
+		if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0)
+			return (method_geterror(args, ETOPO_PROP_NVL, err));
+
+	/* Now, get the latest value */
+	if (topo_method_call(node, pm->tpm_name, pm->tpm_version,
+	    args, &nvl, err) < 0)
+		return (method_geterror(args, *err, err));
+
+	nvlist_free(args);
+
+	/* Verify the property contents */
+	ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name);
+	if (ret != 0 || strcmp(name, pv->tp_name) != 0)
+		return (method_geterror(nvl, ETOPO_PROP_NAME, err));
+
+	ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type);
+	if (ret != 0 || type != pv->tp_type)
+		return (method_geterror(nvl, ETOPO_PROP_TYPE, err));
+
+	/* Release the last value and re-assign to the new value */
+	if (pv->tp_val != NULL)
+		nvlist_free(pv->tp_val);
+	pv->tp_val = nvl;
+
+	return (0);
+}
+
 static topo_propval_t *
-topo_prop_get(tnode_t *node, const char *pgname, const char *pname, int *err)
+prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs,
+    int *err)
 {
-	topo_pgroup_t *pg = NULL;
 	topo_propval_t *pv = NULL;
 
-	if ((pg = pgroup_get(node, pgname)) == NULL) {
+	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
 		*err = ETOPO_PROP_NOENT;
 		return (NULL);
 	}
 
-	if ((pv = propval_get(pg, pname)) == NULL) {
-		*err = ETOPO_PROP_NOENT;
-		return (NULL);
+	if (pv->tp_method != NULL) {
+		if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0)
+			return (NULL);
 	}
 
 	return (pv);
 }
 
 static int
-prop_val_add(nvlist_t *nvl, topo_propval_t *pv, int *err)
-{
-	int ret = 0;
-	uint_t nelems;
-
-	if (nvlist_add_int32(nvl, TOPO_PROP_VAL_TYPE, pv->tp_type) != 0)
-		return (-1);
-
-	switch (pv->tp_type) {
-		case TOPO_TYPE_INT32:
-		{
-			int32_t val;
-			if ((ret = nvlist_lookup_int32(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val)) < 0)
-				break;
-			ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val);
-		}
-		break;
-		case TOPO_TYPE_UINT32:
-		{
-			uint32_t val;
-			if ((ret = nvlist_lookup_uint32(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val)) < 0)
-				break;
-			ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val);
-		}
-		break;
-		case TOPO_TYPE_INT64:
-		{
-			int64_t val;
-			if ((ret = nvlist_lookup_int64(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val)) < 0)
-				break;
-			ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val);
-		}
-		break;
-		case TOPO_TYPE_UINT64:
-		{
-			uint64_t val;
-			if ((ret = nvlist_lookup_uint64(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val)) < 0)
-				break;
-			ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val);
-		}
-		break;
-		case TOPO_TYPE_STRING:
-		{
-			char *val;
-			if ((ret = nvlist_lookup_string(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val)) < 0)
-				break;
-			ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, val);
-		}
-		break;
-		case TOPO_TYPE_FMRI:
-		{
-			nvlist_t *val;
-			if ((ret = nvlist_lookup_nvlist(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val)) < 0)
-				break;
-			ret =  nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, val);
-		}
-		break;
-		case TOPO_TYPE_INT32_ARRAY:
-		{
-			int32_t *val;
-			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
-				break;
-			ret = nvlist_add_int32_array(nvl, TOPO_PROP_VAL_VAL,
-			    val, nelems);
-		}
-		break;
-		case TOPO_TYPE_UINT32_ARRAY:
-		{
-			uint32_t *val;
-			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
-				break;
-			ret = nvlist_add_uint32_array(nvl, TOPO_PROP_VAL_VAL,
-			    val, nelems);
-		}
-		break;
-		case TOPO_TYPE_INT64_ARRAY:
-		{
-			int64_t *val;
-			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
-				break;
-			ret = nvlist_add_int64_array(nvl, TOPO_PROP_VAL_VAL,
-			    val, nelems);
-		}
-		break;
-		case TOPO_TYPE_UINT64_ARRAY:
-		{
-			uint64_t *val;
-			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
-				break;
-			ret = nvlist_add_uint64_array(nvl, TOPO_PROP_VAL_VAL,
-			    val, nelems);
-		}
-		break;
-		case TOPO_TYPE_STRING_ARRAY:
-		{
-			char **val;
-			if ((ret = nvlist_lookup_string_array(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
-				break;
-			ret = nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL,
-			    val, nelems);
-		}
-		break;
-		case TOPO_TYPE_FMRI_ARRAY:
-		{
-			nvlist_t **val;
-			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
-			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
-				break;
-			ret = nvlist_add_nvlist_array(nvl, TOPO_PROP_VAL_VAL,
-			    val, nelems);
-		}
-		break;
-		default:
-			ret = ETOPO_PROP_TYPE;
-	}
-
-	if (ret != 0) {
-		if (ret == ENOMEM)
-			*err = ETOPO_NOMEM;
-		else
-			*err = ETOPO_PROP_NVL;
-		return (-1);
-	}
-
-	return (0);
-}
-
-nvlist_t *
-get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
-{
-	topo_node_unlock(node);
-
-	if (nvl != NULL)
-		nvlist_free(nvl);
-
-	*errp = err;
-
-	return (NULL);
-}
-
-nvlist_t *
-topo_prop_getprops(tnode_t *node, int *err)
-{
-	int ret;
-	topo_hdl_t *thp = node->tn_hdl;
-	nvlist_t *nvl, *pgnvl, *pvnvl;
-	topo_pgroup_t *pg;
-	topo_propval_t *pv;
-	topo_proplist_t *pvl;
-
-	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
-		return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
-	}
-
-	topo_node_lock(node);
-	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
-	    pg = topo_list_next(pg)) {
-		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
-			return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
-
-		if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
-		    pg->tpg_info->tpi_name) != 0 ||
-		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
-		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
-		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
-		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
-		    nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
-		    pg->tpg_info->tpi_version) != 0)
-			return (get_all_seterror(node, nvl, err,
-			    ETOPO_PROP_NVL));
-
-		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
-		    pvl = topo_list_next(pvl)) {
-
-			pv = pvl->tp_pval;
-			if (topo_hdl_nvalloc(thp, &pvnvl, 0)
-			    != 0) {
-				nvlist_free(pgnvl);
-				return (get_all_seterror(node, nvl, err,
-				    ETOPO_NOMEM));
-			}
-			if ((ret = nvlist_add_string(pvnvl, TOPO_PROP_VAL_NAME,
-			    pv->tp_name)) != 0) {
-				nvlist_free(pgnvl);
-				nvlist_free(pvnvl);
-				return (get_all_seterror(node, nvl, err, ret));
-			}
-			if (prop_val_add(pvnvl, pv, err) < 0) {
-				nvlist_free(pgnvl);
-				nvlist_free(pvnvl);
-				return (get_all_seterror(node, nvl, err, ret));
-			}
-			if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
-			    pvnvl)) != 0) {
-				nvlist_free(pgnvl);
-				nvlist_free(pvnvl);
-				return (get_all_seterror(node, nvl, err, ret));
-			}
-
-			nvlist_free(pvnvl);
-		}
-		if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
-		    != 0) {
-			nvlist_free(pgnvl);
-			return (get_all_seterror(node, nvl, err, ret));
-		}
-
-		nvlist_free(pgnvl);
-	}
-
-	topo_node_unlock(node);
-
-	return (nvl);
-}
-
-static int
-get_seterror(tnode_t *node, int *errp, int err)
+get_properror(tnode_t *node, int *errp, int err)
 {
 	topo_node_unlock(node);
 	*errp = err;
@@ -327,12 +196,12 @@
 	topo_propval_t *pv;
 
 	topo_node_lock(node);
-	if ((pv = topo_prop_get(node, pgname, pname, err))
+	if ((pv = prop_get(node, pgname, pname, NULL, err))
 	    == NULL)
-		return (get_seterror(node, err, *err));
+		return (get_properror(node, err, *err));
 
 	if (pv->tp_type != type)
-		return (get_seterror(node, err, ETOPO_PROP_TYPE));
+		return (get_properror(node, err, ETOPO_PROP_TYPE));
 
 	switch (type) {
 		case TOPO_TYPE_INT32:
@@ -356,8 +225,13 @@
 
 			ret = nvlist_lookup_string(pv->tp_val,
 			    TOPO_PROP_VAL_VAL, &str);
-			if (ret == 0)
-				*(char **)val = topo_hdl_strdup(thp, str);
+			if (ret == 0) {
+				char *s2;
+				if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
+					ret = -1;
+				else
+					*(char **)val = s2;
+			}
 			break;
 		}
 		case TOPO_TYPE_FMRI: {
@@ -488,11 +362,11 @@
 
 	if (ret != 0)
 		if (ret == ENOENT)
-			return (get_seterror(node, err, ETOPO_PROP_NOENT));
+			return (get_properror(node, err, ETOPO_PROP_NOENT));
 		else if (ret < ETOPO_UNKNOWN)
-			return (get_seterror(node, err, ETOPO_PROP_NVL));
+			return (get_properror(node, err, ETOPO_PROP_NVL));
 		else
-			return (get_seterror(node, err, ret));
+			return (get_properror(node, err, ret));
 
 	topo_node_unlock(node);
 	return (0);
@@ -594,7 +468,7 @@
 	    TOPO_TYPE_FMRI_ARRAY, nelem, err));
 }
 
-static int
+static topo_propval_t *
 set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
 {
 	topo_hdl_t *thp = node->tn_hdl;
@@ -602,52 +476,40 @@
 
 	if (pvl != NULL) {
 		pv = pvl->tp_pval;
-		if (pv != NULL) {
-			if (pv->tp_name != NULL)
-				topo_hdl_strfree(thp, pv->tp_name);
-			if (pv->tp_val != NULL)
-				nvlist_free(pv->tp_val);
-			topo_hdl_free(thp, pv, sizeof (topo_propval_t));
-		}
+		topo_propval_destroy(pv);
 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
 	}
 
 	topo_node_unlock(node);
 	*errp = err;
 
-	return (-1);
+	return (NULL);
 }
 
-static int
-topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
-    topo_type_t type, int flag, void *val, int nelems, int *err)
+static topo_propval_t *
+prop_create(tnode_t *node, const char *pgname, const char *pname,
+    topo_type_t type, int flag, int *err)
 {
-	int ret, new_prop = 0;
 	topo_hdl_t *thp = node->tn_hdl;
 	topo_pgroup_t *pg;
 	topo_propval_t *pv;
 	topo_proplist_t *pvl;
 
-	topo_node_lock(node);
-	if ((pg = pgroup_get(node, pgname)) == NULL)
-		return (set_seterror(node, NULL, err, ETOPO_PROP_NOENT));
-
 	/*
 	 * Replace existing prop value with new one
 	 */
+	if ((pg = pgroup_get(node, pgname)) == NULL)
+		return (NULL);
+
 	if ((pv = propval_get(pg, pname)) != NULL) {
 		if (pv->tp_type != type)
 			return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
 		else if (pv->tp_flag == TOPO_PROP_IMMUTABLE)
 			return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
+
 		nvlist_free(pv->tp_val);
 		pv->tp_val = NULL;
 	} else {
-		/*
-		 * Property values may be a shared resources among
-		 * different nodes.  We will allocate resources
-		 * on a per-handle basis.
-		 */
 		if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
 		    == NULL)
 			return (set_seterror(node, NULL, err, ETOPO_NOMEM));
@@ -664,79 +526,104 @@
 		pv->tp_type = type;
 		pv->tp_hdl = thp;
 		topo_prop_hold(pv);
-		new_prop++;
+		topo_list_append(&pg->tpg_pvals, pvl);
 	}
 
-	if (topo_hdl_nvalloc(thp, &pv->tp_val, NV_UNIQUE_NAME) < 0)
-		return (set_seterror(node, pvl, err, ETOPO_PROP_NVL));
+	return (pv);
+}
 
-	ret = 0;
+static int
+topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
+    topo_type_t type, int flag, void *val, int nelems, int *err)
+{
+	int ret;
+	topo_hdl_t *thp = node->tn_hdl;
+	nvlist_t *nvl;
+	topo_propval_t *pv;
+
+	if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) {
+		*err = ETOPO_PROP_NVL;
+		return (-1);
+	}
+
+	ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname);
+	ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
 	switch (type) {
 		case TOPO_TYPE_INT32:
-			ret = nvlist_add_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
+			ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
 			    *(int32_t *)val);
 			break;
 		case TOPO_TYPE_UINT32:
-			ret = nvlist_add_uint32(pv->tp_val, TOPO_PROP_VAL_VAL,
+			ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
 			    *(uint32_t *)val);
 			break;
 		case TOPO_TYPE_INT64:
-			ret = nvlist_add_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
+			ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
 			    *(int64_t *)val);
 			break;
 		case TOPO_TYPE_UINT64:
-			ret = nvlist_add_uint64(pv->tp_val, TOPO_PROP_VAL_VAL,
+			ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
 			    *(uint64_t *)val);
 			break;
 		case TOPO_TYPE_STRING:
-			ret = nvlist_add_string(pv->tp_val, TOPO_PROP_VAL_VAL,
+			ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
 			    (char *)val);
 			break;
 		case TOPO_TYPE_FMRI:
-			ret = nvlist_add_nvlist(pv->tp_val, TOPO_PROP_VAL_VAL,
+			ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
 			    (nvlist_t *)val);
 			break;
 		case TOPO_TYPE_INT32_ARRAY:
-			ret = nvlist_add_int32_array(pv->tp_val,
+			ret |= nvlist_add_int32_array(nvl,
 			    TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
 			break;
 		case TOPO_TYPE_UINT32_ARRAY:
-			ret = nvlist_add_uint32_array(pv->tp_val,
+			ret |= nvlist_add_uint32_array(nvl,
 			    TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
 			break;
 		case TOPO_TYPE_INT64_ARRAY:
-			ret = nvlist_add_int64_array(pv->tp_val,
+			ret |= nvlist_add_int64_array(nvl,
 			    TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
 			break;
 		case TOPO_TYPE_UINT64_ARRAY:
-			ret = nvlist_add_uint64_array(pv->tp_val,
+			ret |= nvlist_add_uint64_array(nvl,
 			    TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
 			break;
 		case TOPO_TYPE_STRING_ARRAY:
-			ret = nvlist_add_string_array(pv->tp_val,
+			ret |= nvlist_add_string_array(nvl,
 			    TOPO_PROP_VAL_VAL, (char **)val, nelems);
 			break;
 		case TOPO_TYPE_FMRI_ARRAY:
-			ret = nvlist_add_nvlist_array(pv->tp_val,
+			ret |= nvlist_add_nvlist_array(nvl,
 			    TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
 			break;
 		default:
-			return (set_seterror(node, pvl, err, ETOPO_PROP_TYPE));
+			*err = ETOPO_PROP_TYPE;
+			return (-1);
 	}
 
 	if (ret != 0) {
-		if (ret == ENOMEM)
-			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
-		else
-			return (set_seterror(node, pvl, err, ETOPO_PROP_NVL));
+		nvlist_free(nvl);
+		if (ret == ENOMEM) {
+			*err = ETOPO_PROP_NOMEM;
+			return (-1);
+		} else {
+			*err = ETOPO_PROP_NVL;
+			return (-1);
+		}
 	}
 
-	if (new_prop > 0)
-		topo_list_append(&pg->tpg_pvals, pvl);
+	topo_node_lock(node);
+	if ((pv = prop_create(node, pgname, pname, type, flag, err)) == NULL) {
+		nvlist_free(nvl);
+		return (-1); /* unlocked and err set */
+	}
+
+	pv->tp_val = nvl;
 
 	topo_node_unlock(node);
 
-	return (0);
+	return (ret);
 }
 
 int
@@ -835,6 +722,218 @@
 	    (void *)fmri, nelems, err));
 }
 
+/*
+ * topo_prop_setprop() is a private project function for fmtopo
+ */
+int
+topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop,
+    int flag, nvlist_t *pargs, int *err)
+{
+	int ret;
+	topo_hdl_t *thp = node->tn_hdl;
+	topo_propval_t *pv;
+	nvlist_t *nvl, *args;
+	char *name;
+	topo_type_t type;
+
+	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) {
+		*err = ETOPO_PROP_NAME;
+		return (-1);
+	}
+	if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type)
+	    != 0) {
+		*err = ETOPO_PROP_TYPE;
+		return (-1);
+	}
+
+	topo_node_lock(node);
+	if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL)
+		return (-1); /* unlocked and err set */
+
+	/*
+	 * Set by method or set to new prop value.  If we fail, leave
+	 * property in list with old value.
+	 */
+	if (pv->tp_method != NULL) {
+		topo_propmethod_t *pm = pv->tp_method;
+
+		if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) {
+			topo_node_unlock(node);
+			*err = ETOPO_PROP_NOMEM;
+			return (-1);
+		}
+		ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args);
+		if (pargs != NULL)
+			ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs);
+
+		if (ret != 0) {
+			topo_node_unlock(node);
+			nvlist_free(args);
+			*err = ETOPO_PROP_NVL;
+			return (-1);
+		}
+
+		ret = topo_method_call(node, pm->tpm_name, pm->tpm_version,
+		    args, &nvl, err);
+		nvlist_free(args);
+	} else {
+		if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0)
+			*err = ETOPO_PROP_NOMEM;
+	}
+
+	if (ret != 0) {
+		topo_node_unlock(node);
+		return (-1);
+	}
+
+	pv->tp_val = nvl;
+	topo_node_unlock(node);
+	return (0);
+}
+
+static int
+register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
+    int err)
+{
+	topo_hdl_t *thp = node->tn_hdl;
+
+	if (pm != NULL) {
+		if (pm->tpm_name != NULL)
+			topo_hdl_strfree(thp, pm->tpm_name);
+		if (pm->tpm_args != NULL)
+			nvlist_free(pm->tpm_args);
+		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
+	}
+
+	*errp = err;
+
+	if (l != 0)
+		topo_node_unlock(node);
+
+	return (-1);
+}
+
+int
+prop_method_register(tnode_t *node, const char *pgname, const char *pname,
+    topo_type_t ptype, const char *mname, topo_version_t version,
+    const nvlist_t *args, int *err)
+{
+	topo_hdl_t *thp = node->tn_hdl;
+	topo_propmethod_t *pm = NULL;
+	topo_propval_t *pv = NULL;
+
+	if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL)
+		return (register_methoderror(node, pm, err, 1,
+		    ETOPO_PROP_NOMEM));
+
+	if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL)
+		return (register_methoderror(node, pm, err, 1,
+		    ETOPO_PROP_NOMEM));
+
+	pm->tpm_version = version;
+
+	if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0)
+		return (register_methoderror(node, pm, err, 1,
+		    ETOPO_PROP_NOMEM));
+
+	if ((pv = prop_create(node, pgname, pname, ptype, TOPO_PROP_MUTABLE,
+	    err)) == NULL) {
+		/* node unlocked */
+		return (register_methoderror(node, pm, err, 0, *err));
+	}
+
+	if (pv->tp_method != NULL) {
+		topo_node_unlock(node);
+		return (register_methoderror(node, pm, err, 1,
+		    ETOPO_METHOD_DEFD));
+	}
+
+	pv->tp_val = NULL;
+	pv->tp_method = pm;
+
+	topo_node_unlock(node);
+
+	return (0);
+}
+
+int
+topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname,
+    topo_type_t ptype, const char *mname, const nvlist_t *args, int *err)
+{
+	topo_imethod_t *mp;
+
+	topo_node_lock(node);
+
+	if ((mp = topo_method_lookup(node, mname)) == NULL)
+		return (register_methoderror(node, NULL, err, 1,
+		    ETOPO_METHOD_NOTSUP));
+
+	return (prop_method_register(node, pgname, pname, ptype, mname,
+	    mp->tim_version, args, err)); /* err set and node unlocked */
+}
+
+int
+topo_prop_method_version_register(tnode_t *node, const char *pgname,
+    const char *pname, topo_type_t ptype, const char *mname,
+    topo_version_t version, const nvlist_t *args, int *err)
+{
+	topo_imethod_t *mp;
+
+	topo_node_lock(node);
+
+	if ((mp = topo_method_lookup(node, mname)) == NULL)
+		return (register_methoderror(node, NULL, err, 1,
+		    ETOPO_METHOD_NOTSUP));
+
+	if (version < mp->tim_version)
+		return (register_methoderror(node, NULL, err, 1,
+		    ETOPO_METHOD_VEROLD));
+	if (version > mp->tim_version)
+		return (register_methoderror(node, NULL, err, 1,
+		    ETOPO_METHOD_VERNEW));
+
+	return (prop_method_register(node, pgname, pname, ptype, mname,
+	    version, args, err)); /* err set and node unlocked */
+}
+
+void
+topo_prop_method_unregister(tnode_t *node, const char *pgname,
+    const char *pname)
+{
+	topo_propval_t *pv;
+	topo_pgroup_t *pg;
+	topo_proplist_t *pvl;
+	topo_hdl_t *thp = node->tn_hdl;
+
+	topo_node_lock(node);
+
+	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
+	    pg = topo_list_next(pg)) {
+		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
+			break;
+		}
+	}
+
+	if (pg == NULL) {
+		topo_node_unlock(node);
+		return;
+	}
+
+	for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
+	    pvl = topo_list_next(pvl)) {
+		pv = pvl->tp_pval;
+		if (strcmp(pv->tp_name, pname) == 0) {
+			topo_list_delete(&pg->tpg_pvals, pvl);
+			assert(pv->tp_refs == 1);
+			topo_prop_rele(pv);
+			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
+			break;
+		}
+	}
+
+	topo_node_unlock(node);
+}
+
 static int
 inherit_seterror(tnode_t *node, int *errp, int err)
 {
@@ -860,10 +959,7 @@
 	/*
 	 * Check for an existing property group and prop val
 	 */
-	if ((pg = pgroup_get(pnode, pgname)) == NULL)
-		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
-
-	if ((pv = propval_get(pg, name)) == NULL)
+	if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
 
 	/*
@@ -1068,10 +1164,32 @@
 	}
 	topo_node_unlock(node);
 }
+
+static void
+propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
+{
+	topo_propmethod_t *pm;
+
+	pm = pv->tp_method;
+	if (pm != NULL) {
+		if (pm->tpm_name != NULL)
+			topo_hdl_strfree(thp, pm->tpm_name);
+		if (pm->tpm_args != NULL)
+			nvlist_free(pm->tpm_args);
+		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
+		pv->tp_method = NULL;
+	}
+}
+
 static void
 topo_propval_destroy(topo_propval_t *pv)
 {
-	topo_hdl_t *thp = pv->tp_hdl;
+	topo_hdl_t *thp;
+
+	if (pv == NULL)
+		return;
+
+	thp = pv->tp_hdl;
 
 	if (pv->tp_name != NULL)
 		topo_hdl_strfree(thp, pv->tp_name);
@@ -1079,6 +1197,8 @@
 	if (pv->tp_val != NULL)
 		nvlist_free(pv->tp_val);
 
+	propmethod_destroy(thp, pv);
+
 	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
 }
 
@@ -1098,3 +1218,199 @@
 	if (pv->tp_refs == 0)
 		topo_propval_destroy(pv);
 }
+
+/*
+ * topo_prop_getprop() and topo_prop_getprops() are private project functions
+ * for fmtopo
+ */
+int
+topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname,
+    nvlist_t *args, nvlist_t **prop, int *err)
+{
+	topo_hdl_t *thp = node->tn_hdl;
+	topo_propval_t *pv;
+
+	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);
+	}
+	topo_node_unlock(node);
+
+	return (0);
+}
+
+static int
+prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err)
+{
+	if (pv->tp_method != NULL)
+		if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0)
+			return (-1);
+
+	if (pv->tp_val == NULL) {
+		*err = ETOPO_PROP_NOENT;
+		return (-1);
+	}
+
+	if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) {
+		*err = ETOPO_PROP_NOMEM;
+		return (-1);
+	}
+
+	return (0);
+}
+
+static int
+get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
+{
+	topo_node_unlock(node);
+
+	if (nvl != NULL)
+		nvlist_free(nvl);
+
+	*errp = err;
+
+	return (-1);
+}
+
+int
+topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp,
+    int *err)
+{
+	int ret;
+	topo_hdl_t *thp = node->tn_hdl;
+	nvlist_t *nvl, *pvnvl;
+	topo_pgroup_t *pg;
+	topo_propval_t *pv;
+	topo_proplist_t *pvl;
+
+	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
+		*err = ETOPO_NOMEM;
+		return (-1);
+	}
+
+	topo_node_lock(node);
+	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
+	    pg = topo_list_next(pg)) {
+
+		if (strcmp(pgname, pg->tpg_info->tpi_name) != 0)
+			continue;
+
+		if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME,
+		    pg->tpg_info->tpi_name) != 0 ||
+		    nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB,
+		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
+		    nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB,
+		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
+		    nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION,
+		    pg->tpg_info->tpi_version) != 0)
+			return (get_pgrp_seterror(node, nvl, err,
+			    ETOPO_PROP_NVL));
+
+		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
+		    pvl = topo_list_next(pvl)) {
+
+			pv = pvl->tp_pval;
+			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
+				return (get_pgrp_seterror(node, nvl, err,
+				    *err));
+			}
+			if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL,
+			    pvnvl)) != 0) {
+				nvlist_free(pvnvl);
+				return (get_pgrp_seterror(node, nvl, err, ret));
+			}
+
+			nvlist_free(pvnvl);
+		}
+		topo_node_unlock(node);
+		*pgrp = nvl;
+		return (0);
+	}
+
+	topo_node_unlock(node);
+	*err = ETOPO_PROP_NOENT;
+	return (-1);
+}
+
+static nvlist_t *
+get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
+{
+	topo_node_unlock(node);
+
+	if (nvl != NULL)
+		nvlist_free(nvl);
+
+	*errp = err;
+
+	return (NULL);
+}
+
+nvlist_t *
+topo_prop_getprops(tnode_t *node, int *err)
+{
+	int ret;
+	topo_hdl_t *thp = node->tn_hdl;
+	nvlist_t *nvl, *pgnvl, *pvnvl;
+	topo_pgroup_t *pg;
+	topo_propval_t *pv;
+	topo_proplist_t *pvl;
+
+	topo_node_lock(node);
+	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
+		return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
+	}
+
+	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
+	    pg = topo_list_next(pg)) {
+		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
+			return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
+
+		if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
+		    pg->tpg_info->tpi_name) != 0 ||
+		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
+		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
+		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
+		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
+		    nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
+		    pg->tpg_info->tpi_version) != 0)
+			return (get_all_seterror(node, nvl, err,
+			    ETOPO_PROP_NVL));
+
+		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
+		    pvl = topo_list_next(pvl)) {
+
+			pv = pvl->tp_pval;
+			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
+				nvlist_free(pgnvl);
+				return (get_all_seterror(node, nvl, err, *err));
+			}
+			if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
+			    pvnvl)) != 0) {
+				nvlist_free(pgnvl);
+				nvlist_free(pvnvl);
+				return (get_all_seterror(node, nvl, err, ret));
+			}
+
+			nvlist_free(pvnvl);
+		}
+		if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
+		    != 0) {
+			nvlist_free(pgnvl);
+			return (get_all_seterror(node, nvl, err, ret));
+		}
+
+		nvlist_free(pgnvl);
+	}
+
+	topo_node_unlock(node);
+
+	return (nvl);
+}
--- a/usr/src/lib/fm/topo/libtopo/common/topo_prop.h	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.h	Mon Apr 23 15:34: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.
  */
 
@@ -49,6 +49,12 @@
 	topo_list_t tpg_pvals;		/* property values */
 } topo_pgroup_t;
 
+typedef struct topo_propmethod {
+	char *tpm_name;			/* property method name */
+	topo_version_t tpm_version;	/* method version */
+	nvlist_t *tpm_args;		/* in args for method */
+} topo_propmethod_t;
+
 typedef struct topo_propval {
 	char *tp_name;			/* prop name */
 	topo_type_t tp_type;		/* prop type */
@@ -57,6 +63,7 @@
 	topo_hdl_t *tp_hdl;		/* handle pointer for allocations */
 	void (*tp_free)(struct topo_propval *); /* prop value destructor */
 	nvlist_t *tp_val;
+	topo_propmethod_t *tp_method;	/* Method for accessing dynamic prop */
 } topo_propval_t;
 
 typedef struct topo_proplist {
@@ -67,6 +74,8 @@
 extern void topo_prop_hold(topo_propval_t *);
 extern void topo_prop_rele(topo_propval_t *);
 extern void topo_pgroup_destroy_all(tnode_t *);
+extern nvlist_t *topo_prop_get(tnode_t *, const char *, const char *,
+    topo_type_t, nvlist_t *, int *err);
 
 #ifdef __cplusplus
 }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_protocol.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_protocol.c	Mon Apr 23 15:34: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.
  */
 
@@ -33,91 +33,52 @@
 #include <topo_alloc.h>
 #include <topo_error.h>
 #include <topo_method.h>
+#include <topo_prop.h>
 #include <topo_protocol.h>
 #include <topo_subr.h>
 
 #include <libtopo.h>
 
-static int
-topo_compute(tnode_t *node, nvlist_t *stub, const char *method,
-    topo_version_t version, nvlist_t *rsrc, nvlist_t **asru, int *err)
+int
+topo_node_asru(tnode_t *node, nvlist_t **asru, nvlist_t *priv, int *err)
 {
-	int rc;
-	char *scheme;
-	topo_hdl_t *thp = node->tn_hdl;
-	tnode_t *rnode;
+	nvlist_t *prop, *ap;
 
-	/*
-	 * First try the originating enumerator for
-	 * a compute method.  If none is supported, try the
-	 * node's scheme-specific enumerator.
-	 */
-	if (topo_method_invoke(node, method, version, rsrc, asru, err) == 0)
-		return (0);
-
-	if (*err != ETOPO_METHOD_NOTSUP)
+	if (topo_prop_getprop(node, TOPO_PGROUP_PROTOCOL,
+	    TOPO_PROP_ASRU, priv, &prop, err) < 0)
 		return (-1);
 
-	if ((rc = nvlist_lookup_string(stub, FM_FMRI_SCHEME, &scheme)) != 0) {
-		if (rc == ENOENT) {
-			*err = ETOPO_FMRI_MALFORM;
-		} else {
-			*err = ETOPO_FMRI_NVL;
-		}
+	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &ap) != 0 ||
+	    topo_hdl_nvdup(node->tn_hdl, ap, asru) < 0) {
+		*err = ETOPO_PROP_NVL;
+		nvlist_free(prop);
 		return (-1);
 	}
 
-	if ((rnode = topo_hdl_root(thp, scheme)) == NULL) {
-		*err = ETOPO_METHOD_NOTSUP;
-		return (-1);
-	}
-
-	if (topo_method_invoke(rnode, method, version, rsrc, asru, err) != 0)
-		return (-1);
+	nvlist_free(prop);
 
 	return (0);
 }
 
 int
-topo_node_asru(tnode_t *node, nvlist_t **asru, nvlist_t *priv, int *err)
+topo_node_fru(tnode_t *node, nvlist_t **fru, nvlist_t *priv, int *err)
 {
-	int rc;
-	nvlist_t *ap;
+	nvlist_t *prop, *fp;
 
-	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_ASRU, &ap,
-	    err) != 0)
+	if (topo_prop_getprop(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU,
+	    priv, &prop, err) < 0)
 		return (-1);
 
-	if (node->tn_fflags & TOPO_ASRU_COMPUTE) {
-		rc = topo_compute(node, ap, TOPO_METH_ASRU_COMPUTE,
-		    TOPO_METH_ASRU_COMPUTE_VERSION, priv, asru, err);
-		nvlist_free(ap);
-		return (rc);
-	} else {
-		*asru = ap;
-		return (0);
+	if (nvlist_lookup_nvlist(prop, TOPO_PROP_VAL_VAL, &fp) != 0 ||
+	    topo_hdl_nvdup(node->tn_hdl, fp, fru) < 0) {
+		*err = ETOPO_PROP_NVL;
+		nvlist_free(prop);
+		return (-1);
 	}
-}
 
-int
-topo_node_fru(tnode_t *node, nvlist_t **fru, nvlist_t *priv, int *err)
-{
-	int rc;
-	nvlist_t *fp;
-
-	if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_FRU, &fp,
-	    err) != 0)
-		return (-1);
+	nvlist_free(prop);
 
-	if (node->tn_fflags & TOPO_FRU_COMPUTE) {
-		rc = topo_compute(node, fp, TOPO_METH_FRU_COMPUTE,
-		    TOPO_METH_FRU_COMPUTE_VERSION, priv, fru, err);
-		nvlist_free(fp);
-		return (rc);
-	} else {
-		*fru = fp;
-		return (0);
-	}
+	return (0);
 }
 
 int
@@ -139,24 +100,24 @@
 int
 topo_node_asru_set(tnode_t *node, nvlist_t *asru, int flag, int *err)
 {
-
 	/*
-	 * Inherit ASRU property from our parent if not specified
+	 * Inherit ASRU property from our parent if asru not specified
 	 */
 	if (asru == NULL) {
 		if (topo_prop_inherit(node, TOPO_PGROUP_PROTOCOL,
 		    TOPO_PROP_ASRU, err) < 0) {
 			return (-1);
 		}
+
+		return (0);
+	}
+
+	if (flag & TOPO_ASRU_COMPUTE) {
+		if (topo_prop_method_register(node, TOPO_PGROUP_PROTOCOL,
+		    TOPO_PROP_ASRU, TOPO_TYPE_FMRI, TOPO_METH_ASRU_COMPUTE,
+		    asru, err) < 0)
+			return (-1);
 	} else {
-		/*
-		 * ASRU must be computed on the fly.  asru will
-		 * contain the scheme module to call for the
-		 * computation
-		 */
-		if (flag & TOPO_ASRU_COMPUTE)
-			node->tn_fflags |= TOPO_ASRU_COMPUTE;
-
 		if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL,
 		    TOPO_PROP_ASRU, TOPO_PROP_IMMUTABLE, asru, err) < 0)
 			return (-1);
@@ -177,18 +138,20 @@
 		    err) < 0) {
 			return (-1);
 		}
+	}
+
+	if (flag & TOPO_FRU_COMPUTE) {
+		if (topo_prop_method_register(node, TOPO_PGROUP_PROTOCOL,
+		    TOPO_PROP_FRU, TOPO_TYPE_FMRI, TOPO_METH_FRU_COMPUTE,
+		    fru, err) < 0)
+			return (-1);
 	} else {
-		/*
-		 * FRU must be computed on the fly
-		 */
-		if (flag & TOPO_FRU_COMPUTE)
-			node->tn_fflags |= TOPO_FRU_COMPUTE;
-
 		if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL,
 		    TOPO_PROP_FRU, TOPO_PROP_IMMUTABLE, fru, err) < 0)
 			return (-1);
 	}
 
+
 	return (0);
 }
 
--- a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c	Mon Apr 23 15:34: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.
  */
 
@@ -54,14 +54,13 @@
  * which our current walk falls.  The callback function is passed in during
  * calls to topo_walk_init() and used throughout the walk_step of the
  * scheme tree.  At any time, the callback may terminate the walk by returning
- * TOPO_WALK_TERMINATE or TOPO_WALK_ERR.  TOPO_WALK_NEXT will continue the
- * walk.
+ * TOPO_WALK_TERMINATE or TOPO_WALK_ERR.  TOPO_WALK_NEXT will continue the walk.
  *
- * Walks through the tree may be breadth first or depth first by
+ * The type of walk through the tree may be breadth first or depth first by
  * respectively passing in TOPO_WALK_SIBLING or TOPO_WALK_CHILD to
- * the topo_walk_step() function.  Topology nodes associated with an
- * outstanding walk are held in place and will not be deallocated until
- * the walk through that node completes.
+ * the topo_walk_step() function.  Topology nodes
+ * associated with an outstanding walk are held in place and will not be
+ * deallocated until the walk through that node completes.
  *
  * Once the walk has terminated, the walking process should call
  * topo_walk_fini() to clean-up resources created in topo_walk_init()
@@ -163,10 +162,8 @@
 
 	(void) pthread_mutex_init(&thp->th_lock, NULL);
 
-	if ((tap = topo_zalloc(sizeof (topo_alloc_t), 0)) == NULL) {
-		topo_close(thp);
+	if ((tap = topo_zalloc(sizeof (topo_alloc_t), 0)) == NULL)
 		return (set_open_errno(thp, errp, ETOPO_NOMEM));
-	}
 
 	/*
 	 * Install default allocators
@@ -230,10 +227,8 @@
 		thp->th_product = topo_hdl_strdup(thp, thp->th_platform);
 	}
 
-	if (thp->th_rootdir == NULL) {
-		topo_close(thp);
+	if (thp->th_rootdir == NULL)
 		return (set_open_errno(thp, errp, ETOPO_NOMEM));
-	}
 
 	dbflags	 = getenv("TOPO_DEBUG");
 	dbout = getenv("TOPO_DEBUG_OUT");
@@ -445,7 +440,6 @@
 topo_walk_init(topo_hdl_t *thp, const char *scheme, topo_walk_cb_t cb_f,
     void *pdata, int *errp)
 {
-	tnode_t *child;
 	ttree_t *tp;
 	topo_walk_t *wp;
 
@@ -459,31 +453,9 @@
 			 */
 			assert(tp->tt_root != NULL);
 
-			topo_node_hold(tp->tt_root);
-
-			/*
-			 * Nothing to walk
-			 */
-			if ((child = topo_child_first(tp->tt_root)) == NULL) {
-				*errp = ETOPO_WALK_EMPTY;
-				topo_node_rele(tp->tt_root);
+			if ((wp = topo_node_walk_init(thp, NULL, tp->tt_root,
+			    cb_f, pdata, errp)) == NULL) /* errp set */
 				return (NULL);
-			}
-
-			if ((wp	= topo_hdl_zalloc(thp, sizeof (topo_walk_t)))
-			    == NULL) {
-				*errp = ETOPO_NOMEM;
-				topo_node_rele(tp->tt_root);
-				return (NULL);
-			}
-
-			topo_node_hold(child);
-
-			wp->tw_root = tp->tt_root;
-			wp->tw_node = child;
-			wp->tw_cb = cb_f;
-			wp->tw_pdata = pdata;
-			wp->tw_thp = thp;
 
 			return (wp);
 		}
@@ -501,12 +473,16 @@
 
 	nnp = topo_child_first(cnp);
 
-	if (nnp == NULL)
+	if (nnp == NULL) {
+		topo_dprintf(wp->tw_thp, TOPO_DBG_WALK,
+		    "step_child: TOPO_WALK_TERMINATE for %s=%d\n",
+		    cnp->tn_name, cnp->tn_instance);
 		return (TOPO_WALK_TERMINATE);
+	}
 
 	topo_dprintf(wp->tw_thp, TOPO_DBG_WALK,
-	    "walk through child node %s=%d\n",
-	    nnp->tn_name, nnp->tn_instance);
+	    "step_child: walk through node %s=%d to %s=%d\n",
+	    cnp->tn_name, cnp->tn_instance, nnp->tn_name, nnp->tn_instance);
 
 	topo_node_hold(nnp); /* released on return from walk_step */
 	wp->tw_node = nnp;
@@ -526,12 +502,16 @@
 
 	nnp = topo_child_next(cnp->tn_parent, cnp);
 
-	if (nnp == NULL)
+	if (nnp == NULL) {
+		topo_dprintf(wp->tw_thp, TOPO_DBG_WALK,
+		    "step_sibling: TOPO_WALK_TERMINATE for %s=%d\n",
+		    cnp->tn_name, cnp->tn_instance);
 		return (TOPO_WALK_TERMINATE);
+	}
 
 	topo_dprintf(wp->tw_thp, TOPO_DBG_WALK,
-	    "walk through sibling node %s=%d\n",
-	    nnp->tn_name, nnp->tn_instance);
+	    "step_sibling: through sibling node %s=%d to %s=%d\n",
+	    cnp->tn_name, cnp->tn_instance, nnp->tn_name, nnp->tn_instance);
 
 	topo_node_hold(nnp); /* released on return from walk_step */
 	wp->tw_node = nnp;
@@ -544,6 +524,29 @@
 }
 
 int
+topo_walk_byid(topo_walk_t *wp, const char *name, topo_instance_t inst)
+{
+	int status;
+	tnode_t *nnp, *cnp;
+
+	cnp = wp->tw_node;
+	nnp = topo_node_lookup(cnp, name, inst);
+	if (nnp == NULL)
+		return (TOPO_WALK_TERMINATE);
+
+	topo_node_hold(nnp);
+	wp->tw_node = nnp;
+	if (wp->tw_mod != NULL)
+		status = wp->tw_cb(wp->tw_mod, nnp, wp->tw_pdata);
+	else
+		status = wp->tw_cb(wp->tw_thp, nnp, wp->tw_pdata);
+	topo_node_rele(nnp);
+	wp->tw_node = cnp;
+
+	return (status);
+}
+
+int
 topo_walk_step(topo_walk_t *wp, int flag)
 {
 	int status;
@@ -555,7 +558,7 @@
 	}
 
 	/*
-	 * End of the line
+	 * No more nodes to walk
 	 */
 	if (cnp == NULL) {
 		topo_dprintf(wp->tw_thp, TOPO_DBG_WALK,
@@ -564,30 +567,32 @@
 		return (TOPO_WALK_TERMINATE);
 	}
 
-	topo_dprintf(wp->tw_thp, TOPO_DBG_WALK,
-	    "%s walk_step through node %s=%d\n",
-	    (flag == TOPO_WALK_CHILD ? "TOPO_WALK_CHILD" : "TOPO_WALK_SIBLING"),
-	    cnp->tn_name, cnp->tn_instance);
 
-	if ((status = wp->tw_cb(wp->tw_thp, cnp, wp->tw_pdata))
-	    != TOPO_WALK_NEXT) {
+	if (wp->tw_mod != NULL)
+		status = wp->tw_cb(wp->tw_mod, cnp, wp->tw_pdata);
+	else
+		status = wp->tw_cb(wp->tw_thp, cnp, wp->tw_pdata);
+
+	/*
+	 * Walker callback says we're done
+	 */
+	if (status != TOPO_WALK_NEXT) {
 		topo_node_rele(cnp);
 		return (status);
 	}
 
-	if (flag == TOPO_WALK_CHILD)
-		status = step_child(cnp, wp, 0);
-	else
-		status = step_sibling(cnp, wp, 0);
+	flag == TOPO_WALK_CHILD ? (status = step_child(cnp, wp, 0)) :
+	    (status = step_sibling(cnp, wp, 0));
 
 	/*
-	 * End of the walk, try next child or sibling
+	 * No more nodes in this hash, skip to next node hash by stepping
+	 * to next sibling (depth-first walk) or next child (breadth-first
+	 * walk).
 	 */
 	if (status == TOPO_WALK_TERMINATE) {
-		if (flag == TOPO_WALK_CHILD)
-			status = step_sibling(cnp, wp, 0);
-		else
-			status = step_child(cnp, wp, 0);
+
+		flag == TOPO_WALK_CHILD ? (status = step_sibling(cnp, wp, 0)) :
+		    (status = step_child(cnp, wp, 0));
 	}
 
 	topo_node_rele(cnp); /* done with current node */
--- a/usr/src/lib/fm/topo/libtopo/common/topo_subr.h	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_subr.h	Mon Apr 23 15:34: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.
  */
 
@@ -88,6 +88,8 @@
 extern void topo_fmristr_build(ssize_t *, char *, size_t, char *, char *,
     char *);
 
+extern int topo_walk_byid(topo_walk_t *wp, const char *name, topo_instance_t);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/lib/fm/topo/libtopo/common/topo_tree.h	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_tree.h	Mon Apr 23 15:34: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.
  */
 
@@ -33,6 +33,7 @@
 
 #include <topo_list.h>
 #include <topo_prop.h>
+#include <topo_method.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -54,19 +55,6 @@
 	topo_range_t th_range;		/* instance ranges for nodes */
 } topo_nodehash_t;
 
-typedef struct topo_imethod {
-	topo_list_t tim_list;		/* next/prev pointers */
-	pthread_mutex_t tim_lock;	/* method entry lock */
-	pthread_cond_t	tim_cv;		/* method entry cv */
-	uint_t tim_busy;		/* method entry busy indicator */
-	char *tim_name;			/* Method name */
-	topo_version_t tim_version;	/* Method version */
-	topo_stability_t tim_stability;	/* SMI stability of method */
-	char *tim_desc;			/* Method description */
-	topo_method_f *tim_func;	/* Method function */
-	struct topo_mod *tim_mod;	/* Ptr to controlling module */
-} topo_imethod_t;
-
 struct topo_node {
 	pthread_mutex_t	tn_lock;	/* lock protecting members */
 	char *tn_name;			/* Node name */
@@ -101,8 +89,9 @@
 	struct topo_hdl *tw_thp;	/* Topo handle pointer */
 	struct topo_node *tw_root;	/* Root node of current walk */
 	struct topo_node *tw_node;	/* Current walker node */
-	topo_walk_cb_t tw_cb;		/* Walker callback function */
+	int (*tw_cb)();			/* Walker callback function */
 	void *tw_pdata;			/* Private callback data */
+	topo_mod_t *tw_mod;		/* module if walking from plugin */
 };
 
 typedef struct topo_alloc {
@@ -148,6 +137,8 @@
 extern int topo_node_hash(topo_nodehash_t *, topo_instance_t);
 
 extern int topo_walk_bottomup(topo_walk_t *, int);
+extern topo_walk_t *topo_node_walk_init(topo_hdl_t *, topo_mod_t *, tnode_t *,
+    topo_walk_cb_t, void *, int *);
 
 #ifdef __cplusplus
 }
--- a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c	Mon Apr 23 15:34: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.
  */
 
@@ -838,7 +838,7 @@
 	 */
 	xmlNodePtr cn;
 	tnode_t *ct;
-	int e;
+	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));
@@ -889,7 +889,16 @@
 		if (pad_process(mp, rd->rd_finfo, rn, ct, &rd->rd_pad) < 0)
 			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, "end range process %s\n",
 	    rd->rd_name);
 	return (0);
@@ -922,7 +931,10 @@
 		}
 		if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) {
 			tf_rdata_free(mp, rr);
-			return (NULL);
+			/*
+			 * Range processing error, continue walk
+			 */
+			continue;
 		}
 		if (pr == NULL) {
 			rr = pr = rdp;
@@ -1008,12 +1020,14 @@
 	if ((dtd = xmlGetIntSubset(document)) == NULL) {
 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
 		    "document has no DTD.\n");
+		xmlFreeDoc(document);
 		return (NULL);
 	}
 
 	if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) {
 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
 		    "document DTD unknown; bad topology file\n");
+		xmlFreeDoc(document);
 		return (NULL);
 	}
 
@@ -1056,6 +1070,8 @@
 			topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
 			    "Could not parse DTD \"%s\".\n",
 			    dtdpath);
+			xmlFree(scheme);
+			xmlFreeDoc(document);
 			return (NULL);
 		}
 
@@ -1066,6 +1082,8 @@
 	}
 
 	if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {;
+		xmlFree(scheme);
+		xmlFreeDoc(document);
 		topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
 		    "couldn't handle XInclude statements in document\n");
 		return (NULL);
@@ -1074,7 +1092,7 @@
 	if (validate) {
 		if ((vcp = xmlNewValidCtxt()) == NULL) {
 			xmlFree(scheme);
-			scheme = NULL;
+			xmlFreeDoc(document);
 			return (NULL);
 		}
 		vcp->warning = xmlParserValidityWarning;
@@ -1089,8 +1107,11 @@
 			    "Document is not valid.\n");
 	}
 
-	if ((r = tf_info_new(tmp, document, scheme)) == NULL)
+	if ((r = tf_info_new(tmp, document, scheme)) == NULL) {
+		xmlFree(scheme);
+		xmlFreeDoc(document);
 		return (NULL);
+	}
 
 	xmlFree(scheme);
 	scheme = NULL;
--- a/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c	Mon Apr 23 12:50:31 2007 -0700
+++ b/usr/src/lib/fm/topo/modules/i86pc/chip/chip.c	Mon Apr 23 15:34: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.
  */
 
@@ -578,34 +578,20 @@
  *   asru-physaddr or asru-offset then these are includes in the "mem" scheme
  *   asru as additional membersl physaddr and offset
  */
-/*ARGSUSED*/
 static int
-mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version,
-    nvlist_t *in, nvlist_t **out)
+mem_asru_create(topo_mod_t *mod, nvlist_t *fmri, nvlist_t **asru)
 {
 	int incl_pa = 0, incl_offset = 0;
-	nvlist_t *hcsp, *asru;
+	nvlist_t *hcsp, *ap;
+	char *unum, *scheme;
 	uint64_t pa, offset;
-	char *scheme, *unum;
 	int err;
 
-	if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 &&
-	    strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0)
+	if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &scheme) != 0 ||
+	    strcmp(scheme, FM_FMRI_SCHEME_HC) != 0)
 		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
 
-	if (in == NULL) {
-		if (topo_prop_get_fmri(node, TOPO_PGROUP_PROTOCOL,
-		    TOPO_PROP_ASRU, out, &err) == 0)
-			return (0);
-		else
-			return (topo_mod_seterrno(mod, err));
-	} else {
-		if (nvlist_lookup_string(in, FM_FMRI_SCHEME, &scheme) != 0 ||
-		    strcmp(scheme, FM_FMRI_SCHEME_HC) != 0)
-			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
-	}
-
-	if (nvlist_lookup_nvlist(in, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
+	if (nvlist_lookup_nvlist(fmri, FM_FMRI_HC_SPECIFIC, &hcsp) == 0) {
 		if (nvlist_lookup_uint64(hcsp, "asru-"FM_FMRI_MEM_PHYSADDR,
 		    &pa) == 0)
 			incl_pa = 1;
@@ -615,28 +601,75 @@
 			incl_offset = 1;
 	}
 
-	/* use 'in' to obtain resource path;  could use node resource */
-	if (topo_mod_nvl2str(mod, in, &unum) < 0)
-		return (topo_mod_seterrno(mod, err));
+	/* use 'fmri' to obtain resource path;  could use node resource */
+	if (topo_mod_nvl2str(mod, fmri, &unum) < 0)
+		return (-1);  /* mod errno set */
 
-	if ((asru = mem_fmri_create(mod)) == NULL) {
+	if ((ap = mem_fmri_create(mod)) == NULL) {
 		topo_mod_strfree(mod, unum);
 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
 	}
 
-	err = nvlist_add_string(asru, FM_FMRI_MEM_UNUM, unum);
+	err = nvlist_add_string(ap, FM_FMRI_MEM_UNUM, unum);
 	if (incl_pa)
-		err |= nvlist_add_uint64(asru, FM_FMRI_MEM_PHYSADDR, pa);
+		err |= nvlist_add_uint64(ap, FM_FMRI_MEM_PHYSADDR, pa);
 	if (incl_offset)
-		err |= nvlist_add_uint64(asru, FM_FMRI_MEM_OFFSET, offset);
+		err |= nvlist_add_uint64(ap, FM_FMRI_MEM_OFFSET, offset);
 
 	topo_mod_strfree(mod, unum);
 	if (err != 0) {
-		nvlist_free(asru);
+		nvlist_free(ap);
 		return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
 	}
 
-	*out = asru;
+	*asru = ap;
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+mem_asru_compute(topo_mod_t *mod, tnode_t *node, topo_version_t version,
+    nvlist_t *in, nvlist_t **out)
+{
+	nvlist_t *asru;
+	nvlist_t *args, *pargs;
+	int err;
+
+	if (strcmp(topo_node_name(node), RANK_NODE_NAME) != 0 &&
+	    strcmp(topo_node_name(node), DIMM_NODE_NAME) != 0)
+		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+
+	if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args) != 0)
+		return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+
+	if ((err = nvlist_lookup_nvlist(in, TOPO_PROP_PARGS, &pargs)) != 0) {
+		if (err == ENOENT) {
+			if (topo_mod_nvdup(mod, args, &asru) < 0)
+				return (topo_mod_seterrno(mod, EMOD_NOMEM));
+		} else {
+			return (topo_mod_seterrno(mod, EMOD_METHOD_INVAL));
+		}
+	} else if (mem_asru_create(mod, pargs, &asru) != 0) {
+		return (-1); /* mod errno already set */
+	}
+
+	if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) < 0) {
+		nvlist_free(asru);
+		return (topo_mod_seterrno(mod, EMOD_NOMEM));
+	}
+
+	err = nvlist_add_string(*out, TOPO_PROP_VAL_NAME, TOPO_PROP_ASRU);
+	err |= nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, TOPO_TYPE_FMRI);
+	err |= nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, asru);
+	if (err != 0) {
+		nvlist_free(asru);
+		nvlist_free(*out);
+		return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+	}
+
+	nvlist_free(asru);
+
 	return (0);
 }
 
@@ -705,13 +738,13 @@
 		 * the asru is just that page.  Hence the dual preconstructed
 		 * and computed ASRU.
 		 */
-		(void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]],
-			    TOPO_ASRU_COMPUTE, &err);
-
 		if (topo_method_register(mod, ranknode, rank_methods) < 0)
 			whinge(mod, &nerr, "rank_create: "
 			    "topo_method_register failed");
 
+		(void) topo_node_asru_set(ranknode, cs_fmri[csnumarr[i]],
+			    TOPO_ASRU_COMPUTE, &err);
+
 		(void) topo_pgroup_create(ranknode, &rank_pgroup, &err);
 
 		(void) topo_prop_set_uint64(ranknode, PGNAME(RANK), "size",
@@ -774,12 +807,10 @@
 		}
 
 		/*
-		 * The asru is static but we prefer to publish it in the
-		 * "mem" scheme so call the compute method directly to
-		 * perform the conversion.
+		 * Use the mem computation method directly to publish the asru
+		 * in the "mem" scheme.
 		 */
-		if (mem_asru_compute(mod, dimmnode,
-		    TOPO_METH_ASRU_COMPUTE_VERSION, fmri, &asru) == 0) {
+		if (mem_asru_create(mod, fmri, &asru) == 0) {
 			(void) topo_node_asru_set(dimmnode, asru, 0, &err);
 			nvlist_free(asru);
 		} else {
@@ -820,7 +851,7 @@
 	void *buf = NULL;
 	uint8_t ver;
 
-	nvlist_t *nvl;
+	nvlist_t *nvl = NULL;
 	char path[64];
 	int fd, err;
 
@@ -861,6 +892,7 @@
 	err = nvlist_unpack(buf, mcs.mcs_size, &nvl, 0);
 	topo_mod_free(mod, buf, mcs.mcs_size);
 
+
 	if (nvlist_lookup_uint8(nvl, MC_NVLIST_VERSTR, &ver) != 0) {
 		whinge(mod, NULL, "mc nvlist is not versioned\n");
 		nvlist_free(nvl);