xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_prop.c (revision e5dcf7beb7c949f9234713d5818b581ec3825443)
17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
57aec1d6eScindi  * Common Development and Distribution License (the "License").
67aec1d6eScindi  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  */
217aec1d6eScindi /*
22*e5dcf7beSRobert Johnston  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237aec1d6eScindi  * Use is subject to license terms.
247aec1d6eScindi  */
257aec1d6eScindi 
267aec1d6eScindi #include <strings.h>
277aec1d6eScindi #include <assert.h>
287aec1d6eScindi #include <fm/libtopo.h>
297aec1d6eScindi #include <topo_prop.h>
307aec1d6eScindi #include <topo_string.h>
317aec1d6eScindi #include <topo_alloc.h>
327aec1d6eScindi #include <topo_error.h>
33c40d7343Scindi #include <topo_method.h>
34c40d7343Scindi 
35c40d7343Scindi /*
36c40d7343Scindi  * Topology nodes are permitted to contain property information.
37c40d7343Scindi  * Property information is organized according to property grouping.
38c40d7343Scindi  * Each property group defines a name, a stability level for that name,
39c40d7343Scindi  * a stability level for all underlying property data (name, type, values),
40c40d7343Scindi  * a version for the property group definition and and a list of uniquely
41c40d7343Scindi  * defined properties.  Property group versions are incremented when one of
42c40d7343Scindi  * the following changes occurs:
43c40d7343Scindi  *	- a property name changes
44c40d7343Scindi  *	- a property type changes
45c40d7343Scindi  *	- a property definition is removed from the group
46c40d7343Scindi  * Compatible changes such as new property definitions in the group do
47c40d7343Scindi  * not require version changes.
48c40d7343Scindi  *
49c40d7343Scindi  * Each property defines a unique (within the group) name, a type and
50c40d7343Scindi  * a value.  Properties may be statically defined as int32, uint32, int64,
51c40d7343Scindi  * uint64, fmri, string or arrays of each type.  Properties may also be
52c40d7343Scindi  * dynamically exported via module registered methods.  For example, a module
53c40d7343Scindi  * may register a method to export an ASRU property that is dynamically
54c40d7343Scindi  * contructed when a call to topo_node_fmri() is invoked for a particular
55c40d7343Scindi  * topology node.
56c40d7343Scindi  *
57c40d7343Scindi  * Static properties are persistently attached to topology nodes during
58c40d7343Scindi  * enumeration by an enumeration module or as part of XML statements in a
59c40d7343Scindi  * toplogy map file using the topo_prop_set* family of routines.  Similarly,
60c40d7343Scindi  * property methods are registered during enumeration or as part of
61c40d7343Scindi  * statements in topololgy map files.  Set-up of property methods is performed
62c40d7343Scindi  * by calling topo_prop_method_register().
63c40d7343Scindi  *
64c40d7343Scindi  * All properties, whether statically persisted in a snapshot or dynamically
65c40d7343Scindi  * obtained, may be read via the topo_prop_get* family of interfaces.
66c40d7343Scindi  * Callers wishing to receive all property groups and properties for a given
67c40d7343Scindi  * node may use topo_prop_getall().  This routine returns a nested nvlist
68c40d7343Scindi  * of all groupings and property (name, type, value) sets.  Groupings
69c40d7343Scindi  * are defined by TOPO_PROP_GROUP (name, data stability, name stability and
70c40d7343Scindi  * version) and a nested nvlist of properties (TOPO_PROP_VAL).  Each property
71c40d7343Scindi  * value is defined by its name, type and value.
72c40d7343Scindi  */
73c40d7343Scindi static void topo_propval_destroy(topo_propval_t *);
747aec1d6eScindi 
757aec1d6eScindi static topo_pgroup_t *
767aec1d6eScindi pgroup_get(tnode_t *node, const char *pgname)
777aec1d6eScindi {
787aec1d6eScindi 	topo_pgroup_t *pg;
797aec1d6eScindi 	/*
807aec1d6eScindi 	 * Check for an existing pgroup
817aec1d6eScindi 	 */
827aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
837aec1d6eScindi 	    pg = topo_list_next(pg)) {
840eb822a1Scindi 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
857aec1d6eScindi 			return (pg);
867aec1d6eScindi 		}
877aec1d6eScindi 	}
887aec1d6eScindi 
897aec1d6eScindi 	return (NULL);
907aec1d6eScindi }
917aec1d6eScindi 
927aec1d6eScindi static topo_propval_t *
937aec1d6eScindi propval_get(topo_pgroup_t *pg, const char *pname)
947aec1d6eScindi {
957aec1d6eScindi 	topo_proplist_t *pvl;
967aec1d6eScindi 
97c40d7343Scindi 	if (pg == NULL)
98c40d7343Scindi 		return (NULL);
99c40d7343Scindi 
1007aec1d6eScindi 	for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1017aec1d6eScindi 	    pvl = topo_list_next(pvl)) {
1027aec1d6eScindi 		if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
1037aec1d6eScindi 			return (pvl->tp_pval);
1047aec1d6eScindi 	}
1057aec1d6eScindi 
1067aec1d6eScindi 	return (NULL);
1077aec1d6eScindi }
1087aec1d6eScindi 
109c40d7343Scindi static int
110c40d7343Scindi method_geterror(nvlist_t *nvl, int err, int *errp)
1117aec1d6eScindi {
112c40d7343Scindi 	if (nvl != NULL)
113c40d7343Scindi 		nvlist_free(nvl);
1147aec1d6eScindi 
115c40d7343Scindi 	*errp = err;
1167aec1d6eScindi 
117c40d7343Scindi 	return (-1);
1187aec1d6eScindi }
1197aec1d6eScindi 
1207aec1d6eScindi static int
121c40d7343Scindi prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm,
122c40d7343Scindi     nvlist_t *pargs, int *err)
1237aec1d6eScindi {
124c40d7343Scindi 	int ret;
125c40d7343Scindi 	nvlist_t *args, *nvl;
126c40d7343Scindi 	char *name;
127c40d7343Scindi 	topo_type_t type;
1280eb822a1Scindi 
129c40d7343Scindi 	if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 ||
130c40d7343Scindi 	    nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0)
131c40d7343Scindi 		return (method_geterror(NULL, ETOPO_PROP_NVL, err));
1320eb822a1Scindi 
133c40d7343Scindi 	if (pargs != NULL)
134c40d7343Scindi 		if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0)
135c40d7343Scindi 			return (method_geterror(args, ETOPO_PROP_NVL, err));
1360eb822a1Scindi 
1375108f83cSrobj 	/*
1385108f83cSrobj 	 * Now, get the latest value
1395108f83cSrobj 	 *
1405108f83cSrobj 	 * Grab a reference to the property and then unlock the node.  This will
1415108f83cSrobj 	 * allow property methods to safely re-enter the prop_get codepath,
1425108f83cSrobj 	 * making it possible for property methods to access other property
1435108f83cSrobj 	 * values on the same node w\o causing a deadlock.
1445108f83cSrobj 	 */
1455108f83cSrobj 	topo_prop_hold(pv);
1465108f83cSrobj 	topo_node_unlock(node);
147c40d7343Scindi 	if (topo_method_call(node, pm->tpm_name, pm->tpm_version,
1485108f83cSrobj 	    args, &nvl, err) < 0) {
14929852fb9Srobj 		topo_node_lock(node);
1505108f83cSrobj 		topo_prop_rele(pv);
151c40d7343Scindi 		return (method_geterror(args, *err, err));
1525108f83cSrobj 	}
1535108f83cSrobj 	topo_node_lock(node);
1545108f83cSrobj 	topo_prop_rele(pv);
1550eb822a1Scindi 
156c40d7343Scindi 	nvlist_free(args);
1577aec1d6eScindi 
158c40d7343Scindi 	/* Verify the property contents */
159c40d7343Scindi 	ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name);
160c40d7343Scindi 	if (ret != 0 || strcmp(name, pv->tp_name) != 0)
161c40d7343Scindi 		return (method_geterror(nvl, ETOPO_PROP_NAME, err));
1620eb822a1Scindi 
163c40d7343Scindi 	ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type);
164c40d7343Scindi 	if (ret != 0 || type != pv->tp_type)
165c40d7343Scindi 		return (method_geterror(nvl, ETOPO_PROP_TYPE, err));
1667aec1d6eScindi 
167c40d7343Scindi 	/* Release the last value and re-assign to the new value */
168c40d7343Scindi 	if (pv->tp_val != NULL)
169c40d7343Scindi 		nvlist_free(pv->tp_val);
170c40d7343Scindi 	pv->tp_val = nvl;
1717aec1d6eScindi 
172c40d7343Scindi 	return (0);
1737aec1d6eScindi }
1747aec1d6eScindi 
175c40d7343Scindi static topo_propval_t *
176c40d7343Scindi prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs,
177c40d7343Scindi     int *err)
1787aec1d6eScindi {
179c40d7343Scindi 	topo_propval_t *pv = NULL;
1807aec1d6eScindi 
181c40d7343Scindi 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
182c40d7343Scindi 		*err = ETOPO_PROP_NOENT;
183c40d7343Scindi 		return (NULL);
1847aec1d6eScindi 	}
1857aec1d6eScindi 
186*e5dcf7beSRobert Johnston 	if (pv->tp_flag & TOPO_PROP_NONVOLATILE && pv->tp_val != NULL)
187*e5dcf7beSRobert Johnston 		return (pv);
188*e5dcf7beSRobert Johnston 
189c40d7343Scindi 	if (pv->tp_method != NULL) {
190c40d7343Scindi 		if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0)
191c40d7343Scindi 			return (NULL);
1927aec1d6eScindi 	}
1937aec1d6eScindi 
194c40d7343Scindi 	return (pv);
1957aec1d6eScindi }
1967aec1d6eScindi 
1977aec1d6eScindi static int
198c40d7343Scindi get_properror(tnode_t *node, int *errp, int err)
1997aec1d6eScindi {
2007aec1d6eScindi 	topo_node_unlock(node);
2017aec1d6eScindi 	*errp = err;
2027aec1d6eScindi 	return (-1);
2037aec1d6eScindi }
2047aec1d6eScindi 
2050eb822a1Scindi static int
2060eb822a1Scindi prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
2070eb822a1Scindi     topo_type_t type, uint_t *nelems, int *err)
2087aec1d6eScindi {
2090eb822a1Scindi 	int i, j, ret = 0;
2100eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
2117aec1d6eScindi 	topo_propval_t *pv;
2127aec1d6eScindi 
2137aec1d6eScindi 	topo_node_lock(node);
214c40d7343Scindi 	if ((pv = prop_get(node, pgname, pname, NULL, err))
2157aec1d6eScindi 	    == NULL)
216c40d7343Scindi 		return (get_properror(node, err, *err));
2177aec1d6eScindi 
2180eb822a1Scindi 	if (pv->tp_type != type)
219c40d7343Scindi 		return (get_properror(node, err, ETOPO_PROP_TYPE));
2207aec1d6eScindi 
2210eb822a1Scindi 	switch (type) {
2220eb822a1Scindi 		case TOPO_TYPE_INT32:
2230eb822a1Scindi 			ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
2240eb822a1Scindi 			    (int32_t *)val);
2250eb822a1Scindi 			break;
2260eb822a1Scindi 		case TOPO_TYPE_UINT32:
2270eb822a1Scindi 			ret = nvlist_lookup_uint32(pv->tp_val,
2280eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint32_t *)val);
2290eb822a1Scindi 			break;
2300eb822a1Scindi 		case TOPO_TYPE_INT64:
2310eb822a1Scindi 			ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
2320eb822a1Scindi 			    (int64_t *)val);
2330eb822a1Scindi 			break;
2340eb822a1Scindi 		case TOPO_TYPE_UINT64:
2350eb822a1Scindi 			ret = nvlist_lookup_uint64(pv->tp_val,
2360eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint64_t *)val);
2370eb822a1Scindi 			break;
238825ba0f2Srobj 		case TOPO_TYPE_DOUBLE:
239825ba0f2Srobj 			ret = nvlist_lookup_double(pv->tp_val,
240825ba0f2Srobj 			    TOPO_PROP_VAL_VAL, (double *)val);
241825ba0f2Srobj 			break;
2420eb822a1Scindi 		case TOPO_TYPE_STRING: {
2430eb822a1Scindi 			char *str;
2447aec1d6eScindi 
2450eb822a1Scindi 			ret = nvlist_lookup_string(pv->tp_val,
2460eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &str);
247c40d7343Scindi 			if (ret == 0) {
248c40d7343Scindi 				char *s2;
249c40d7343Scindi 				if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
250c40d7343Scindi 					ret = -1;
251c40d7343Scindi 				else
252c40d7343Scindi 					*(char **)val = s2;
253c40d7343Scindi 			}
2540eb822a1Scindi 			break;
2550eb822a1Scindi 		}
2560eb822a1Scindi 		case TOPO_TYPE_FMRI: {
2570eb822a1Scindi 			nvlist_t *nvl;
2580eb822a1Scindi 
2590eb822a1Scindi 			ret = nvlist_lookup_nvlist(pv->tp_val,
2600eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &nvl);
2610eb822a1Scindi 			if (ret == 0)
2620eb822a1Scindi 				ret = topo_hdl_nvdup(thp, nvl,
2630eb822a1Scindi 				    (nvlist_t **)val);
2640eb822a1Scindi 			break;
2650eb822a1Scindi 		}
2660eb822a1Scindi 		case TOPO_TYPE_INT32_ARRAY: {
2670eb822a1Scindi 			int32_t *a1, *a2;
2680eb822a1Scindi 
2690eb822a1Scindi 			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
2700eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
2710eb822a1Scindi 				break;
2720eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
2730eb822a1Scindi 			    *nelems)) == NULL) {
2740eb822a1Scindi 				ret = ETOPO_NOMEM;
2750eb822a1Scindi 				break;
2760eb822a1Scindi 			}
2770eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
2780eb822a1Scindi 				a1[i] = a2[i];
2790eb822a1Scindi 			*(int32_t **)val = a1;
2800eb822a1Scindi 			break;
2810eb822a1Scindi 		}
2820eb822a1Scindi 		case TOPO_TYPE_UINT32_ARRAY: {
2830eb822a1Scindi 			uint32_t *a1, *a2;
2840eb822a1Scindi 
2850eb822a1Scindi 			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
2860eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
2870eb822a1Scindi 				break;
2880eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
2890eb822a1Scindi 			    *nelems)) == NULL) {
2900eb822a1Scindi 				ret = ETOPO_NOMEM;
2910eb822a1Scindi 				break;
2920eb822a1Scindi 			}
2930eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
2940eb822a1Scindi 				a1[i] = a2[i];
2950eb822a1Scindi 			*(uint32_t **)val = a1;
2960eb822a1Scindi 			break;
2970eb822a1Scindi 		}
2980eb822a1Scindi 		case TOPO_TYPE_INT64_ARRAY: {
2990eb822a1Scindi 			int64_t *a1, *a2;
3000eb822a1Scindi 
3010eb822a1Scindi 			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
3020eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3030eb822a1Scindi 				break;
3040eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
3050eb822a1Scindi 			    *nelems)) == NULL) {
3060eb822a1Scindi 				ret = ETOPO_NOMEM;
3070eb822a1Scindi 				break;
3080eb822a1Scindi 			}
3090eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
3100eb822a1Scindi 				a1[i] = a2[i];
3110eb822a1Scindi 			*(int64_t **)val = a1;
3120eb822a1Scindi 			break;
3130eb822a1Scindi 		}
3140eb822a1Scindi 		case TOPO_TYPE_UINT64_ARRAY: {
3150eb822a1Scindi 			uint64_t *a1, *a2;
3160eb822a1Scindi 
3170eb822a1Scindi 			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
3180eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3190eb822a1Scindi 				break;
3200eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
3210eb822a1Scindi 			    *nelems)) == NULL) {
3220eb822a1Scindi 				ret = ETOPO_NOMEM;
3230eb822a1Scindi 				break;
3240eb822a1Scindi 			}
3250eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
3260eb822a1Scindi 				a1[i] = a2[i];
3270eb822a1Scindi 			*(uint64_t **)val = a1;
3280eb822a1Scindi 			break;
3290eb822a1Scindi 		}
3300eb822a1Scindi 		case TOPO_TYPE_STRING_ARRAY: {
3310eb822a1Scindi 			char **a1, **a2;
3320eb822a1Scindi 
3330eb822a1Scindi 			if ((ret = nvlist_lookup_string_array(pv->tp_val,
3340eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3350eb822a1Scindi 				break;
3360eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
3370eb822a1Scindi 			    *nelems)) == NULL) {
3380eb822a1Scindi 				ret = ETOPO_NOMEM;
3390eb822a1Scindi 				break;
3400eb822a1Scindi 			}
3410eb822a1Scindi 			for (i = 0; i < *nelems; ++i) {
3420eb822a1Scindi 				if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
3430eb822a1Scindi 				    == NULL) {
3440eb822a1Scindi 					for (j = 0; j < i; ++j)
3450eb822a1Scindi 						topo_hdl_free(thp, a1[j],
3460eb822a1Scindi 						    sizeof (char *));
3470eb822a1Scindi 					topo_hdl_free(thp, a1,
3480eb822a1Scindi 					    sizeof (char *) * *nelems);
3490eb822a1Scindi 					break;
3500eb822a1Scindi 				}
3510eb822a1Scindi 			}
3520eb822a1Scindi 			*(char ***)val = a1;
3530eb822a1Scindi 			break;
3540eb822a1Scindi 		}
3550eb822a1Scindi 		case TOPO_TYPE_FMRI_ARRAY: {
3560eb822a1Scindi 			nvlist_t **a1, **a2;
3570eb822a1Scindi 
3580eb822a1Scindi 			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
3590eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3600eb822a1Scindi 				break;
3610eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
3620eb822a1Scindi 			    *nelems)) == NULL) {
3630eb822a1Scindi 				ret = ETOPO_NOMEM;
3640eb822a1Scindi 				break;
3650eb822a1Scindi 			}
3660eb822a1Scindi 			for (i = 0; i < *nelems; ++i) {
3670eb822a1Scindi 				if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
3680eb822a1Scindi 					for (j = 0; j < i; ++j)
3690eb822a1Scindi 						nvlist_free(a1[j]);
3700eb822a1Scindi 					topo_hdl_free(thp, a1,
3710eb822a1Scindi 					    sizeof (nvlist_t *) * *nelems);
3720eb822a1Scindi 					break;
3730eb822a1Scindi 				}
3740eb822a1Scindi 			}
3750eb822a1Scindi 			*(nvlist_t ***)val = a1;
3760eb822a1Scindi 			break;
3770eb822a1Scindi 		}
3780eb822a1Scindi 		default:
3790eb822a1Scindi 			ret = ETOPO_PROP_NOENT;
3800eb822a1Scindi 	}
3810eb822a1Scindi 
3820eb822a1Scindi 	if (ret != 0)
3830eb822a1Scindi 		if (ret == ENOENT)
384c40d7343Scindi 			return (get_properror(node, err, ETOPO_PROP_NOENT));
3850eb822a1Scindi 		else if (ret < ETOPO_UNKNOWN)
386c40d7343Scindi 			return (get_properror(node, err, ETOPO_PROP_NVL));
3870eb822a1Scindi 		else
388c40d7343Scindi 			return (get_properror(node, err, ret));
3897aec1d6eScindi 
3900eb822a1Scindi 	topo_node_unlock(node);
3917aec1d6eScindi 	return (0);
3927aec1d6eScindi }
3937aec1d6eScindi 
3940eb822a1Scindi int
3950eb822a1Scindi topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
3960eb822a1Scindi     int32_t *val, int *err)
3970eb822a1Scindi {
3980eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32,
3990eb822a1Scindi 	    NULL, err));
4000eb822a1Scindi }
4010eb822a1Scindi 
4027aec1d6eScindi int
4037aec1d6eScindi topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
4047aec1d6eScindi     uint32_t *val, int *err)
4057aec1d6eScindi {
4060eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32,
4070eb822a1Scindi 	    NULL, err));
4087aec1d6eScindi }
4097aec1d6eScindi 
4107aec1d6eScindi int
4117aec1d6eScindi topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
4127aec1d6eScindi     int64_t *val, int *err)
4137aec1d6eScindi {
4140eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64,
4150eb822a1Scindi 	    NULL, err));
4167aec1d6eScindi }
4177aec1d6eScindi 
4187aec1d6eScindi int
4197aec1d6eScindi topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
4207aec1d6eScindi     uint64_t *val, int *err)
4217aec1d6eScindi {
4220eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64,
4230eb822a1Scindi 	    NULL, err));
4247aec1d6eScindi }
4257aec1d6eScindi 
426825ba0f2Srobj int
427825ba0f2Srobj topo_prop_get_double(tnode_t *node, const char *pgname, const char *pname,
428825ba0f2Srobj     double *val, int *err)
429825ba0f2Srobj {
430825ba0f2Srobj 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_DOUBLE,
431825ba0f2Srobj 	    NULL, err));
432825ba0f2Srobj }
433825ba0f2Srobj 
4347aec1d6eScindi int
4357aec1d6eScindi topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
4367aec1d6eScindi     char **val, int *err)
4377aec1d6eScindi {
4380eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING,
4390eb822a1Scindi 	    NULL, err));
4407aec1d6eScindi }
4417aec1d6eScindi 
4427aec1d6eScindi int
4437aec1d6eScindi topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
4447aec1d6eScindi     nvlist_t **val, int *err)
4457aec1d6eScindi {
4460eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI,
4470eb822a1Scindi 	    NULL, err));
4480eb822a1Scindi }
4497aec1d6eScindi 
4500eb822a1Scindi int
4510eb822a1Scindi topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname,
4520eb822a1Scindi     int32_t **val, uint_t *nelem, int *err)
4530eb822a1Scindi {
4540eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4550eb822a1Scindi 	    TOPO_TYPE_INT32_ARRAY, nelem, err));
4560eb822a1Scindi }
4577aec1d6eScindi 
4580eb822a1Scindi int
4590eb822a1Scindi topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname,
4600eb822a1Scindi     uint32_t **val, uint_t *nelem, int *err)
4610eb822a1Scindi {
4620eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4630eb822a1Scindi 	    TOPO_TYPE_UINT32_ARRAY, nelem, err));
4640eb822a1Scindi }
4657aec1d6eScindi 
4660eb822a1Scindi int
4670eb822a1Scindi topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname,
4680eb822a1Scindi     int64_t **val, uint_t *nelem, int *err)
4690eb822a1Scindi {
4700eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4710eb822a1Scindi 	    TOPO_TYPE_INT64_ARRAY, nelem, err));
4720eb822a1Scindi }
4737aec1d6eScindi 
4740eb822a1Scindi int
4750eb822a1Scindi topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname,
4760eb822a1Scindi     uint64_t **val, uint_t *nelem, int *err)
4770eb822a1Scindi {
4780eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4790eb822a1Scindi 	    TOPO_TYPE_UINT64_ARRAY, nelem, err));
4807aec1d6eScindi }
4817aec1d6eScindi 
4820eb822a1Scindi int
4830eb822a1Scindi topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname,
4840eb822a1Scindi     char ***val, uint_t *nelem, int *err)
4857aec1d6eScindi {
4860eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4870eb822a1Scindi 	    TOPO_TYPE_STRING_ARRAY, nelem, err));
4887aec1d6eScindi }
4897aec1d6eScindi 
4900eb822a1Scindi int
4910eb822a1Scindi topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname,
4920eb822a1Scindi     nvlist_t ***val, uint_t *nelem, int *err)
4937aec1d6eScindi {
4940eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4950eb822a1Scindi 	    TOPO_TYPE_FMRI_ARRAY, nelem, err));
4967aec1d6eScindi }
4977aec1d6eScindi 
498c40d7343Scindi static topo_propval_t *
4990eb822a1Scindi set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
5007aec1d6eScindi {
5010eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
5020eb822a1Scindi 	topo_propval_t *pv;
5030eb822a1Scindi 
5040eb822a1Scindi 	if (pvl != NULL) {
5050eb822a1Scindi 		pv = pvl->tp_pval;
506c40d7343Scindi 		topo_propval_destroy(pv);
5070eb822a1Scindi 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
5080eb822a1Scindi 	}
5097aec1d6eScindi 
5100eb822a1Scindi 	topo_node_unlock(node);
5117aec1d6eScindi 	*errp = err;
5127aec1d6eScindi 
513c40d7343Scindi 	return (NULL);
5147aec1d6eScindi }
5157aec1d6eScindi 
516c40d7343Scindi static topo_propval_t *
517c40d7343Scindi prop_create(tnode_t *node, const char *pgname, const char *pname,
518c40d7343Scindi     topo_type_t type, int flag, int *err)
5197aec1d6eScindi {
5207aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
5217aec1d6eScindi 	topo_pgroup_t *pg;
5227aec1d6eScindi 	topo_propval_t *pv;
5237aec1d6eScindi 	topo_proplist_t *pvl;
5247aec1d6eScindi 
5250eb822a1Scindi 	/*
5260eb822a1Scindi 	 * Replace existing prop value with new one
5270eb822a1Scindi 	 */
52812cc75c8Scindi 	if ((pg = pgroup_get(node, pgname)) == NULL) {
52912cc75c8Scindi 		topo_node_unlock(node);
53012cc75c8Scindi 		*err = ETOPO_PROP_NOENT;
531c40d7343Scindi 		return (NULL);
53212cc75c8Scindi 	}
533c40d7343Scindi 
5347aec1d6eScindi 	if ((pv = propval_get(pg, pname)) != NULL) {
5357aec1d6eScindi 		if (pv->tp_type != type)
5360eb822a1Scindi 			return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
537*e5dcf7beSRobert Johnston 		else if (! (pv->tp_flag & TOPO_PROP_MUTABLE))
5380eb822a1Scindi 			return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
539c40d7343Scindi 
5400eb822a1Scindi 		nvlist_free(pv->tp_val);
5410eb822a1Scindi 		pv->tp_val = NULL;
5427aec1d6eScindi 	} else {
5437aec1d6eScindi 		if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
5447aec1d6eScindi 		    == NULL)
5450eb822a1Scindi 			return (set_seterror(node, NULL, err, ETOPO_NOMEM));
5467aec1d6eScindi 
5477aec1d6eScindi 		if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
5480eb822a1Scindi 		    == NULL)
5490eb822a1Scindi 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
55012cc75c8Scindi 
55112cc75c8Scindi 		pv->tp_hdl = thp;
5520eb822a1Scindi 		pvl->tp_pval = pv;
5530eb822a1Scindi 
5547aec1d6eScindi 		if ((pv->tp_name = topo_hdl_strdup(thp, pname))
5550eb822a1Scindi 		    == NULL)
5560eb822a1Scindi 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
5577aec1d6eScindi 		pv->tp_flag = flag;
5587aec1d6eScindi 		pv->tp_type = type;
5597aec1d6eScindi 		topo_prop_hold(pv);
560c40d7343Scindi 		topo_list_append(&pg->tpg_pvals, pvl);
5617aec1d6eScindi 	}
5627aec1d6eScindi 
563c40d7343Scindi 	return (pv);
564c40d7343Scindi }
565c40d7343Scindi 
566c40d7343Scindi static int
567c40d7343Scindi topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
568c40d7343Scindi     topo_type_t type, int flag, void *val, int nelems, int *err)
569c40d7343Scindi {
570c40d7343Scindi 	int ret;
571c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
572c40d7343Scindi 	nvlist_t *nvl;
573c40d7343Scindi 
574c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) {
575c40d7343Scindi 		*err = ETOPO_PROP_NVL;
576c40d7343Scindi 		return (-1);
577c40d7343Scindi 	}
5780eb822a1Scindi 
579c40d7343Scindi 	ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname);
580c40d7343Scindi 	ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
5817aec1d6eScindi 	switch (type) {
5827aec1d6eScindi 		case TOPO_TYPE_INT32:
583c40d7343Scindi 			ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
5840eb822a1Scindi 			    *(int32_t *)val);
5857aec1d6eScindi 			break;
5867aec1d6eScindi 		case TOPO_TYPE_UINT32:
587c40d7343Scindi 			ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
5880eb822a1Scindi 			    *(uint32_t *)val);
5897aec1d6eScindi 			break;
5907aec1d6eScindi 		case TOPO_TYPE_INT64:
591c40d7343Scindi 			ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
5920eb822a1Scindi 			    *(int64_t *)val);
5937aec1d6eScindi 			break;
5947aec1d6eScindi 		case TOPO_TYPE_UINT64:
595c40d7343Scindi 			ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
5960eb822a1Scindi 			    *(uint64_t *)val);
5977aec1d6eScindi 			break;
598825ba0f2Srobj 		case TOPO_TYPE_DOUBLE:
599825ba0f2Srobj 			ret |= nvlist_add_double(nvl, TOPO_PROP_VAL_VAL,
600825ba0f2Srobj 			    *(double *)val);
601825ba0f2Srobj 			break;
6027aec1d6eScindi 		case TOPO_TYPE_STRING:
603c40d7343Scindi 			ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
6040eb822a1Scindi 			    (char *)val);
6057aec1d6eScindi 			break;
6067aec1d6eScindi 		case TOPO_TYPE_FMRI:
607c40d7343Scindi 			ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
6080eb822a1Scindi 			    (nvlist_t *)val);
6090eb822a1Scindi 			break;
6100eb822a1Scindi 		case TOPO_TYPE_INT32_ARRAY:
611c40d7343Scindi 			ret |= nvlist_add_int32_array(nvl,
6120eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
6130eb822a1Scindi 			break;
6140eb822a1Scindi 		case TOPO_TYPE_UINT32_ARRAY:
615c40d7343Scindi 			ret |= nvlist_add_uint32_array(nvl,
6160eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
6170eb822a1Scindi 			break;
6180eb822a1Scindi 		case TOPO_TYPE_INT64_ARRAY:
619c40d7343Scindi 			ret |= nvlist_add_int64_array(nvl,
6200eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
6210eb822a1Scindi 			break;
6220eb822a1Scindi 		case TOPO_TYPE_UINT64_ARRAY:
623c40d7343Scindi 			ret |= nvlist_add_uint64_array(nvl,
6240eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
6250eb822a1Scindi 			break;
6260eb822a1Scindi 		case TOPO_TYPE_STRING_ARRAY:
627c40d7343Scindi 			ret |= nvlist_add_string_array(nvl,
6280eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (char **)val, nelems);
6290eb822a1Scindi 			break;
6300eb822a1Scindi 		case TOPO_TYPE_FMRI_ARRAY:
631c40d7343Scindi 			ret |= nvlist_add_nvlist_array(nvl,
6320eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
6337aec1d6eScindi 			break;
6347aec1d6eScindi 		default:
635c40d7343Scindi 			*err = ETOPO_PROP_TYPE;
636c40d7343Scindi 			return (-1);
6377aec1d6eScindi 	}
6387aec1d6eScindi 
6390eb822a1Scindi 	if (ret != 0) {
640c40d7343Scindi 		nvlist_free(nvl);
641c40d7343Scindi 		if (ret == ENOMEM) {
642c40d7343Scindi 			*err = ETOPO_PROP_NOMEM;
643c40d7343Scindi 			return (-1);
644c40d7343Scindi 		} else {
645c40d7343Scindi 			*err = ETOPO_PROP_NVL;
646c40d7343Scindi 			return (-1);
647c40d7343Scindi 		}
6480eb822a1Scindi 	}
6490eb822a1Scindi 
650825ba0f2Srobj 	if (topo_prop_setprop(node, pgname, nvl, flag, nvl, err) != 0) {
651c40d7343Scindi 		nvlist_free(nvl);
652825ba0f2Srobj 		return (-1); /* err set */
653c40d7343Scindi 	}
654825ba0f2Srobj 	nvlist_free(nvl);
655c40d7343Scindi 	return (ret);
6567aec1d6eScindi }
6577aec1d6eScindi 
6587aec1d6eScindi int
6597aec1d6eScindi topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
6607aec1d6eScindi     int flag, int32_t val, int *err)
6617aec1d6eScindi {
6627aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
6630eb822a1Scindi 	    &val, 1, err));
6647aec1d6eScindi }
6657aec1d6eScindi 
6667aec1d6eScindi int
6677aec1d6eScindi topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
6687aec1d6eScindi     int flag, uint32_t val, int *err)
6697aec1d6eScindi {
6707aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
6710eb822a1Scindi 	    &val, 1, err));
6727aec1d6eScindi }
6737aec1d6eScindi 
6747aec1d6eScindi int
6757aec1d6eScindi topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
6767aec1d6eScindi     int flag, int64_t val, int *err)
6777aec1d6eScindi {
6787aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
6790eb822a1Scindi 	    &val, 1, err));
6807aec1d6eScindi }
6817aec1d6eScindi 
6827aec1d6eScindi int
6837aec1d6eScindi topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
6847aec1d6eScindi     int flag, uint64_t val, int *err)
6857aec1d6eScindi {
6867aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
6870eb822a1Scindi 	    &val, 1, err));
6887aec1d6eScindi }
6897aec1d6eScindi 
690825ba0f2Srobj int
691825ba0f2Srobj topo_prop_set_double(tnode_t *node, const char *pgname, const char *pname,
692825ba0f2Srobj     int flag, double val, int *err)
693825ba0f2Srobj {
694825ba0f2Srobj 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_DOUBLE, flag,
695825ba0f2Srobj 	    &val, 1, err));
696825ba0f2Srobj }
697825ba0f2Srobj 
6987aec1d6eScindi int
6997aec1d6eScindi topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
7007aec1d6eScindi     int flag, const char *val, int *err)
7017aec1d6eScindi {
7027aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
7030eb822a1Scindi 	    (void *)val, 1, err));
7047aec1d6eScindi }
7057aec1d6eScindi 
7067aec1d6eScindi int
7077aec1d6eScindi topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
7087aec1d6eScindi     int flag, const nvlist_t *fmri, int *err)
7097aec1d6eScindi {
7107aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
7110eb822a1Scindi 	    (void *)fmri, 1, err));
7120eb822a1Scindi }
7130eb822a1Scindi 
7140eb822a1Scindi int
7150eb822a1Scindi topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname,
7160eb822a1Scindi     int flag, int32_t *val, uint_t nelems, int *err)
7170eb822a1Scindi {
7180eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag,
7190eb822a1Scindi 	    val, nelems, err));
7200eb822a1Scindi }
7210eb822a1Scindi 
7220eb822a1Scindi int
7230eb822a1Scindi topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname,
7240eb822a1Scindi     int flag, uint32_t *val, uint_t nelems, int *err)
7250eb822a1Scindi {
7260eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag,
7270eb822a1Scindi 	    val, nelems, err));
7280eb822a1Scindi }
7290eb822a1Scindi 
7300eb822a1Scindi int
7310eb822a1Scindi topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname,
7320eb822a1Scindi     int flag, int64_t *val, uint_t nelems, int *err)
7330eb822a1Scindi {
7340eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag,
7350eb822a1Scindi 	    val, nelems, err));
7360eb822a1Scindi }
7370eb822a1Scindi 
7380eb822a1Scindi int
7390eb822a1Scindi topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname,
7400eb822a1Scindi     int flag, uint64_t *val, uint_t nelems, int *err)
7410eb822a1Scindi {
7420eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag,
7430eb822a1Scindi 	    val, nelems, err));
7440eb822a1Scindi }
7450eb822a1Scindi 
7460eb822a1Scindi int
7470eb822a1Scindi topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname,
7480eb822a1Scindi     int flag, const char **val, uint_t nelems, int *err)
7490eb822a1Scindi {
7500eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag,
7510eb822a1Scindi 	    (void *)val, nelems, err));
7520eb822a1Scindi }
7530eb822a1Scindi 
7540eb822a1Scindi int
7550eb822a1Scindi topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname,
7560eb822a1Scindi     int flag, const nvlist_t **fmri, uint_t nelems, int *err)
7570eb822a1Scindi {
7580eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag,
7590eb822a1Scindi 	    (void *)fmri, nelems, err));
7607aec1d6eScindi }
7617aec1d6eScindi 
762c40d7343Scindi /*
763c40d7343Scindi  * topo_prop_setprop() is a private project function for fmtopo
764c40d7343Scindi  */
765c40d7343Scindi int
766c40d7343Scindi topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop,
767c40d7343Scindi     int flag, nvlist_t *pargs, int *err)
768c40d7343Scindi {
769c40d7343Scindi 	int ret;
770c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
771c40d7343Scindi 	topo_propval_t *pv;
772c40d7343Scindi 	nvlist_t *nvl, *args;
773c40d7343Scindi 	char *name;
774c40d7343Scindi 	topo_type_t type;
775c40d7343Scindi 
776c40d7343Scindi 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) {
777c40d7343Scindi 		*err = ETOPO_PROP_NAME;
778c40d7343Scindi 		return (-1);
779c40d7343Scindi 	}
780c40d7343Scindi 	if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type)
781c40d7343Scindi 	    != 0) {
782c40d7343Scindi 		*err = ETOPO_PROP_TYPE;
783c40d7343Scindi 		return (-1);
784c40d7343Scindi 	}
785c40d7343Scindi 
786c40d7343Scindi 	topo_node_lock(node);
787c40d7343Scindi 	if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL)
788c40d7343Scindi 		return (-1); /* unlocked and err set */
789c40d7343Scindi 
790c40d7343Scindi 	/*
791c40d7343Scindi 	 * Set by method or set to new prop value.  If we fail, leave
792c40d7343Scindi 	 * property in list with old value.
793c40d7343Scindi 	 */
794c40d7343Scindi 	if (pv->tp_method != NULL) {
795c40d7343Scindi 		topo_propmethod_t *pm = pv->tp_method;
796c40d7343Scindi 
797c40d7343Scindi 		if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) {
798c40d7343Scindi 			topo_node_unlock(node);
799c40d7343Scindi 			*err = ETOPO_PROP_NOMEM;
800c40d7343Scindi 			return (-1);
801c40d7343Scindi 		}
802c40d7343Scindi 		ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args);
803c40d7343Scindi 		if (pargs != NULL)
804c40d7343Scindi 			ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs);
805c40d7343Scindi 
806c40d7343Scindi 		if (ret != 0) {
807c40d7343Scindi 			topo_node_unlock(node);
808c40d7343Scindi 			nvlist_free(args);
809c40d7343Scindi 			*err = ETOPO_PROP_NVL;
810c40d7343Scindi 			return (-1);
811c40d7343Scindi 		}
812c40d7343Scindi 
8135108f83cSrobj 		/*
8145108f83cSrobj 		 *
8155108f83cSrobj 		 * Grab a reference to the property and then unlock the node.
8165108f83cSrobj 		 * This will allow property methods to safely re-enter the
8175108f83cSrobj 		 * prop_get codepath, making it possible for property methods
8185108f83cSrobj 		 * to access other property values on the same node w\o causing
8195108f83cSrobj 		 * a deadlock.
8205108f83cSrobj 		 *
8215108f83cSrobj 		 * We don't technically need this now, since this interface is
8225108f83cSrobj 		 * currently only used by fmtopo (which is single-threaded), but
8235108f83cSrobj 		 * we may make this interface available to other parts of
8245108f83cSrobj 		 * libtopo in the future, so best to make it MT-safe now.
8255108f83cSrobj 		 */
8265108f83cSrobj 		topo_prop_hold(pv);
8275108f83cSrobj 		topo_node_unlock(node);
828c40d7343Scindi 		ret = topo_method_call(node, pm->tpm_name, pm->tpm_version,
829c40d7343Scindi 		    args, &nvl, err);
8305108f83cSrobj 		topo_node_lock(node);
8315108f83cSrobj 		topo_prop_rele(pv);
8325108f83cSrobj 
833c40d7343Scindi 		nvlist_free(args);
834c40d7343Scindi 	} else {
835c40d7343Scindi 		if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0)
836c40d7343Scindi 			*err = ETOPO_PROP_NOMEM;
837c40d7343Scindi 	}
838c40d7343Scindi 
839c40d7343Scindi 	if (ret != 0) {
840c40d7343Scindi 		topo_node_unlock(node);
841c40d7343Scindi 		return (-1);
842c40d7343Scindi 	}
843c40d7343Scindi 
844c40d7343Scindi 	pv->tp_val = nvl;
845c40d7343Scindi 	topo_node_unlock(node);
846c40d7343Scindi 	return (0);
847c40d7343Scindi }
848c40d7343Scindi 
849c40d7343Scindi static int
850c40d7343Scindi register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
851c40d7343Scindi     int err)
852c40d7343Scindi {
853c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
854c40d7343Scindi 
855c40d7343Scindi 	if (pm != NULL) {
856c40d7343Scindi 		if (pm->tpm_name != NULL)
857c40d7343Scindi 			topo_hdl_strfree(thp, pm->tpm_name);
858c40d7343Scindi 		if (pm->tpm_args != NULL)
859c40d7343Scindi 			nvlist_free(pm->tpm_args);
860c40d7343Scindi 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
861c40d7343Scindi 	}
862c40d7343Scindi 
863c40d7343Scindi 	*errp = err;
864c40d7343Scindi 
865c40d7343Scindi 	if (l != 0)
866c40d7343Scindi 		topo_node_unlock(node);
867c40d7343Scindi 
868c40d7343Scindi 	return (-1);
869c40d7343Scindi }
870c40d7343Scindi 
871c40d7343Scindi int
872c40d7343Scindi prop_method_register(tnode_t *node, const char *pgname, const char *pname,
873c40d7343Scindi     topo_type_t ptype, const char *mname, topo_version_t version,
874c40d7343Scindi     const nvlist_t *args, int *err)
875c40d7343Scindi {
876c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
877c40d7343Scindi 	topo_propmethod_t *pm = NULL;
878c40d7343Scindi 	topo_propval_t *pv = NULL;
879c40d7343Scindi 
880c40d7343Scindi 	if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL)
881c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
882c40d7343Scindi 		    ETOPO_PROP_NOMEM));
883c40d7343Scindi 
884c40d7343Scindi 	if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL)
885c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
886c40d7343Scindi 		    ETOPO_PROP_NOMEM));
887c40d7343Scindi 
888c40d7343Scindi 	pm->tpm_version = version;
889c40d7343Scindi 
890c40d7343Scindi 	if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0)
891c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
892c40d7343Scindi 		    ETOPO_PROP_NOMEM));
893c40d7343Scindi 
8942eeaed14Srobj 	/*
8952eeaed14Srobj 	 * It's possible the property may already exist.  However we still want
8962eeaed14Srobj 	 * to allow the method to be registered.  This is to handle the case
897*e5dcf7beSRobert Johnston 	 * where we specify a prop method in an xml map to override the value
8982eeaed14Srobj 	 * that was set by the enumerator.
899825ba0f2Srobj 	 *
900*e5dcf7beSRobert Johnston 	 * By default, propmethod-backed properties are not MUTABLE.  This is
901*e5dcf7beSRobert Johnston 	 * done to simplify the programming model for modules that implement
902*e5dcf7beSRobert Johnston 	 * property methods as most propmethods tend to only support get
903*e5dcf7beSRobert Johnston 	 * operations.  Enumerator modules can override this by calling
904*e5dcf7beSRobert Johnston 	 * topo_prop_setmutable().  Propmethods that are registered via XML can
905*e5dcf7beSRobert Johnston 	 * be set as mutable via the optional "mutable" attribute, which will
906*e5dcf7beSRobert Johnston 	 * result in the xml parser calling topo_prop_setflags() after
907*e5dcf7beSRobert Johnston 	 * registering the propmethod.
9082eeaed14Srobj 	 */
9092eeaed14Srobj 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL)
9102eeaed14Srobj 		if ((pv = prop_create(node, pgname, pname, ptype,
911825ba0f2Srobj 		    TOPO_PROP_IMMUTABLE, err)) == NULL) {
9122eeaed14Srobj 			/* node unlocked */
9132eeaed14Srobj 			return (register_methoderror(node, pm, err, 0, *err));
9142eeaed14Srobj 		}
915c40d7343Scindi 
9164557a2a1Srobj 	if (pv->tp_method != NULL)
917c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
918c40d7343Scindi 		    ETOPO_METHOD_DEFD));
919c40d7343Scindi 
9202eeaed14Srobj 	if (pv->tp_val != NULL) {
9212eeaed14Srobj 		nvlist_free(pv->tp_val);
9222eeaed14Srobj 		pv->tp_val = NULL;
9232eeaed14Srobj 	}
924c40d7343Scindi 	pv->tp_method = pm;
925c40d7343Scindi 
926c40d7343Scindi 	topo_node_unlock(node);
927c40d7343Scindi 
928c40d7343Scindi 	return (0);
929c40d7343Scindi }
930c40d7343Scindi 
931c40d7343Scindi int
932c40d7343Scindi topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname,
933c40d7343Scindi     topo_type_t ptype, const char *mname, const nvlist_t *args, int *err)
934c40d7343Scindi {
935c40d7343Scindi 	topo_imethod_t *mp;
936c40d7343Scindi 
937c40d7343Scindi 	topo_node_lock(node);
938c40d7343Scindi 
939c40d7343Scindi 	if ((mp = topo_method_lookup(node, mname)) == NULL)
940c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
9414557a2a1Srobj 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
9424557a2a1Srobj 
9434557a2a1Srobj 	topo_node_lock(node);
944c40d7343Scindi 
945c40d7343Scindi 	return (prop_method_register(node, pgname, pname, ptype, mname,
946c40d7343Scindi 	    mp->tim_version, args, err)); /* err set and node unlocked */
947c40d7343Scindi }
948c40d7343Scindi 
949c40d7343Scindi int
950c40d7343Scindi topo_prop_method_version_register(tnode_t *node, const char *pgname,
951c40d7343Scindi     const char *pname, topo_type_t ptype, const char *mname,
952c40d7343Scindi     topo_version_t version, const nvlist_t *args, int *err)
953c40d7343Scindi {
954c40d7343Scindi 	topo_imethod_t *mp;
955c40d7343Scindi 
956c40d7343Scindi 	topo_node_lock(node);
957c40d7343Scindi 
958c40d7343Scindi 	if ((mp = topo_method_lookup(node, mname)) == NULL)
959c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
9604557a2a1Srobj 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
9614557a2a1Srobj 
9624557a2a1Srobj 	topo_node_lock(node);
963c40d7343Scindi 
964c40d7343Scindi 	if (version < mp->tim_version)
965c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
966c40d7343Scindi 		    ETOPO_METHOD_VEROLD));
967c40d7343Scindi 	if (version > mp->tim_version)
968c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
969c40d7343Scindi 		    ETOPO_METHOD_VERNEW));
970c40d7343Scindi 
971c40d7343Scindi 	return (prop_method_register(node, pgname, pname, ptype, mname,
972c40d7343Scindi 	    version, args, err)); /* err set and node unlocked */
973c40d7343Scindi }
974c40d7343Scindi 
975c40d7343Scindi void
976c40d7343Scindi topo_prop_method_unregister(tnode_t *node, const char *pgname,
977c40d7343Scindi     const char *pname)
978c40d7343Scindi {
979c40d7343Scindi 	topo_propval_t *pv;
980c40d7343Scindi 	topo_pgroup_t *pg;
981c40d7343Scindi 	topo_proplist_t *pvl;
982c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
983c40d7343Scindi 
984c40d7343Scindi 	topo_node_lock(node);
985c40d7343Scindi 
986c40d7343Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
987c40d7343Scindi 	    pg = topo_list_next(pg)) {
988c40d7343Scindi 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
989c40d7343Scindi 			break;
990c40d7343Scindi 		}
991c40d7343Scindi 	}
992c40d7343Scindi 
993c40d7343Scindi 	if (pg == NULL) {
994c40d7343Scindi 		topo_node_unlock(node);
995c40d7343Scindi 		return;
996c40d7343Scindi 	}
997c40d7343Scindi 
998c40d7343Scindi 	for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
999c40d7343Scindi 	    pvl = topo_list_next(pvl)) {
1000c40d7343Scindi 		pv = pvl->tp_pval;
1001c40d7343Scindi 		if (strcmp(pv->tp_name, pname) == 0) {
1002c40d7343Scindi 			topo_list_delete(&pg->tpg_pvals, pvl);
1003c40d7343Scindi 			assert(pv->tp_refs == 1);
1004c40d7343Scindi 			topo_prop_rele(pv);
1005c40d7343Scindi 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1006c40d7343Scindi 			break;
1007c40d7343Scindi 		}
1008c40d7343Scindi 	}
1009c40d7343Scindi 
1010c40d7343Scindi 	topo_node_unlock(node);
1011c40d7343Scindi }
1012c40d7343Scindi 
1013825ba0f2Srobj int
1014825ba0f2Srobj topo_prop_setmutable(tnode_t *node, const char *pgname, const char *pname,
1015825ba0f2Srobj     int *err)
1016825ba0f2Srobj {
1017825ba0f2Srobj 	topo_propval_t *pv = NULL;
1018825ba0f2Srobj 
1019825ba0f2Srobj 	topo_node_lock(node);
1020825ba0f2Srobj 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1021825ba0f2Srobj 		topo_node_unlock(node);
1022825ba0f2Srobj 		*err = ETOPO_PROP_NOENT;
1023825ba0f2Srobj 		return (-1);
1024825ba0f2Srobj 	}
1025825ba0f2Srobj 
1026825ba0f2Srobj 	/*
1027825ba0f2Srobj 	 * If the property is being inherited then we don't want to allow a
1028825ba0f2Srobj 	 * change from IMMUTABLE to MUTABLE.
1029825ba0f2Srobj 	 */
1030825ba0f2Srobj 	if (pv->tp_refs > 1) {
1031825ba0f2Srobj 		topo_node_unlock(node);
1032825ba0f2Srobj 		*err = ETOPO_PROP_DEFD;
1033825ba0f2Srobj 		return (-1);
1034825ba0f2Srobj 	}
1035*e5dcf7beSRobert Johnston 	pv->tp_flag |= TOPO_PROP_MUTABLE;
1036*e5dcf7beSRobert Johnston 
1037*e5dcf7beSRobert Johnston 	topo_node_unlock(node);
1038*e5dcf7beSRobert Johnston 
1039*e5dcf7beSRobert Johnston 	return (0);
1040*e5dcf7beSRobert Johnston }
1041*e5dcf7beSRobert Johnston int
1042*e5dcf7beSRobert Johnston topo_prop_setnonvolatile(tnode_t *node, const char *pgname, const char *pname,
1043*e5dcf7beSRobert Johnston     int *err)
1044*e5dcf7beSRobert Johnston {
1045*e5dcf7beSRobert Johnston 	topo_propval_t *pv = NULL;
1046*e5dcf7beSRobert Johnston 
1047*e5dcf7beSRobert Johnston 	topo_node_lock(node);
1048*e5dcf7beSRobert Johnston 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1049*e5dcf7beSRobert Johnston 		topo_node_unlock(node);
1050*e5dcf7beSRobert Johnston 		*err = ETOPO_PROP_NOENT;
1051*e5dcf7beSRobert Johnston 		return (-1);
1052*e5dcf7beSRobert Johnston 	}
1053*e5dcf7beSRobert Johnston 
1054*e5dcf7beSRobert Johnston 	pv->tp_flag |= TOPO_PROP_NONVOLATILE;
1055825ba0f2Srobj 
1056825ba0f2Srobj 	topo_node_unlock(node);
1057825ba0f2Srobj 
1058825ba0f2Srobj 	return (0);
1059825ba0f2Srobj }
1060825ba0f2Srobj 
10617aec1d6eScindi static int
10627aec1d6eScindi inherit_seterror(tnode_t *node, int *errp, int err)
10637aec1d6eScindi {
10647aec1d6eScindi 	topo_node_unlock(node);
10657aec1d6eScindi 	topo_node_unlock(node->tn_parent);
10667aec1d6eScindi 
10677aec1d6eScindi 	*errp = err;
10687aec1d6eScindi 
10697aec1d6eScindi 	return (-1);
10707aec1d6eScindi }
10717aec1d6eScindi 
10727aec1d6eScindi int
10737aec1d6eScindi topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
10747aec1d6eScindi {
10757aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
10767aec1d6eScindi 	tnode_t *pnode = node->tn_parent;
10777aec1d6eScindi 	topo_pgroup_t *pg;
10787aec1d6eScindi 	topo_propval_t *pv;
10797aec1d6eScindi 	topo_proplist_t *pvl;
10807aec1d6eScindi 
10817aec1d6eScindi 	topo_node_lock(pnode);
10827aec1d6eScindi 	topo_node_lock(node);
10832eeaed14Srobj 
10842eeaed14Srobj 	/*
10852eeaed14Srobj 	 * Check if the requested property group and prop val are already set
10862eeaed14Srobj 	 * on the node.
10872eeaed14Srobj 	 */
10882eeaed14Srobj 	if (propval_get(pgroup_get(node, pgname), name) != NULL)
10892eeaed14Srobj 		return (inherit_seterror(node, err, ETOPO_PROP_DEFD));
10902eeaed14Srobj 
10917aec1d6eScindi 	/*
10922eeaed14Srobj 	 * Check if the requested property group and prop val exists on the
10932eeaed14Srobj 	 * parent node
10947aec1d6eScindi 	 */
1095c40d7343Scindi 	if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
10967aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
10977aec1d6eScindi 
10987aec1d6eScindi 	/*
10997aec1d6eScindi 	 * Can this propval be inherited?
11007aec1d6eScindi 	 */
1101*e5dcf7beSRobert Johnston 	if (pv->tp_flag & TOPO_PROP_MUTABLE)
11027aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
11037aec1d6eScindi 
11047aec1d6eScindi 	/*
11057aec1d6eScindi 	 * Property group should already exist: bump the ref count for this
11067aec1d6eScindi 	 * propval and add it to the node's property group
11077aec1d6eScindi 	 */
11087aec1d6eScindi 	if ((pg = pgroup_get(node, pgname)) == NULL)
11097aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
11107aec1d6eScindi 
11117aec1d6eScindi 	if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
11127aec1d6eScindi 	    == NULL)
11137aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_NOMEM));
11147aec1d6eScindi 
11157aec1d6eScindi 	topo_prop_hold(pv);
11167aec1d6eScindi 	pvl->tp_pval = pv;
11177aec1d6eScindi 	topo_list_append(&pg->tpg_pvals, pvl);
11187aec1d6eScindi 
11197aec1d6eScindi 	topo_node_unlock(node);
11207aec1d6eScindi 	topo_node_unlock(pnode);
11217aec1d6eScindi 
11227aec1d6eScindi 	return (0);
11237aec1d6eScindi }
11247aec1d6eScindi 
11250eb822a1Scindi topo_pgroup_info_t *
11260eb822a1Scindi topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
11277aec1d6eScindi {
11280eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
11297aec1d6eScindi 	topo_pgroup_t *pg;
11300eb822a1Scindi 	topo_ipgroup_info_t *pip;
11310eb822a1Scindi 	topo_pgroup_info_t *info;
11327aec1d6eScindi 
11330eb822a1Scindi 	topo_node_lock(node);
11347aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
11357aec1d6eScindi 	    pg = topo_list_next(pg)) {
11360eb822a1Scindi 		if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
11370eb822a1Scindi 			if ((info = topo_hdl_alloc(thp,
11380eb822a1Scindi 			    sizeof (topo_pgroup_info_t))) == NULL)
11390eb822a1Scindi 				return (NULL);
11400eb822a1Scindi 
11410eb822a1Scindi 			pip = pg->tpg_info;
11420eb822a1Scindi 			if ((info->tpi_name =
114312cc75c8Scindi 			    topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
11440eb822a1Scindi 				*err = ETOPO_PROP_NOMEM;
11450eb822a1Scindi 				topo_hdl_free(thp, info,
11460eb822a1Scindi 				    sizeof (topo_pgroup_info_t));
11470eb822a1Scindi 				topo_node_unlock(node);
11480eb822a1Scindi 				return (NULL);
11490eb822a1Scindi 			}
11500eb822a1Scindi 			info->tpi_namestab = pip->tpi_namestab;
11510eb822a1Scindi 			info->tpi_datastab = pip->tpi_datastab;
11520eb822a1Scindi 			info->tpi_version = pip->tpi_version;
11530eb822a1Scindi 			topo_node_unlock(node);
11540eb822a1Scindi 			return (info);
11557aec1d6eScindi 		}
11567aec1d6eScindi 	}
11577aec1d6eScindi 
11580eb822a1Scindi 	*err = ETOPO_PROP_NOENT;
11590eb822a1Scindi 	topo_node_unlock(node);
11600eb822a1Scindi 	return (NULL);
11610eb822a1Scindi }
11620eb822a1Scindi 
11630eb822a1Scindi static int
11640eb822a1Scindi pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
11650eb822a1Scindi     int *err)
11660eb822a1Scindi {
11670eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
11680eb822a1Scindi 
11690eb822a1Scindi 	if (pip != NULL) {
11700eb822a1Scindi 		if (pip->tpi_name != NULL)
11710eb822a1Scindi 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
11720eb822a1Scindi 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
11730eb822a1Scindi 	}
11740eb822a1Scindi 
11750eb822a1Scindi 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
11760eb822a1Scindi 	*err = ETOPO_NOMEM;
11770eb822a1Scindi 
11780eb822a1Scindi 	topo_node_unlock(node);
11790eb822a1Scindi 
11807aec1d6eScindi 	return (-1);
11817aec1d6eScindi }
11827aec1d6eScindi 
11837aec1d6eScindi int
11840eb822a1Scindi topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err)
11857aec1d6eScindi {
11867aec1d6eScindi 	topo_pgroup_t *pg;
11870eb822a1Scindi 	topo_ipgroup_info_t *pip;
11880eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
11897aec1d6eScindi 
11907aec1d6eScindi 	*err = 0;
11917aec1d6eScindi 
11920eb822a1Scindi 	topo_node_lock(node);
11937aec1d6eScindi 	/*
11947aec1d6eScindi 	 * Check for an existing pgroup
11957aec1d6eScindi 	 */
11967aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
11977aec1d6eScindi 	    pg = topo_list_next(pg)) {
11980eb822a1Scindi 		if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) {
11997aec1d6eScindi 			*err = ETOPO_PROP_DEFD;
12000eb822a1Scindi 			topo_node_unlock(node);
12017aec1d6eScindi 			return (-1);
12027aec1d6eScindi 		}
12037aec1d6eScindi 	}
12047aec1d6eScindi 
12050eb822a1Scindi 	if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) {
12067aec1d6eScindi 		*err = ETOPO_NOMEM;
12070eb822a1Scindi 		topo_node_unlock(node);
12087aec1d6eScindi 		return (-1);
12097aec1d6eScindi 	}
12107aec1d6eScindi 
12110eb822a1Scindi 	if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t)))
12120eb822a1Scindi 	    == NULL)
12130eb822a1Scindi 		return (pgroup_seterr(node, pg, pip, err));
12147aec1d6eScindi 
12150eb822a1Scindi 	if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name))
12160eb822a1Scindi 	    == NULL)
12170eb822a1Scindi 		return (pgroup_seterr(node, pg, pip, err));
12180eb822a1Scindi 
12190eb822a1Scindi 	pip->tpi_namestab = pinfo->tpi_namestab;
12200eb822a1Scindi 	pip->tpi_datastab = pinfo->tpi_datastab;
12210eb822a1Scindi 	pip->tpi_version = pinfo->tpi_version;
12220eb822a1Scindi 
12230eb822a1Scindi 	pg->tpg_info = pip;
12247aec1d6eScindi 
12257aec1d6eScindi 	topo_list_append(&node->tn_pgroups, pg);
12260eb822a1Scindi 	topo_node_unlock(node);
12277aec1d6eScindi 
12287aec1d6eScindi 	return (0);
12297aec1d6eScindi }
12307aec1d6eScindi 
12317aec1d6eScindi void
12327aec1d6eScindi topo_pgroup_destroy(tnode_t *node, const char *pname)
12337aec1d6eScindi {
12347aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
12357aec1d6eScindi 	topo_pgroup_t *pg;
12367aec1d6eScindi 	topo_proplist_t *pvl;
12370eb822a1Scindi 	topo_ipgroup_info_t *pip;
12387aec1d6eScindi 
12397aec1d6eScindi 	topo_node_lock(node);
12407aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
12417aec1d6eScindi 	    pg = topo_list_next(pg)) {
12420eb822a1Scindi 		if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
12437aec1d6eScindi 			break;
12447aec1d6eScindi 		}
12457aec1d6eScindi 	}
12467aec1d6eScindi 
12477aec1d6eScindi 	if (pg == NULL) {
12487aec1d6eScindi 		topo_node_unlock(node);
12497aec1d6eScindi 		return;
12507aec1d6eScindi 	}
12517aec1d6eScindi 
12527aec1d6eScindi 	while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
12537aec1d6eScindi 		topo_list_delete(&pg->tpg_pvals, pvl);
12547aec1d6eScindi 		topo_prop_rele(pvl->tp_pval);
12557aec1d6eScindi 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
12567aec1d6eScindi 	}
12577aec1d6eScindi 
12587aec1d6eScindi 	topo_list_delete(&node->tn_pgroups, pg);
12590eb822a1Scindi 	topo_node_unlock(node);
12607aec1d6eScindi 
12610eb822a1Scindi 	pip = pg->tpg_info;
12620eb822a1Scindi 	if (pip != NULL) {
12630eb822a1Scindi 		if (pip->tpi_name != NULL)
12640eb822a1Scindi 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
12650eb822a1Scindi 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
12660eb822a1Scindi 	}
12677aec1d6eScindi 
12680eb822a1Scindi 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
12697aec1d6eScindi }
12707aec1d6eScindi 
12717aec1d6eScindi void
12727aec1d6eScindi topo_pgroup_destroy_all(tnode_t *node)
12737aec1d6eScindi {
12747aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
12757aec1d6eScindi 	topo_pgroup_t *pg;
12767aec1d6eScindi 	topo_proplist_t *pvl;
12770eb822a1Scindi 	topo_ipgroup_info_t *pip;
12787aec1d6eScindi 
12797aec1d6eScindi 	topo_node_lock(node);
12807aec1d6eScindi 	while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
12817aec1d6eScindi 		while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
12827aec1d6eScindi 			topo_list_delete(&pg->tpg_pvals, pvl);
12837aec1d6eScindi 			topo_prop_rele(pvl->tp_pval);
12847aec1d6eScindi 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
12857aec1d6eScindi 		}
12867aec1d6eScindi 
12877aec1d6eScindi 		topo_list_delete(&node->tn_pgroups, pg);
12887aec1d6eScindi 
12890eb822a1Scindi 		pip = pg->tpg_info;
12900eb822a1Scindi 		if (pip != NULL) {
12910eb822a1Scindi 			if (pip->tpi_name != NULL)
12920eb822a1Scindi 				topo_hdl_strfree(thp, (char *)pip->tpi_name);
12930eb822a1Scindi 			topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
12940eb822a1Scindi 		}
12950eb822a1Scindi 
12967aec1d6eScindi 		topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
12977aec1d6eScindi 	}
12987aec1d6eScindi 	topo_node_unlock(node);
12997aec1d6eScindi }
1300c40d7343Scindi 
1301c40d7343Scindi static void
1302c40d7343Scindi propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
1303c40d7343Scindi {
1304c40d7343Scindi 	topo_propmethod_t *pm;
1305c40d7343Scindi 
1306c40d7343Scindi 	pm = pv->tp_method;
1307c40d7343Scindi 	if (pm != NULL) {
1308c40d7343Scindi 		if (pm->tpm_name != NULL)
1309c40d7343Scindi 			topo_hdl_strfree(thp, pm->tpm_name);
1310c40d7343Scindi 		if (pm->tpm_args != NULL)
1311c40d7343Scindi 			nvlist_free(pm->tpm_args);
1312c40d7343Scindi 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
1313c40d7343Scindi 		pv->tp_method = NULL;
1314c40d7343Scindi 	}
1315c40d7343Scindi }
1316c40d7343Scindi 
13177aec1d6eScindi static void
13187aec1d6eScindi topo_propval_destroy(topo_propval_t *pv)
13197aec1d6eScindi {
1320c40d7343Scindi 	topo_hdl_t *thp;
1321c40d7343Scindi 
1322c40d7343Scindi 	if (pv == NULL)
1323c40d7343Scindi 		return;
1324c40d7343Scindi 
1325c40d7343Scindi 	thp = pv->tp_hdl;
13267aec1d6eScindi 
13277aec1d6eScindi 	if (pv->tp_name != NULL)
13287aec1d6eScindi 		topo_hdl_strfree(thp, pv->tp_name);
13297aec1d6eScindi 
13300eb822a1Scindi 	if (pv->tp_val != NULL)
13310eb822a1Scindi 		nvlist_free(pv->tp_val);
13327aec1d6eScindi 
1333c40d7343Scindi 	propmethod_destroy(thp, pv);
1334c40d7343Scindi 
13357aec1d6eScindi 	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
13367aec1d6eScindi }
13377aec1d6eScindi 
13387aec1d6eScindi void
13397aec1d6eScindi topo_prop_hold(topo_propval_t *pv)
13407aec1d6eScindi {
13417aec1d6eScindi 	pv->tp_refs++;
13427aec1d6eScindi }
13437aec1d6eScindi 
13447aec1d6eScindi void
13457aec1d6eScindi topo_prop_rele(topo_propval_t *pv)
13467aec1d6eScindi {
13477aec1d6eScindi 	pv->tp_refs--;
13487aec1d6eScindi 
13497aec1d6eScindi 	assert(pv->tp_refs >= 0);
13507aec1d6eScindi 
13517aec1d6eScindi 	if (pv->tp_refs == 0)
13527aec1d6eScindi 		topo_propval_destroy(pv);
13537aec1d6eScindi }
1354c40d7343Scindi 
1355c40d7343Scindi /*
1356c40d7343Scindi  * topo_prop_getprop() and topo_prop_getprops() are private project functions
1357c40d7343Scindi  * for fmtopo
1358c40d7343Scindi  */
1359c40d7343Scindi int
1360c40d7343Scindi topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname,
1361c40d7343Scindi     nvlist_t *args, nvlist_t **prop, int *err)
1362c40d7343Scindi {
1363c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
1364c40d7343Scindi 	topo_propval_t *pv;
1365c40d7343Scindi 
1366c40d7343Scindi 	topo_node_lock(node);
1367c40d7343Scindi 	if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) {
1368c40d7343Scindi 		(void) get_properror(node, err, *err);
1369c40d7343Scindi 		return (-1);
1370c40d7343Scindi 	}
1371c40d7343Scindi 
1372c40d7343Scindi 	if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) {
1373c40d7343Scindi 		(void) get_properror(node, err, ETOPO_NOMEM);
1374c40d7343Scindi 		return (-1);
1375c40d7343Scindi 	}
1376c40d7343Scindi 	topo_node_unlock(node);
1377c40d7343Scindi 
1378c40d7343Scindi 	return (0);
1379c40d7343Scindi }
1380c40d7343Scindi 
1381c40d7343Scindi static int
1382c40d7343Scindi prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err)
1383c40d7343Scindi {
1384c40d7343Scindi 	if (pv->tp_method != NULL)
1385c40d7343Scindi 		if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0)
1386c40d7343Scindi 			return (-1);
1387c40d7343Scindi 
1388c40d7343Scindi 	if (pv->tp_val == NULL) {
1389c40d7343Scindi 		*err = ETOPO_PROP_NOENT;
1390c40d7343Scindi 		return (-1);
1391c40d7343Scindi 	}
1392c40d7343Scindi 
1393c40d7343Scindi 	if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) {
1394c40d7343Scindi 		*err = ETOPO_PROP_NOMEM;
1395c40d7343Scindi 		return (-1);
1396c40d7343Scindi 	}
1397c40d7343Scindi 
1398c40d7343Scindi 	return (0);
1399c40d7343Scindi }
1400c40d7343Scindi 
1401c40d7343Scindi static int
1402c40d7343Scindi get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1403c40d7343Scindi {
1404c40d7343Scindi 	topo_node_unlock(node);
1405c40d7343Scindi 
1406c40d7343Scindi 	if (nvl != NULL)
1407c40d7343Scindi 		nvlist_free(nvl);
1408c40d7343Scindi 
1409c40d7343Scindi 	*errp = err;
1410c40d7343Scindi 
1411c40d7343Scindi 	return (-1);
1412c40d7343Scindi }
1413c40d7343Scindi 
1414c40d7343Scindi int
1415c40d7343Scindi topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp,
1416c40d7343Scindi     int *err)
1417c40d7343Scindi {
1418c40d7343Scindi 	int ret;
1419c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
1420c40d7343Scindi 	nvlist_t *nvl, *pvnvl;
1421c40d7343Scindi 	topo_pgroup_t *pg;
1422c40d7343Scindi 	topo_propval_t *pv;
1423c40d7343Scindi 	topo_proplist_t *pvl;
1424c40d7343Scindi 
1425c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1426c40d7343Scindi 		*err = ETOPO_NOMEM;
1427c40d7343Scindi 		return (-1);
1428c40d7343Scindi 	}
1429c40d7343Scindi 
1430c40d7343Scindi 	topo_node_lock(node);
1431c40d7343Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1432c40d7343Scindi 	    pg = topo_list_next(pg)) {
1433c40d7343Scindi 
1434c40d7343Scindi 		if (strcmp(pgname, pg->tpg_info->tpi_name) != 0)
1435c40d7343Scindi 			continue;
1436c40d7343Scindi 
1437c40d7343Scindi 		if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME,
1438c40d7343Scindi 		    pg->tpg_info->tpi_name) != 0 ||
1439c40d7343Scindi 		    nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB,
1440c40d7343Scindi 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1441c40d7343Scindi 		    nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB,
1442c40d7343Scindi 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1443c40d7343Scindi 		    nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION,
1444c40d7343Scindi 		    pg->tpg_info->tpi_version) != 0)
1445c40d7343Scindi 			return (get_pgrp_seterror(node, nvl, err,
1446c40d7343Scindi 			    ETOPO_PROP_NVL));
1447c40d7343Scindi 
1448c40d7343Scindi 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1449c40d7343Scindi 		    pvl = topo_list_next(pvl)) {
1450c40d7343Scindi 
1451c40d7343Scindi 			pv = pvl->tp_pval;
1452c40d7343Scindi 			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1453c40d7343Scindi 				return (get_pgrp_seterror(node, nvl, err,
1454c40d7343Scindi 				    *err));
1455c40d7343Scindi 			}
1456c40d7343Scindi 			if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL,
1457c40d7343Scindi 			    pvnvl)) != 0) {
1458c40d7343Scindi 				nvlist_free(pvnvl);
1459c40d7343Scindi 				return (get_pgrp_seterror(node, nvl, err, ret));
1460c40d7343Scindi 			}
1461c40d7343Scindi 
1462c40d7343Scindi 			nvlist_free(pvnvl);
1463c40d7343Scindi 		}
1464c40d7343Scindi 		topo_node_unlock(node);
1465c40d7343Scindi 		*pgrp = nvl;
1466c40d7343Scindi 		return (0);
1467c40d7343Scindi 	}
1468c40d7343Scindi 
1469c40d7343Scindi 	topo_node_unlock(node);
1470c40d7343Scindi 	*err = ETOPO_PROP_NOENT;
1471c40d7343Scindi 	return (-1);
1472c40d7343Scindi }
1473c40d7343Scindi 
1474c40d7343Scindi static nvlist_t *
1475c40d7343Scindi get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1476c40d7343Scindi {
1477c40d7343Scindi 	topo_node_unlock(node);
1478c40d7343Scindi 
1479c40d7343Scindi 	if (nvl != NULL)
1480c40d7343Scindi 		nvlist_free(nvl);
1481c40d7343Scindi 
1482c40d7343Scindi 	*errp = err;
1483c40d7343Scindi 
1484c40d7343Scindi 	return (NULL);
1485c40d7343Scindi }
1486c40d7343Scindi 
1487c40d7343Scindi nvlist_t *
1488c40d7343Scindi topo_prop_getprops(tnode_t *node, int *err)
1489c40d7343Scindi {
1490c40d7343Scindi 	int ret;
1491c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
1492c40d7343Scindi 	nvlist_t *nvl, *pgnvl, *pvnvl;
1493c40d7343Scindi 	topo_pgroup_t *pg;
1494c40d7343Scindi 	topo_propval_t *pv;
1495c40d7343Scindi 	topo_proplist_t *pvl;
1496c40d7343Scindi 
1497c40d7343Scindi 	topo_node_lock(node);
1498c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1499c40d7343Scindi 		return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
1500c40d7343Scindi 	}
1501c40d7343Scindi 
1502c40d7343Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1503c40d7343Scindi 	    pg = topo_list_next(pg)) {
1504c40d7343Scindi 		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
1505c40d7343Scindi 			return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
1506c40d7343Scindi 
1507c40d7343Scindi 		if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
1508c40d7343Scindi 		    pg->tpg_info->tpi_name) != 0 ||
1509c40d7343Scindi 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
1510c40d7343Scindi 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1511c40d7343Scindi 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
1512c40d7343Scindi 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1513c40d7343Scindi 		    nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
1514c40d7343Scindi 		    pg->tpg_info->tpi_version) != 0)
1515c40d7343Scindi 			return (get_all_seterror(node, nvl, err,
1516c40d7343Scindi 			    ETOPO_PROP_NVL));
1517c40d7343Scindi 
1518c40d7343Scindi 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1519c40d7343Scindi 		    pvl = topo_list_next(pvl)) {
1520c40d7343Scindi 
1521c40d7343Scindi 			pv = pvl->tp_pval;
1522c40d7343Scindi 			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1523c40d7343Scindi 				nvlist_free(pgnvl);
1524c40d7343Scindi 				return (get_all_seterror(node, nvl, err, *err));
1525c40d7343Scindi 			}
1526c40d7343Scindi 			if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
1527c40d7343Scindi 			    pvnvl)) != 0) {
1528c40d7343Scindi 				nvlist_free(pgnvl);
1529c40d7343Scindi 				nvlist_free(pvnvl);
1530c40d7343Scindi 				return (get_all_seterror(node, nvl, err, ret));
1531c40d7343Scindi 			}
1532c40d7343Scindi 
1533c40d7343Scindi 			nvlist_free(pvnvl);
1534c40d7343Scindi 		}
1535c40d7343Scindi 		if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
1536c40d7343Scindi 		    != 0) {
1537c40d7343Scindi 			nvlist_free(pgnvl);
1538c40d7343Scindi 			return (get_all_seterror(node, nvl, err, ret));
1539c40d7343Scindi 		}
1540c40d7343Scindi 
1541c40d7343Scindi 		nvlist_free(pgnvl);
1542c40d7343Scindi 	}
1543c40d7343Scindi 
1544c40d7343Scindi 	topo_node_unlock(node);
1545c40d7343Scindi 
1546c40d7343Scindi 	return (nvl);
1547c40d7343Scindi }
1548