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 /*
22e5dcf7beSRobert Johnston  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237aec1d6eScindi  * Use is subject to license terms.
247aec1d6eScindi  */
257aec1d6eScindi 
26*dd23d762SRobert Mustacchi /*
27*dd23d762SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
28*dd23d762SRobert Mustacchi  */
29*dd23d762SRobert Mustacchi 
307aec1d6eScindi #include <strings.h>
31*dd23d762SRobert Mustacchi #include <stdarg.h>
327aec1d6eScindi #include <assert.h>
337aec1d6eScindi #include <fm/libtopo.h>
347aec1d6eScindi #include <topo_prop.h>
357aec1d6eScindi #include <topo_string.h>
367aec1d6eScindi #include <topo_alloc.h>
377aec1d6eScindi #include <topo_error.h>
38c40d7343Scindi #include <topo_method.h>
39c40d7343Scindi 
40c40d7343Scindi /*
41c40d7343Scindi  * Topology nodes are permitted to contain property information.
42c40d7343Scindi  * Property information is organized according to property grouping.
43c40d7343Scindi  * Each property group defines a name, a stability level for that name,
44c40d7343Scindi  * a stability level for all underlying property data (name, type, values),
45c40d7343Scindi  * a version for the property group definition and and a list of uniquely
46c40d7343Scindi  * defined properties.  Property group versions are incremented when one of
47c40d7343Scindi  * the following changes occurs:
48c40d7343Scindi  *	- a property name changes
49c40d7343Scindi  *	- a property type changes
50c40d7343Scindi  *	- a property definition is removed from the group
51c40d7343Scindi  * Compatible changes such as new property definitions in the group do
52c40d7343Scindi  * not require version changes.
53c40d7343Scindi  *
54c40d7343Scindi  * Each property defines a unique (within the group) name, a type and
55c40d7343Scindi  * a value.  Properties may be statically defined as int32, uint32, int64,
56c40d7343Scindi  * uint64, fmri, string or arrays of each type.  Properties may also be
57c40d7343Scindi  * dynamically exported via module registered methods.  For example, a module
58c40d7343Scindi  * may register a method to export an ASRU property that is dynamically
59c40d7343Scindi  * contructed when a call to topo_node_fmri() is invoked for a particular
60c40d7343Scindi  * topology node.
61c40d7343Scindi  *
62c40d7343Scindi  * Static properties are persistently attached to topology nodes during
63c40d7343Scindi  * enumeration by an enumeration module or as part of XML statements in a
64c40d7343Scindi  * toplogy map file using the topo_prop_set* family of routines.  Similarly,
65c40d7343Scindi  * property methods are registered during enumeration or as part of
66c40d7343Scindi  * statements in topololgy map files.  Set-up of property methods is performed
67c40d7343Scindi  * by calling topo_prop_method_register().
68c40d7343Scindi  *
69c40d7343Scindi  * All properties, whether statically persisted in a snapshot or dynamically
70c40d7343Scindi  * obtained, may be read via the topo_prop_get* family of interfaces.
71c40d7343Scindi  * Callers wishing to receive all property groups and properties for a given
72c40d7343Scindi  * node may use topo_prop_getall().  This routine returns a nested nvlist
73c40d7343Scindi  * of all groupings and property (name, type, value) sets.  Groupings
74c40d7343Scindi  * are defined by TOPO_PROP_GROUP (name, data stability, name stability and
75c40d7343Scindi  * version) and a nested nvlist of properties (TOPO_PROP_VAL).  Each property
76c40d7343Scindi  * value is defined by its name, type and value.
77c40d7343Scindi  */
78c40d7343Scindi static void topo_propval_destroy(topo_propval_t *);
797aec1d6eScindi 
807aec1d6eScindi static topo_pgroup_t *
pgroup_get(tnode_t * node,const char * pgname)817aec1d6eScindi pgroup_get(tnode_t *node, const char *pgname)
827aec1d6eScindi {
837aec1d6eScindi 	topo_pgroup_t *pg;
847aec1d6eScindi 	/*
857aec1d6eScindi 	 * Check for an existing pgroup
867aec1d6eScindi 	 */
877aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
887aec1d6eScindi 	    pg = topo_list_next(pg)) {
890eb822a1Scindi 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
907aec1d6eScindi 			return (pg);
917aec1d6eScindi 		}
927aec1d6eScindi 	}
937aec1d6eScindi 
947aec1d6eScindi 	return (NULL);
957aec1d6eScindi }
967aec1d6eScindi 
977aec1d6eScindi static topo_propval_t *
propval_get(topo_pgroup_t * pg,const char * pname)987aec1d6eScindi propval_get(topo_pgroup_t *pg, const char *pname)
997aec1d6eScindi {
1007aec1d6eScindi 	topo_proplist_t *pvl;
1017aec1d6eScindi 
102c40d7343Scindi 	if (pg == NULL)
103c40d7343Scindi 		return (NULL);
104c40d7343Scindi 
1057aec1d6eScindi 	for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1067aec1d6eScindi 	    pvl = topo_list_next(pvl)) {
1077aec1d6eScindi 		if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
1087aec1d6eScindi 			return (pvl->tp_pval);
1097aec1d6eScindi 	}
1107aec1d6eScindi 
1117aec1d6eScindi 	return (NULL);
1127aec1d6eScindi }
1137aec1d6eScindi 
114c40d7343Scindi static int
method_geterror(nvlist_t * nvl,int err,int * errp)115c40d7343Scindi method_geterror(nvlist_t *nvl, int err, int *errp)
1167aec1d6eScindi {
117aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(nvl);
1187aec1d6eScindi 
119c40d7343Scindi 	*errp = err;
1207aec1d6eScindi 
121c40d7343Scindi 	return (-1);
1227aec1d6eScindi }
1237aec1d6eScindi 
1247aec1d6eScindi static int
prop_method_get(tnode_t * node,topo_propval_t * pv,topo_propmethod_t * pm,nvlist_t * pargs,int * err)125c40d7343Scindi prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm,
126c40d7343Scindi     nvlist_t *pargs, int *err)
1277aec1d6eScindi {
128c40d7343Scindi 	int ret;
129c40d7343Scindi 	nvlist_t *args, *nvl;
130c40d7343Scindi 	char *name;
131c40d7343Scindi 	topo_type_t type;
1320eb822a1Scindi 
133c40d7343Scindi 	if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 ||
134c40d7343Scindi 	    nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0)
135c40d7343Scindi 		return (method_geterror(NULL, ETOPO_PROP_NVL, err));
1360eb822a1Scindi 
137c40d7343Scindi 	if (pargs != NULL)
138c40d7343Scindi 		if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0)
139c40d7343Scindi 			return (method_geterror(args, ETOPO_PROP_NVL, err));
1400eb822a1Scindi 
1415108f83cSrobj 	/*
1425108f83cSrobj 	 * Now, get the latest value
1435108f83cSrobj 	 *
1445108f83cSrobj 	 * Grab a reference to the property and then unlock the node.  This will
1455108f83cSrobj 	 * allow property methods to safely re-enter the prop_get codepath,
1465108f83cSrobj 	 * making it possible for property methods to access other property
1475108f83cSrobj 	 * values on the same node w\o causing a deadlock.
1485108f83cSrobj 	 */
1495108f83cSrobj 	topo_prop_hold(pv);
1505108f83cSrobj 	topo_node_unlock(node);
151c40d7343Scindi 	if (topo_method_call(node, pm->tpm_name, pm->tpm_version,
1525108f83cSrobj 	    args, &nvl, err) < 0) {
15329852fb9Srobj 		topo_node_lock(node);
1545108f83cSrobj 		topo_prop_rele(pv);
155c40d7343Scindi 		return (method_geterror(args, *err, err));
1565108f83cSrobj 	}
1575108f83cSrobj 	topo_node_lock(node);
1585108f83cSrobj 	topo_prop_rele(pv);
1590eb822a1Scindi 
160c40d7343Scindi 	nvlist_free(args);
1617aec1d6eScindi 
162c40d7343Scindi 	/* Verify the property contents */
163c40d7343Scindi 	ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name);
164c40d7343Scindi 	if (ret != 0 || strcmp(name, pv->tp_name) != 0)
165c40d7343Scindi 		return (method_geterror(nvl, ETOPO_PROP_NAME, err));
1660eb822a1Scindi 
167c40d7343Scindi 	ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type);
168c40d7343Scindi 	if (ret != 0 || type != pv->tp_type)
169c40d7343Scindi 		return (method_geterror(nvl, ETOPO_PROP_TYPE, err));
1707aec1d6eScindi 
171c40d7343Scindi 	/* Release the last value and re-assign to the new value */
172aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(pv->tp_val);
173c40d7343Scindi 	pv->tp_val = nvl;
1747aec1d6eScindi 
175c40d7343Scindi 	return (0);
1767aec1d6eScindi }
1777aec1d6eScindi 
178c40d7343Scindi static topo_propval_t *
prop_get(tnode_t * node,const char * pgname,const char * pname,nvlist_t * pargs,int * err)179c40d7343Scindi prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs,
180c40d7343Scindi     int *err)
1817aec1d6eScindi {
182c40d7343Scindi 	topo_propval_t *pv = NULL;
1837aec1d6eScindi 
184c40d7343Scindi 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
185c40d7343Scindi 		*err = ETOPO_PROP_NOENT;
186c40d7343Scindi 		return (NULL);
1877aec1d6eScindi 	}
1887aec1d6eScindi 
189e5dcf7beSRobert Johnston 	if (pv->tp_flag & TOPO_PROP_NONVOLATILE && pv->tp_val != NULL)
190e5dcf7beSRobert Johnston 		return (pv);
191e5dcf7beSRobert Johnston 
192c40d7343Scindi 	if (pv->tp_method != NULL) {
193c40d7343Scindi 		if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0)
194c40d7343Scindi 			return (NULL);
1957aec1d6eScindi 	}
1967aec1d6eScindi 
197c40d7343Scindi 	return (pv);
1987aec1d6eScindi }
1997aec1d6eScindi 
2007aec1d6eScindi static int
get_properror(tnode_t * node,int * errp,int err)201c40d7343Scindi get_properror(tnode_t *node, int *errp, int err)
2027aec1d6eScindi {
2037aec1d6eScindi 	topo_node_unlock(node);
2047aec1d6eScindi 	*errp = err;
2057aec1d6eScindi 	return (-1);
2067aec1d6eScindi }
2077aec1d6eScindi 
2080eb822a1Scindi static int
prop_getval(tnode_t * node,const char * pgname,const char * pname,void * val,topo_type_t type,uint_t * nelems,int * err)2090eb822a1Scindi prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
2100eb822a1Scindi     topo_type_t type, uint_t *nelems, int *err)
2117aec1d6eScindi {
2120eb822a1Scindi 	int i, j, ret = 0;
2130eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
2147aec1d6eScindi 	topo_propval_t *pv;
2157aec1d6eScindi 
2167aec1d6eScindi 	topo_node_lock(node);
217c40d7343Scindi 	if ((pv = prop_get(node, pgname, pname, NULL, err))
2187aec1d6eScindi 	    == NULL)
219c40d7343Scindi 		return (get_properror(node, err, *err));
2207aec1d6eScindi 
2210eb822a1Scindi 	if (pv->tp_type != type)
222c40d7343Scindi 		return (get_properror(node, err, ETOPO_PROP_TYPE));
2237aec1d6eScindi 
2240eb822a1Scindi 	switch (type) {
2250eb822a1Scindi 		case TOPO_TYPE_INT32:
2260eb822a1Scindi 			ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
2270eb822a1Scindi 			    (int32_t *)val);
2280eb822a1Scindi 			break;
2290eb822a1Scindi 		case TOPO_TYPE_UINT32:
2300eb822a1Scindi 			ret = nvlist_lookup_uint32(pv->tp_val,
2310eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint32_t *)val);
2320eb822a1Scindi 			break;
2330eb822a1Scindi 		case TOPO_TYPE_INT64:
2340eb822a1Scindi 			ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
2350eb822a1Scindi 			    (int64_t *)val);
2360eb822a1Scindi 			break;
2370eb822a1Scindi 		case TOPO_TYPE_UINT64:
2380eb822a1Scindi 			ret = nvlist_lookup_uint64(pv->tp_val,
2390eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint64_t *)val);
2400eb822a1Scindi 			break;
241825ba0f2Srobj 		case TOPO_TYPE_DOUBLE:
242825ba0f2Srobj 			ret = nvlist_lookup_double(pv->tp_val,
243825ba0f2Srobj 			    TOPO_PROP_VAL_VAL, (double *)val);
244825ba0f2Srobj 			break;
2450eb822a1Scindi 		case TOPO_TYPE_STRING: {
2460eb822a1Scindi 			char *str;
2477aec1d6eScindi 
2480eb822a1Scindi 			ret = nvlist_lookup_string(pv->tp_val,
2490eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &str);
250c40d7343Scindi 			if (ret == 0) {
251c40d7343Scindi 				char *s2;
252c40d7343Scindi 				if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
253c40d7343Scindi 					ret = -1;
254c40d7343Scindi 				else
255c40d7343Scindi 					*(char **)val = s2;
256c40d7343Scindi 			}
2570eb822a1Scindi 			break;
2580eb822a1Scindi 		}
2590eb822a1Scindi 		case TOPO_TYPE_FMRI: {
2600eb822a1Scindi 			nvlist_t *nvl;
2610eb822a1Scindi 
2620eb822a1Scindi 			ret = nvlist_lookup_nvlist(pv->tp_val,
2630eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &nvl);
2640eb822a1Scindi 			if (ret == 0)
2650eb822a1Scindi 				ret = topo_hdl_nvdup(thp, nvl,
2660eb822a1Scindi 				    (nvlist_t **)val);
2670eb822a1Scindi 			break;
2680eb822a1Scindi 		}
2690eb822a1Scindi 		case TOPO_TYPE_INT32_ARRAY: {
2700eb822a1Scindi 			int32_t *a1, *a2;
2710eb822a1Scindi 
2720eb822a1Scindi 			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
2730eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
2740eb822a1Scindi 				break;
2750eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
2760eb822a1Scindi 			    *nelems)) == NULL) {
2770eb822a1Scindi 				ret = ETOPO_NOMEM;
2780eb822a1Scindi 				break;
2790eb822a1Scindi 			}
2800eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
2810eb822a1Scindi 				a1[i] = a2[i];
2820eb822a1Scindi 			*(int32_t **)val = a1;
2830eb822a1Scindi 			break;
2840eb822a1Scindi 		}
2850eb822a1Scindi 		case TOPO_TYPE_UINT32_ARRAY: {
2860eb822a1Scindi 			uint32_t *a1, *a2;
2870eb822a1Scindi 
2880eb822a1Scindi 			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
2890eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
2900eb822a1Scindi 				break;
2910eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
2920eb822a1Scindi 			    *nelems)) == NULL) {
2930eb822a1Scindi 				ret = ETOPO_NOMEM;
2940eb822a1Scindi 				break;
2950eb822a1Scindi 			}
2960eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
2970eb822a1Scindi 				a1[i] = a2[i];
2980eb822a1Scindi 			*(uint32_t **)val = a1;
2990eb822a1Scindi 			break;
3000eb822a1Scindi 		}
3010eb822a1Scindi 		case TOPO_TYPE_INT64_ARRAY: {
3020eb822a1Scindi 			int64_t *a1, *a2;
3030eb822a1Scindi 
3040eb822a1Scindi 			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
3050eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3060eb822a1Scindi 				break;
3070eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
3080eb822a1Scindi 			    *nelems)) == NULL) {
3090eb822a1Scindi 				ret = ETOPO_NOMEM;
3100eb822a1Scindi 				break;
3110eb822a1Scindi 			}
3120eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
3130eb822a1Scindi 				a1[i] = a2[i];
3140eb822a1Scindi 			*(int64_t **)val = a1;
3150eb822a1Scindi 			break;
3160eb822a1Scindi 		}
3170eb822a1Scindi 		case TOPO_TYPE_UINT64_ARRAY: {
3180eb822a1Scindi 			uint64_t *a1, *a2;
3190eb822a1Scindi 
3200eb822a1Scindi 			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
3210eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3220eb822a1Scindi 				break;
3230eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
3240eb822a1Scindi 			    *nelems)) == NULL) {
3250eb822a1Scindi 				ret = ETOPO_NOMEM;
3260eb822a1Scindi 				break;
3270eb822a1Scindi 			}
3280eb822a1Scindi 			for (i = 0; i < *nelems; ++i)
3290eb822a1Scindi 				a1[i] = a2[i];
3300eb822a1Scindi 			*(uint64_t **)val = a1;
3310eb822a1Scindi 			break;
3320eb822a1Scindi 		}
3330eb822a1Scindi 		case TOPO_TYPE_STRING_ARRAY: {
3340eb822a1Scindi 			char **a1, **a2;
3350eb822a1Scindi 
3360eb822a1Scindi 			if ((ret = nvlist_lookup_string_array(pv->tp_val,
3370eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3380eb822a1Scindi 				break;
3390eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
3400eb822a1Scindi 			    *nelems)) == NULL) {
3410eb822a1Scindi 				ret = ETOPO_NOMEM;
3420eb822a1Scindi 				break;
3430eb822a1Scindi 			}
3440eb822a1Scindi 			for (i = 0; i < *nelems; ++i) {
3450eb822a1Scindi 				if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
3460eb822a1Scindi 				    == NULL) {
3470eb822a1Scindi 					for (j = 0; j < i; ++j)
3480eb822a1Scindi 						topo_hdl_free(thp, a1[j],
3490eb822a1Scindi 						    sizeof (char *));
3500eb822a1Scindi 					topo_hdl_free(thp, a1,
3510eb822a1Scindi 					    sizeof (char *) * *nelems);
3520eb822a1Scindi 					break;
3530eb822a1Scindi 				}
3540eb822a1Scindi 			}
3550eb822a1Scindi 			*(char ***)val = a1;
3560eb822a1Scindi 			break;
3570eb822a1Scindi 		}
3580eb822a1Scindi 		case TOPO_TYPE_FMRI_ARRAY: {
3590eb822a1Scindi 			nvlist_t **a1, **a2;
3600eb822a1Scindi 
3610eb822a1Scindi 			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
3620eb822a1Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3630eb822a1Scindi 				break;
3640eb822a1Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
3650eb822a1Scindi 			    *nelems)) == NULL) {
3660eb822a1Scindi 				ret = ETOPO_NOMEM;
3670eb822a1Scindi 				break;
3680eb822a1Scindi 			}
3690eb822a1Scindi 			for (i = 0; i < *nelems; ++i) {
3700eb822a1Scindi 				if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
3710eb822a1Scindi 					for (j = 0; j < i; ++j)
3720eb822a1Scindi 						nvlist_free(a1[j]);
3730eb822a1Scindi 					topo_hdl_free(thp, a1,
3740eb822a1Scindi 					    sizeof (nvlist_t *) * *nelems);
3750eb822a1Scindi 					break;
3760eb822a1Scindi 				}
3770eb822a1Scindi 			}
3780eb822a1Scindi 			*(nvlist_t ***)val = a1;
3790eb822a1Scindi 			break;
3800eb822a1Scindi 		}
3810eb822a1Scindi 		default:
3820eb822a1Scindi 			ret = ETOPO_PROP_NOENT;
3830eb822a1Scindi 	}
3840eb822a1Scindi 
38544d6604fSRobert Mustacchi 	if (ret != 0) {
3860eb822a1Scindi 		if (ret == ENOENT)
387c40d7343Scindi 			return (get_properror(node, err, ETOPO_PROP_NOENT));
3880eb822a1Scindi 		else if (ret < ETOPO_UNKNOWN)
389c40d7343Scindi 			return (get_properror(node, err, ETOPO_PROP_NVL));
3900eb822a1Scindi 		else
391c40d7343Scindi 			return (get_properror(node, err, ret));
39244d6604fSRobert Mustacchi 	}
3937aec1d6eScindi 
3940eb822a1Scindi 	topo_node_unlock(node);
3957aec1d6eScindi 	return (0);
3967aec1d6eScindi }
3977aec1d6eScindi 
3980eb822a1Scindi int
topo_prop_get_int32(tnode_t * node,const char * pgname,const char * pname,int32_t * val,int * err)3990eb822a1Scindi topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
4000eb822a1Scindi     int32_t *val, int *err)
4010eb822a1Scindi {
4020eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32,
4030eb822a1Scindi 	    NULL, err));
4040eb822a1Scindi }
4050eb822a1Scindi 
4067aec1d6eScindi int
topo_prop_get_uint32(tnode_t * node,const char * pgname,const char * pname,uint32_t * val,int * err)4077aec1d6eScindi topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
4087aec1d6eScindi     uint32_t *val, int *err)
4097aec1d6eScindi {
4100eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32,
4110eb822a1Scindi 	    NULL, err));
4127aec1d6eScindi }
4137aec1d6eScindi 
4147aec1d6eScindi int
topo_prop_get_int64(tnode_t * node,const char * pgname,const char * pname,int64_t * val,int * err)4157aec1d6eScindi topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
4167aec1d6eScindi     int64_t *val, int *err)
4177aec1d6eScindi {
4180eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64,
4190eb822a1Scindi 	    NULL, err));
4207aec1d6eScindi }
4217aec1d6eScindi 
4227aec1d6eScindi int
topo_prop_get_uint64(tnode_t * node,const char * pgname,const char * pname,uint64_t * val,int * err)4237aec1d6eScindi topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
4247aec1d6eScindi     uint64_t *val, int *err)
4257aec1d6eScindi {
4260eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64,
4270eb822a1Scindi 	    NULL, err));
4287aec1d6eScindi }
4297aec1d6eScindi 
430825ba0f2Srobj int
topo_prop_get_double(tnode_t * node,const char * pgname,const char * pname,double * val,int * err)431825ba0f2Srobj topo_prop_get_double(tnode_t *node, const char *pgname, const char *pname,
432825ba0f2Srobj     double *val, int *err)
433825ba0f2Srobj {
434825ba0f2Srobj 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_DOUBLE,
435825ba0f2Srobj 	    NULL, err));
436825ba0f2Srobj }
437825ba0f2Srobj 
4387aec1d6eScindi int
topo_prop_get_string(tnode_t * node,const char * pgname,const char * pname,char ** val,int * err)4397aec1d6eScindi topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
4407aec1d6eScindi     char **val, int *err)
4417aec1d6eScindi {
4420eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING,
4430eb822a1Scindi 	    NULL, err));
4447aec1d6eScindi }
4457aec1d6eScindi 
4467aec1d6eScindi int
topo_prop_get_fmri(tnode_t * node,const char * pgname,const char * pname,nvlist_t ** val,int * err)4477aec1d6eScindi topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
4487aec1d6eScindi     nvlist_t **val, int *err)
4497aec1d6eScindi {
4500eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI,
4510eb822a1Scindi 	    NULL, err));
4520eb822a1Scindi }
4537aec1d6eScindi 
4540eb822a1Scindi int
topo_prop_get_int32_array(tnode_t * node,const char * pgname,const char * pname,int32_t ** val,uint_t * nelem,int * err)4550eb822a1Scindi topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname,
4560eb822a1Scindi     int32_t **val, uint_t *nelem, int *err)
4570eb822a1Scindi {
4580eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4590eb822a1Scindi 	    TOPO_TYPE_INT32_ARRAY, nelem, err));
4600eb822a1Scindi }
4617aec1d6eScindi 
4620eb822a1Scindi int
topo_prop_get_uint32_array(tnode_t * node,const char * pgname,const char * pname,uint32_t ** val,uint_t * nelem,int * err)4630eb822a1Scindi topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname,
4640eb822a1Scindi     uint32_t **val, uint_t *nelem, int *err)
4650eb822a1Scindi {
4660eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4670eb822a1Scindi 	    TOPO_TYPE_UINT32_ARRAY, nelem, err));
4680eb822a1Scindi }
4697aec1d6eScindi 
4700eb822a1Scindi int
topo_prop_get_int64_array(tnode_t * node,const char * pgname,const char * pname,int64_t ** val,uint_t * nelem,int * err)4710eb822a1Scindi topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname,
4720eb822a1Scindi     int64_t **val, uint_t *nelem, int *err)
4730eb822a1Scindi {
4740eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4750eb822a1Scindi 	    TOPO_TYPE_INT64_ARRAY, nelem, err));
4760eb822a1Scindi }
4777aec1d6eScindi 
4780eb822a1Scindi int
topo_prop_get_uint64_array(tnode_t * node,const char * pgname,const char * pname,uint64_t ** val,uint_t * nelem,int * err)4790eb822a1Scindi topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname,
4800eb822a1Scindi     uint64_t **val, uint_t *nelem, int *err)
4810eb822a1Scindi {
4820eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4830eb822a1Scindi 	    TOPO_TYPE_UINT64_ARRAY, nelem, err));
4847aec1d6eScindi }
4857aec1d6eScindi 
4860eb822a1Scindi int
topo_prop_get_string_array(tnode_t * node,const char * pgname,const char * pname,char *** val,uint_t * nelem,int * err)4870eb822a1Scindi topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname,
4880eb822a1Scindi     char ***val, uint_t *nelem, int *err)
4897aec1d6eScindi {
4900eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4910eb822a1Scindi 	    TOPO_TYPE_STRING_ARRAY, nelem, err));
4927aec1d6eScindi }
4937aec1d6eScindi 
4940eb822a1Scindi int
topo_prop_get_fmri_array(tnode_t * node,const char * pgname,const char * pname,nvlist_t *** val,uint_t * nelem,int * err)4950eb822a1Scindi topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname,
4960eb822a1Scindi     nvlist_t ***val, uint_t *nelem, int *err)
4977aec1d6eScindi {
4980eb822a1Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4990eb822a1Scindi 	    TOPO_TYPE_FMRI_ARRAY, nelem, err));
5007aec1d6eScindi }
5017aec1d6eScindi 
502c40d7343Scindi static topo_propval_t *
set_seterror(tnode_t * node,topo_proplist_t * pvl,int * errp,int err)5030eb822a1Scindi set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
5047aec1d6eScindi {
5050eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
5060eb822a1Scindi 	topo_propval_t *pv;
5070eb822a1Scindi 
5080eb822a1Scindi 	if (pvl != NULL) {
5090eb822a1Scindi 		pv = pvl->tp_pval;
510c40d7343Scindi 		topo_propval_destroy(pv);
5110eb822a1Scindi 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
5120eb822a1Scindi 	}
5137aec1d6eScindi 
5140eb822a1Scindi 	topo_node_unlock(node);
5157aec1d6eScindi 	*errp = err;
5167aec1d6eScindi 
517c40d7343Scindi 	return (NULL);
5187aec1d6eScindi }
5197aec1d6eScindi 
520c40d7343Scindi static topo_propval_t *
prop_create(tnode_t * node,const char * pgname,const char * pname,topo_type_t type,int flag,int * err)521c40d7343Scindi prop_create(tnode_t *node, const char *pgname, const char *pname,
522c40d7343Scindi     topo_type_t type, int flag, int *err)
5237aec1d6eScindi {
5247aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
5257aec1d6eScindi 	topo_pgroup_t *pg;
5267aec1d6eScindi 	topo_propval_t *pv;
5277aec1d6eScindi 	topo_proplist_t *pvl;
5287aec1d6eScindi 
5290eb822a1Scindi 	/*
5300eb822a1Scindi 	 * Replace existing prop value with new one
5310eb822a1Scindi 	 */
53212cc75c8Scindi 	if ((pg = pgroup_get(node, pgname)) == NULL) {
53312cc75c8Scindi 		topo_node_unlock(node);
53412cc75c8Scindi 		*err = ETOPO_PROP_NOENT;
535c40d7343Scindi 		return (NULL);
53612cc75c8Scindi 	}
537c40d7343Scindi 
5387aec1d6eScindi 	if ((pv = propval_get(pg, pname)) != NULL) {
5397aec1d6eScindi 		if (pv->tp_type != type)
5400eb822a1Scindi 			return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
541e5dcf7beSRobert Johnston 		else if (! (pv->tp_flag & TOPO_PROP_MUTABLE))
5420eb822a1Scindi 			return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
543c40d7343Scindi 
5440eb822a1Scindi 		nvlist_free(pv->tp_val);
5450eb822a1Scindi 		pv->tp_val = NULL;
5467aec1d6eScindi 	} else {
5477aec1d6eScindi 		if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
5487aec1d6eScindi 		    == NULL)
5490eb822a1Scindi 			return (set_seterror(node, NULL, err, ETOPO_NOMEM));
5507aec1d6eScindi 
5517aec1d6eScindi 		if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
5520eb822a1Scindi 		    == NULL)
5530eb822a1Scindi 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
55412cc75c8Scindi 
55512cc75c8Scindi 		pv->tp_hdl = thp;
5560eb822a1Scindi 		pvl->tp_pval = pv;
5570eb822a1Scindi 
5587aec1d6eScindi 		if ((pv->tp_name = topo_hdl_strdup(thp, pname))
5590eb822a1Scindi 		    == NULL)
5600eb822a1Scindi 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
5617aec1d6eScindi 		pv->tp_flag = flag;
5627aec1d6eScindi 		pv->tp_type = type;
5637aec1d6eScindi 		topo_prop_hold(pv);
564c40d7343Scindi 		topo_list_append(&pg->tpg_pvals, pvl);
5657aec1d6eScindi 	}
5667aec1d6eScindi 
567c40d7343Scindi 	return (pv);
568c40d7343Scindi }
569c40d7343Scindi 
570c40d7343Scindi 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)571c40d7343Scindi topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
572c40d7343Scindi     topo_type_t type, int flag, void *val, int nelems, int *err)
573c40d7343Scindi {
574c40d7343Scindi 	int ret;
575c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
576c40d7343Scindi 	nvlist_t *nvl;
577c40d7343Scindi 
578c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) {
579c40d7343Scindi 		*err = ETOPO_PROP_NVL;
580c40d7343Scindi 		return (-1);
581c40d7343Scindi 	}
5820eb822a1Scindi 
583c40d7343Scindi 	ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname);
584c40d7343Scindi 	ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
5857aec1d6eScindi 	switch (type) {
5867aec1d6eScindi 		case TOPO_TYPE_INT32:
587c40d7343Scindi 			ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
5880eb822a1Scindi 			    *(int32_t *)val);
5897aec1d6eScindi 			break;
5907aec1d6eScindi 		case TOPO_TYPE_UINT32:
591c40d7343Scindi 			ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
5920eb822a1Scindi 			    *(uint32_t *)val);
5937aec1d6eScindi 			break;
5947aec1d6eScindi 		case TOPO_TYPE_INT64:
595c40d7343Scindi 			ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
5960eb822a1Scindi 			    *(int64_t *)val);
5977aec1d6eScindi 			break;
5987aec1d6eScindi 		case TOPO_TYPE_UINT64:
599c40d7343Scindi 			ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
6000eb822a1Scindi 			    *(uint64_t *)val);
6017aec1d6eScindi 			break;
602825ba0f2Srobj 		case TOPO_TYPE_DOUBLE:
603825ba0f2Srobj 			ret |= nvlist_add_double(nvl, TOPO_PROP_VAL_VAL,
604825ba0f2Srobj 			    *(double *)val);
605825ba0f2Srobj 			break;
6067aec1d6eScindi 		case TOPO_TYPE_STRING:
607c40d7343Scindi 			ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
6080eb822a1Scindi 			    (char *)val);
6097aec1d6eScindi 			break;
6107aec1d6eScindi 		case TOPO_TYPE_FMRI:
611c40d7343Scindi 			ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
6120eb822a1Scindi 			    (nvlist_t *)val);
6130eb822a1Scindi 			break;
6140eb822a1Scindi 		case TOPO_TYPE_INT32_ARRAY:
615c40d7343Scindi 			ret |= nvlist_add_int32_array(nvl,
6160eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
6170eb822a1Scindi 			break;
6180eb822a1Scindi 		case TOPO_TYPE_UINT32_ARRAY:
619c40d7343Scindi 			ret |= nvlist_add_uint32_array(nvl,
6200eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
6210eb822a1Scindi 			break;
6220eb822a1Scindi 		case TOPO_TYPE_INT64_ARRAY:
623c40d7343Scindi 			ret |= nvlist_add_int64_array(nvl,
6240eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
6250eb822a1Scindi 			break;
6260eb822a1Scindi 		case TOPO_TYPE_UINT64_ARRAY:
627c40d7343Scindi 			ret |= nvlist_add_uint64_array(nvl,
6280eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
6290eb822a1Scindi 			break;
6300eb822a1Scindi 		case TOPO_TYPE_STRING_ARRAY:
631c40d7343Scindi 			ret |= nvlist_add_string_array(nvl,
6320eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (char **)val, nelems);
6330eb822a1Scindi 			break;
6340eb822a1Scindi 		case TOPO_TYPE_FMRI_ARRAY:
635c40d7343Scindi 			ret |= nvlist_add_nvlist_array(nvl,
6360eb822a1Scindi 			    TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
6377aec1d6eScindi 			break;
6387aec1d6eScindi 		default:
639c40d7343Scindi 			*err = ETOPO_PROP_TYPE;
640c40d7343Scindi 			return (-1);
6417aec1d6eScindi 	}
6427aec1d6eScindi 
6430eb822a1Scindi 	if (ret != 0) {
644c40d7343Scindi 		nvlist_free(nvl);
645c40d7343Scindi 		if (ret == ENOMEM) {
646c40d7343Scindi 			*err = ETOPO_PROP_NOMEM;
647c40d7343Scindi 			return (-1);
648c40d7343Scindi 		} else {
649c40d7343Scindi 			*err = ETOPO_PROP_NVL;
650c40d7343Scindi 			return (-1);
651c40d7343Scindi 		}
6520eb822a1Scindi 	}
6530eb822a1Scindi 
654825ba0f2Srobj 	if (topo_prop_setprop(node, pgname, nvl, flag, nvl, err) != 0) {
655c40d7343Scindi 		nvlist_free(nvl);
656825ba0f2Srobj 		return (-1); /* err set */
657c40d7343Scindi 	}
658825ba0f2Srobj 	nvlist_free(nvl);
659c40d7343Scindi 	return (ret);
6607aec1d6eScindi }
6617aec1d6eScindi 
6627aec1d6eScindi int
topo_prop_set_int32(tnode_t * node,const char * pgname,const char * pname,int flag,int32_t val,int * err)6637aec1d6eScindi topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
6647aec1d6eScindi     int flag, int32_t val, int *err)
6657aec1d6eScindi {
6667aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
6670eb822a1Scindi 	    &val, 1, err));
6687aec1d6eScindi }
6697aec1d6eScindi 
6707aec1d6eScindi int
topo_prop_set_uint32(tnode_t * node,const char * pgname,const char * pname,int flag,uint32_t val,int * err)6717aec1d6eScindi topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
6727aec1d6eScindi     int flag, uint32_t val, int *err)
6737aec1d6eScindi {
6747aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
6750eb822a1Scindi 	    &val, 1, err));
6767aec1d6eScindi }
6777aec1d6eScindi 
6787aec1d6eScindi int
topo_prop_set_int64(tnode_t * node,const char * pgname,const char * pname,int flag,int64_t val,int * err)6797aec1d6eScindi topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
6807aec1d6eScindi     int flag, int64_t val, int *err)
6817aec1d6eScindi {
6827aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
6830eb822a1Scindi 	    &val, 1, err));
6847aec1d6eScindi }
6857aec1d6eScindi 
6867aec1d6eScindi int
topo_prop_set_uint64(tnode_t * node,const char * pgname,const char * pname,int flag,uint64_t val,int * err)6877aec1d6eScindi topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
6887aec1d6eScindi     int flag, uint64_t val, int *err)
6897aec1d6eScindi {
6907aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
6910eb822a1Scindi 	    &val, 1, err));
6927aec1d6eScindi }
6937aec1d6eScindi 
694825ba0f2Srobj int
topo_prop_set_double(tnode_t * node,const char * pgname,const char * pname,int flag,double val,int * err)695825ba0f2Srobj topo_prop_set_double(tnode_t *node, const char *pgname, const char *pname,
696825ba0f2Srobj     int flag, double val, int *err)
697825ba0f2Srobj {
698825ba0f2Srobj 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_DOUBLE, flag,
699825ba0f2Srobj 	    &val, 1, err));
700825ba0f2Srobj }
701825ba0f2Srobj 
7027aec1d6eScindi int
topo_prop_set_string(tnode_t * node,const char * pgname,const char * pname,int flag,const char * val,int * err)7037aec1d6eScindi topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
7047aec1d6eScindi     int flag, const char *val, int *err)
7057aec1d6eScindi {
7067aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
7070eb822a1Scindi 	    (void *)val, 1, err));
7087aec1d6eScindi }
7097aec1d6eScindi 
7107aec1d6eScindi int
topo_prop_set_fmri(tnode_t * node,const char * pgname,const char * pname,int flag,const nvlist_t * fmri,int * err)7117aec1d6eScindi topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
7127aec1d6eScindi     int flag, const nvlist_t *fmri, int *err)
7137aec1d6eScindi {
7147aec1d6eScindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
7150eb822a1Scindi 	    (void *)fmri, 1, err));
7160eb822a1Scindi }
7170eb822a1Scindi 
7180eb822a1Scindi int
topo_prop_set_int32_array(tnode_t * node,const char * pgname,const char * pname,int flag,int32_t * val,uint_t nelems,int * err)7190eb822a1Scindi topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname,
7200eb822a1Scindi     int flag, int32_t *val, uint_t nelems, int *err)
7210eb822a1Scindi {
7220eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag,
7230eb822a1Scindi 	    val, nelems, err));
7240eb822a1Scindi }
7250eb822a1Scindi 
7260eb822a1Scindi int
topo_prop_set_uint32_array(tnode_t * node,const char * pgname,const char * pname,int flag,uint32_t * val,uint_t nelems,int * err)7270eb822a1Scindi topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname,
7280eb822a1Scindi     int flag, uint32_t *val, uint_t nelems, int *err)
7290eb822a1Scindi {
7300eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag,
7310eb822a1Scindi 	    val, nelems, err));
7320eb822a1Scindi }
7330eb822a1Scindi 
7340eb822a1Scindi int
topo_prop_set_int64_array(tnode_t * node,const char * pgname,const char * pname,int flag,int64_t * val,uint_t nelems,int * err)7350eb822a1Scindi topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname,
7360eb822a1Scindi     int flag, int64_t *val, uint_t nelems, int *err)
7370eb822a1Scindi {
7380eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag,
7390eb822a1Scindi 	    val, nelems, err));
7400eb822a1Scindi }
7410eb822a1Scindi 
7420eb822a1Scindi int
topo_prop_set_uint64_array(tnode_t * node,const char * pgname,const char * pname,int flag,uint64_t * val,uint_t nelems,int * err)7430eb822a1Scindi topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname,
7440eb822a1Scindi     int flag, uint64_t *val, uint_t nelems, int *err)
7450eb822a1Scindi {
7460eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag,
7470eb822a1Scindi 	    val, nelems, err));
7480eb822a1Scindi }
7490eb822a1Scindi 
7500eb822a1Scindi int
topo_prop_set_string_array(tnode_t * node,const char * pgname,const char * pname,int flag,const char ** val,uint_t nelems,int * err)7510eb822a1Scindi topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname,
7520eb822a1Scindi     int flag, const char **val, uint_t nelems, int *err)
7530eb822a1Scindi {
7540eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag,
7550eb822a1Scindi 	    (void *)val, nelems, err));
7560eb822a1Scindi }
7570eb822a1Scindi 
7580eb822a1Scindi int
topo_prop_set_fmri_array(tnode_t * node,const char * pgname,const char * pname,int flag,const nvlist_t ** fmri,uint_t nelems,int * err)7590eb822a1Scindi topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname,
7600eb822a1Scindi     int flag, const nvlist_t **fmri, uint_t nelems, int *err)
7610eb822a1Scindi {
7620eb822a1Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag,
7630eb822a1Scindi 	    (void *)fmri, nelems, err));
7647aec1d6eScindi }
7657aec1d6eScindi 
766c40d7343Scindi /*
767c40d7343Scindi  * topo_prop_setprop() is a private project function for fmtopo
768c40d7343Scindi  */
769c40d7343Scindi int
topo_prop_setprop(tnode_t * node,const char * pgname,nvlist_t * prop,int flag,nvlist_t * pargs,int * err)770c40d7343Scindi topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop,
771c40d7343Scindi     int flag, nvlist_t *pargs, int *err)
772c40d7343Scindi {
773c40d7343Scindi 	int ret;
774c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
775c40d7343Scindi 	topo_propval_t *pv;
776c40d7343Scindi 	nvlist_t *nvl, *args;
777c40d7343Scindi 	char *name;
778c40d7343Scindi 	topo_type_t type;
779c40d7343Scindi 
780c40d7343Scindi 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) {
781c40d7343Scindi 		*err = ETOPO_PROP_NAME;
782c40d7343Scindi 		return (-1);
783c40d7343Scindi 	}
784c40d7343Scindi 	if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type)
785c40d7343Scindi 	    != 0) {
786c40d7343Scindi 		*err = ETOPO_PROP_TYPE;
787c40d7343Scindi 		return (-1);
788c40d7343Scindi 	}
789c40d7343Scindi 
790c40d7343Scindi 	topo_node_lock(node);
791c40d7343Scindi 	if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL)
792c40d7343Scindi 		return (-1); /* unlocked and err set */
793c40d7343Scindi 
794c40d7343Scindi 	/*
795c40d7343Scindi 	 * Set by method or set to new prop value.  If we fail, leave
796c40d7343Scindi 	 * property in list with old value.
797c40d7343Scindi 	 */
798c40d7343Scindi 	if (pv->tp_method != NULL) {
799c40d7343Scindi 		topo_propmethod_t *pm = pv->tp_method;
800c40d7343Scindi 
801c40d7343Scindi 		if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) {
802c40d7343Scindi 			topo_node_unlock(node);
803c40d7343Scindi 			*err = ETOPO_PROP_NOMEM;
804c40d7343Scindi 			return (-1);
805c40d7343Scindi 		}
806c40d7343Scindi 		ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args);
807c40d7343Scindi 		if (pargs != NULL)
808c40d7343Scindi 			ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs);
809c40d7343Scindi 
810c40d7343Scindi 		if (ret != 0) {
811c40d7343Scindi 			topo_node_unlock(node);
812c40d7343Scindi 			nvlist_free(args);
813c40d7343Scindi 			*err = ETOPO_PROP_NVL;
814c40d7343Scindi 			return (-1);
815c40d7343Scindi 		}
816c40d7343Scindi 
8175108f83cSrobj 		/*
8185108f83cSrobj 		 *
8195108f83cSrobj 		 * Grab a reference to the property and then unlock the node.
8205108f83cSrobj 		 * This will allow property methods to safely re-enter the
8215108f83cSrobj 		 * prop_get codepath, making it possible for property methods
8225108f83cSrobj 		 * to access other property values on the same node w\o causing
8235108f83cSrobj 		 * a deadlock.
8245108f83cSrobj 		 *
8255108f83cSrobj 		 * We don't technically need this now, since this interface is
8265108f83cSrobj 		 * currently only used by fmtopo (which is single-threaded), but
8275108f83cSrobj 		 * we may make this interface available to other parts of
8285108f83cSrobj 		 * libtopo in the future, so best to make it MT-safe now.
8295108f83cSrobj 		 */
8305108f83cSrobj 		topo_prop_hold(pv);
8315108f83cSrobj 		topo_node_unlock(node);
832c40d7343Scindi 		ret = topo_method_call(node, pm->tpm_name, pm->tpm_version,
833c40d7343Scindi 		    args, &nvl, err);
8345108f83cSrobj 		topo_node_lock(node);
8355108f83cSrobj 		topo_prop_rele(pv);
8365108f83cSrobj 
837c40d7343Scindi 		nvlist_free(args);
838c40d7343Scindi 	} else {
839c40d7343Scindi 		if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0)
840c40d7343Scindi 			*err = ETOPO_PROP_NOMEM;
841c40d7343Scindi 	}
842c40d7343Scindi 
843c40d7343Scindi 	if (ret != 0) {
844c40d7343Scindi 		topo_node_unlock(node);
845c40d7343Scindi 		return (-1);
846c40d7343Scindi 	}
847c40d7343Scindi 
848c40d7343Scindi 	pv->tp_val = nvl;
849c40d7343Scindi 	topo_node_unlock(node);
850c40d7343Scindi 	return (0);
851c40d7343Scindi }
852c40d7343Scindi 
853c40d7343Scindi static int
register_methoderror(tnode_t * node,topo_propmethod_t * pm,int * errp,int l,int err)854c40d7343Scindi register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
855c40d7343Scindi     int err)
856c40d7343Scindi {
857c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
858c40d7343Scindi 
859c40d7343Scindi 	if (pm != NULL) {
860c40d7343Scindi 		if (pm->tpm_name != NULL)
861c40d7343Scindi 			topo_hdl_strfree(thp, pm->tpm_name);
862aab83bb8SJosef 'Jeff' Sipek 		nvlist_free(pm->tpm_args);
863c40d7343Scindi 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
864c40d7343Scindi 	}
865c40d7343Scindi 
866c40d7343Scindi 	*errp = err;
867c40d7343Scindi 
868c40d7343Scindi 	if (l != 0)
869c40d7343Scindi 		topo_node_unlock(node);
870c40d7343Scindi 
871c40d7343Scindi 	return (-1);
872c40d7343Scindi }
873c40d7343Scindi 
874c40d7343Scindi 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)875c40d7343Scindi prop_method_register(tnode_t *node, const char *pgname, const char *pname,
876c40d7343Scindi     topo_type_t ptype, const char *mname, topo_version_t version,
877c40d7343Scindi     const nvlist_t *args, int *err)
878c40d7343Scindi {
879c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
880c40d7343Scindi 	topo_propmethod_t *pm = NULL;
881c40d7343Scindi 	topo_propval_t *pv = NULL;
882c40d7343Scindi 
883c40d7343Scindi 	if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL)
884c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
885c40d7343Scindi 		    ETOPO_PROP_NOMEM));
886c40d7343Scindi 
887c40d7343Scindi 	if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL)
888c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
889c40d7343Scindi 		    ETOPO_PROP_NOMEM));
890c40d7343Scindi 
891c40d7343Scindi 	pm->tpm_version = version;
892c40d7343Scindi 
893c40d7343Scindi 	if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0)
894c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
895c40d7343Scindi 		    ETOPO_PROP_NOMEM));
896c40d7343Scindi 
8972eeaed14Srobj 	/*
8982eeaed14Srobj 	 * It's possible the property may already exist.  However we still want
8992eeaed14Srobj 	 * to allow the method to be registered.  This is to handle the case
900e5dcf7beSRobert Johnston 	 * where we specify a prop method in an xml map to override the value
9012eeaed14Srobj 	 * that was set by the enumerator.
902825ba0f2Srobj 	 *
903e5dcf7beSRobert Johnston 	 * By default, propmethod-backed properties are not MUTABLE.  This is
904e5dcf7beSRobert Johnston 	 * done to simplify the programming model for modules that implement
905e5dcf7beSRobert Johnston 	 * property methods as most propmethods tend to only support get
906e5dcf7beSRobert Johnston 	 * operations.  Enumerator modules can override this by calling
907e5dcf7beSRobert Johnston 	 * topo_prop_setmutable().  Propmethods that are registered via XML can
908e5dcf7beSRobert Johnston 	 * be set as mutable via the optional "mutable" attribute, which will
909e5dcf7beSRobert Johnston 	 * result in the xml parser calling topo_prop_setflags() after
910e5dcf7beSRobert Johnston 	 * registering the propmethod.
9112eeaed14Srobj 	 */
9122eeaed14Srobj 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL)
9132eeaed14Srobj 		if ((pv = prop_create(node, pgname, pname, ptype,
914825ba0f2Srobj 		    TOPO_PROP_IMMUTABLE, err)) == NULL) {
9152eeaed14Srobj 			/* node unlocked */
9162eeaed14Srobj 			return (register_methoderror(node, pm, err, 0, *err));
9172eeaed14Srobj 		}
918c40d7343Scindi 
9194557a2a1Srobj 	if (pv->tp_method != NULL)
920c40d7343Scindi 		return (register_methoderror(node, pm, err, 1,
921c40d7343Scindi 		    ETOPO_METHOD_DEFD));
922c40d7343Scindi 
9232eeaed14Srobj 	if (pv->tp_val != NULL) {
9242eeaed14Srobj 		nvlist_free(pv->tp_val);
9252eeaed14Srobj 		pv->tp_val = NULL;
9262eeaed14Srobj 	}
927c40d7343Scindi 	pv->tp_method = pm;
928c40d7343Scindi 
929c40d7343Scindi 	topo_node_unlock(node);
930c40d7343Scindi 
931c40d7343Scindi 	return (0);
932c40d7343Scindi }
933c40d7343Scindi 
934c40d7343Scindi 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)935c40d7343Scindi topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname,
936c40d7343Scindi     topo_type_t ptype, const char *mname, const nvlist_t *args, int *err)
937c40d7343Scindi {
938c40d7343Scindi 	topo_imethod_t *mp;
939c40d7343Scindi 
940c40d7343Scindi 	topo_node_lock(node);
941c40d7343Scindi 
942c40d7343Scindi 	if ((mp = topo_method_lookup(node, mname)) == NULL)
943c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
9444557a2a1Srobj 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
9454557a2a1Srobj 
9464557a2a1Srobj 	topo_node_lock(node);
947c40d7343Scindi 
948c40d7343Scindi 	return (prop_method_register(node, pgname, pname, ptype, mname,
949c40d7343Scindi 	    mp->tim_version, args, err)); /* err set and node unlocked */
950c40d7343Scindi }
951c40d7343Scindi 
952c40d7343Scindi 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)953c40d7343Scindi topo_prop_method_version_register(tnode_t *node, const char *pgname,
954c40d7343Scindi     const char *pname, topo_type_t ptype, const char *mname,
955c40d7343Scindi     topo_version_t version, const nvlist_t *args, int *err)
956c40d7343Scindi {
957c40d7343Scindi 	topo_imethod_t *mp;
958c40d7343Scindi 
959c40d7343Scindi 	topo_node_lock(node);
960c40d7343Scindi 
961c40d7343Scindi 	if ((mp = topo_method_lookup(node, mname)) == NULL)
962c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
9634557a2a1Srobj 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
9644557a2a1Srobj 
9654557a2a1Srobj 	topo_node_lock(node);
966c40d7343Scindi 
967c40d7343Scindi 	if (version < mp->tim_version)
968c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
969c40d7343Scindi 		    ETOPO_METHOD_VEROLD));
970c40d7343Scindi 	if (version > mp->tim_version)
971c40d7343Scindi 		return (register_methoderror(node, NULL, err, 1,
972c40d7343Scindi 		    ETOPO_METHOD_VERNEW));
973c40d7343Scindi 
974c40d7343Scindi 	return (prop_method_register(node, pgname, pname, ptype, mname,
975c40d7343Scindi 	    version, args, err)); /* err set and node unlocked */
976c40d7343Scindi }
977c40d7343Scindi 
978c40d7343Scindi void
topo_prop_method_unregister(tnode_t * node,const char * pgname,const char * pname)979c40d7343Scindi topo_prop_method_unregister(tnode_t *node, const char *pgname,
980c40d7343Scindi     const char *pname)
981c40d7343Scindi {
982c40d7343Scindi 	topo_propval_t *pv;
983c40d7343Scindi 	topo_pgroup_t *pg;
984c40d7343Scindi 	topo_proplist_t *pvl;
985c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
986c40d7343Scindi 
987c40d7343Scindi 	topo_node_lock(node);
988c40d7343Scindi 
989c40d7343Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
990c40d7343Scindi 	    pg = topo_list_next(pg)) {
991c40d7343Scindi 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
992c40d7343Scindi 			break;
993c40d7343Scindi 		}
994c40d7343Scindi 	}
995c40d7343Scindi 
996c40d7343Scindi 	if (pg == NULL) {
997c40d7343Scindi 		topo_node_unlock(node);
998c40d7343Scindi 		return;
999c40d7343Scindi 	}
1000c40d7343Scindi 
1001c40d7343Scindi 	for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
1002c40d7343Scindi 	    pvl = topo_list_next(pvl)) {
1003c40d7343Scindi 		pv = pvl->tp_pval;
1004c40d7343Scindi 		if (strcmp(pv->tp_name, pname) == 0) {
1005c40d7343Scindi 			topo_list_delete(&pg->tpg_pvals, pvl);
1006c40d7343Scindi 			assert(pv->tp_refs == 1);
1007c40d7343Scindi 			topo_prop_rele(pv);
1008c40d7343Scindi 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1009c40d7343Scindi 			break;
1010c40d7343Scindi 		}
1011c40d7343Scindi 	}
1012c40d7343Scindi 
1013c40d7343Scindi 	topo_node_unlock(node);
1014c40d7343Scindi }
1015c40d7343Scindi 
1016825ba0f2Srobj int
topo_prop_setmutable(tnode_t * node,const char * pgname,const char * pname,int * err)1017825ba0f2Srobj topo_prop_setmutable(tnode_t *node, const char *pgname, const char *pname,
1018825ba0f2Srobj     int *err)
1019825ba0f2Srobj {
1020825ba0f2Srobj 	topo_propval_t *pv = NULL;
1021825ba0f2Srobj 
1022825ba0f2Srobj 	topo_node_lock(node);
1023825ba0f2Srobj 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1024825ba0f2Srobj 		topo_node_unlock(node);
1025825ba0f2Srobj 		*err = ETOPO_PROP_NOENT;
1026825ba0f2Srobj 		return (-1);
1027825ba0f2Srobj 	}
1028825ba0f2Srobj 
1029825ba0f2Srobj 	/*
1030825ba0f2Srobj 	 * If the property is being inherited then we don't want to allow a
1031825ba0f2Srobj 	 * change from IMMUTABLE to MUTABLE.
1032825ba0f2Srobj 	 */
1033825ba0f2Srobj 	if (pv->tp_refs > 1) {
1034825ba0f2Srobj 		topo_node_unlock(node);
1035825ba0f2Srobj 		*err = ETOPO_PROP_DEFD;
1036825ba0f2Srobj 		return (-1);
1037825ba0f2Srobj 	}
1038e5dcf7beSRobert Johnston 	pv->tp_flag |= TOPO_PROP_MUTABLE;
1039e5dcf7beSRobert Johnston 
1040e5dcf7beSRobert Johnston 	topo_node_unlock(node);
1041e5dcf7beSRobert Johnston 
1042e5dcf7beSRobert Johnston 	return (0);
1043e5dcf7beSRobert Johnston }
1044e5dcf7beSRobert Johnston int
topo_prop_setnonvolatile(tnode_t * node,const char * pgname,const char * pname,int * err)1045e5dcf7beSRobert Johnston topo_prop_setnonvolatile(tnode_t *node, const char *pgname, const char *pname,
1046e5dcf7beSRobert Johnston     int *err)
1047e5dcf7beSRobert Johnston {
1048e5dcf7beSRobert Johnston 	topo_propval_t *pv = NULL;
1049e5dcf7beSRobert Johnston 
1050e5dcf7beSRobert Johnston 	topo_node_lock(node);
1051e5dcf7beSRobert Johnston 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1052e5dcf7beSRobert Johnston 		topo_node_unlock(node);
1053e5dcf7beSRobert Johnston 		*err = ETOPO_PROP_NOENT;
1054e5dcf7beSRobert Johnston 		return (-1);
1055e5dcf7beSRobert Johnston 	}
1056e5dcf7beSRobert Johnston 
1057e5dcf7beSRobert Johnston 	pv->tp_flag |= TOPO_PROP_NONVOLATILE;
1058825ba0f2Srobj 
1059825ba0f2Srobj 	topo_node_unlock(node);
1060825ba0f2Srobj 
1061825ba0f2Srobj 	return (0);
1062825ba0f2Srobj }
1063825ba0f2Srobj 
10647aec1d6eScindi static int
inherit_seterror(tnode_t * node,int * errp,int err)10657aec1d6eScindi inherit_seterror(tnode_t *node, int *errp, int err)
10667aec1d6eScindi {
10677aec1d6eScindi 	topo_node_unlock(node);
10687aec1d6eScindi 	topo_node_unlock(node->tn_parent);
10697aec1d6eScindi 
10707aec1d6eScindi 	*errp = err;
10717aec1d6eScindi 
10727aec1d6eScindi 	return (-1);
10737aec1d6eScindi }
10747aec1d6eScindi 
10757aec1d6eScindi int
topo_prop_inherit(tnode_t * node,const char * pgname,const char * name,int * err)10767aec1d6eScindi topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
10777aec1d6eScindi {
10787aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
10797aec1d6eScindi 	tnode_t *pnode = node->tn_parent;
10807aec1d6eScindi 	topo_pgroup_t *pg;
10817aec1d6eScindi 	topo_propval_t *pv;
10827aec1d6eScindi 	topo_proplist_t *pvl;
10837aec1d6eScindi 
10847aec1d6eScindi 	topo_node_lock(pnode);
10857aec1d6eScindi 	topo_node_lock(node);
10862eeaed14Srobj 
10872eeaed14Srobj 	/*
10882eeaed14Srobj 	 * Check if the requested property group and prop val are already set
10892eeaed14Srobj 	 * on the node.
10902eeaed14Srobj 	 */
10912eeaed14Srobj 	if (propval_get(pgroup_get(node, pgname), name) != NULL)
10922eeaed14Srobj 		return (inherit_seterror(node, err, ETOPO_PROP_DEFD));
10932eeaed14Srobj 
10947aec1d6eScindi 	/*
10952eeaed14Srobj 	 * Check if the requested property group and prop val exists on the
10962eeaed14Srobj 	 * parent node
10977aec1d6eScindi 	 */
1098c40d7343Scindi 	if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
10997aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
11007aec1d6eScindi 
11017aec1d6eScindi 	/*
11027aec1d6eScindi 	 * Can this propval be inherited?
11037aec1d6eScindi 	 */
1104e5dcf7beSRobert Johnston 	if (pv->tp_flag & TOPO_PROP_MUTABLE)
11057aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
11067aec1d6eScindi 
11077aec1d6eScindi 	/*
11087aec1d6eScindi 	 * Property group should already exist: bump the ref count for this
11097aec1d6eScindi 	 * propval and add it to the node's property group
11107aec1d6eScindi 	 */
11117aec1d6eScindi 	if ((pg = pgroup_get(node, pgname)) == NULL)
11127aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
11137aec1d6eScindi 
11147aec1d6eScindi 	if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
11157aec1d6eScindi 	    == NULL)
11167aec1d6eScindi 		return (inherit_seterror(node, err, ETOPO_NOMEM));
11177aec1d6eScindi 
11187aec1d6eScindi 	topo_prop_hold(pv);
11197aec1d6eScindi 	pvl->tp_pval = pv;
11207aec1d6eScindi 	topo_list_append(&pg->tpg_pvals, pvl);
11217aec1d6eScindi 
11227aec1d6eScindi 	topo_node_unlock(node);
11237aec1d6eScindi 	topo_node_unlock(pnode);
11247aec1d6eScindi 
11257aec1d6eScindi 	return (0);
11267aec1d6eScindi }
11277aec1d6eScindi 
11280eb822a1Scindi topo_pgroup_info_t *
topo_pgroup_info(tnode_t * node,const char * pgname,int * err)11290eb822a1Scindi topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
11307aec1d6eScindi {
11310eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
11327aec1d6eScindi 	topo_pgroup_t *pg;
11330eb822a1Scindi 	topo_ipgroup_info_t *pip;
11340eb822a1Scindi 	topo_pgroup_info_t *info;
11357aec1d6eScindi 
11360eb822a1Scindi 	topo_node_lock(node);
11377aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
11387aec1d6eScindi 	    pg = topo_list_next(pg)) {
11390eb822a1Scindi 		if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
11400eb822a1Scindi 			if ((info = topo_hdl_alloc(thp,
11410eb822a1Scindi 			    sizeof (topo_pgroup_info_t))) == NULL)
11420eb822a1Scindi 				return (NULL);
11430eb822a1Scindi 
11440eb822a1Scindi 			pip = pg->tpg_info;
11450eb822a1Scindi 			if ((info->tpi_name =
114612cc75c8Scindi 			    topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
11470eb822a1Scindi 				*err = ETOPO_PROP_NOMEM;
11480eb822a1Scindi 				topo_hdl_free(thp, info,
11490eb822a1Scindi 				    sizeof (topo_pgroup_info_t));
11500eb822a1Scindi 				topo_node_unlock(node);
11510eb822a1Scindi 				return (NULL);
11520eb822a1Scindi 			}
11530eb822a1Scindi 			info->tpi_namestab = pip->tpi_namestab;
11540eb822a1Scindi 			info->tpi_datastab = pip->tpi_datastab;
11550eb822a1Scindi 			info->tpi_version = pip->tpi_version;
11560eb822a1Scindi 			topo_node_unlock(node);
11570eb822a1Scindi 			return (info);
11587aec1d6eScindi 		}
11597aec1d6eScindi 	}
11607aec1d6eScindi 
11610eb822a1Scindi 	*err = ETOPO_PROP_NOENT;
11620eb822a1Scindi 	topo_node_unlock(node);
11630eb822a1Scindi 	return (NULL);
11640eb822a1Scindi }
11650eb822a1Scindi 
11660eb822a1Scindi static int
pgroup_seterr(tnode_t * node,topo_pgroup_t * pg,topo_ipgroup_info_t * pip,int * err)11670eb822a1Scindi pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
11680eb822a1Scindi     int *err)
11690eb822a1Scindi {
11700eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
11710eb822a1Scindi 
11720eb822a1Scindi 	if (pip != NULL) {
11730eb822a1Scindi 		if (pip->tpi_name != NULL)
11740eb822a1Scindi 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
11750eb822a1Scindi 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
11760eb822a1Scindi 	}
11770eb822a1Scindi 
11780eb822a1Scindi 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
11790eb822a1Scindi 	*err = ETOPO_NOMEM;
11800eb822a1Scindi 
11810eb822a1Scindi 	topo_node_unlock(node);
11820eb822a1Scindi 
11837aec1d6eScindi 	return (-1);
11847aec1d6eScindi }
11857aec1d6eScindi 
11867aec1d6eScindi int
topo_pgroup_create(tnode_t * node,const topo_pgroup_info_t * pinfo,int * err)11870eb822a1Scindi topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err)
11887aec1d6eScindi {
11897aec1d6eScindi 	topo_pgroup_t *pg;
11900eb822a1Scindi 	topo_ipgroup_info_t *pip;
11910eb822a1Scindi 	topo_hdl_t *thp = node->tn_hdl;
11927aec1d6eScindi 
11937aec1d6eScindi 	*err = 0;
11947aec1d6eScindi 
11950eb822a1Scindi 	topo_node_lock(node);
11967aec1d6eScindi 	/*
11977aec1d6eScindi 	 * Check for an existing pgroup
11987aec1d6eScindi 	 */
11997aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
12007aec1d6eScindi 	    pg = topo_list_next(pg)) {
12010eb822a1Scindi 		if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) {
12027aec1d6eScindi 			*err = ETOPO_PROP_DEFD;
12030eb822a1Scindi 			topo_node_unlock(node);
12047aec1d6eScindi 			return (-1);
12057aec1d6eScindi 		}
12067aec1d6eScindi 	}
12077aec1d6eScindi 
12080eb822a1Scindi 	if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) {
12097aec1d6eScindi 		*err = ETOPO_NOMEM;
12100eb822a1Scindi 		topo_node_unlock(node);
12117aec1d6eScindi 		return (-1);
12127aec1d6eScindi 	}
12137aec1d6eScindi 
12140eb822a1Scindi 	if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t)))
12150eb822a1Scindi 	    == NULL)
12160eb822a1Scindi 		return (pgroup_seterr(node, pg, pip, err));
12177aec1d6eScindi 
12180eb822a1Scindi 	if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name))
12190eb822a1Scindi 	    == NULL)
12200eb822a1Scindi 		return (pgroup_seterr(node, pg, pip, err));
12210eb822a1Scindi 
12220eb822a1Scindi 	pip->tpi_namestab = pinfo->tpi_namestab;
12230eb822a1Scindi 	pip->tpi_datastab = pinfo->tpi_datastab;
12240eb822a1Scindi 	pip->tpi_version = pinfo->tpi_version;
12250eb822a1Scindi 
12260eb822a1Scindi 	pg->tpg_info = pip;
12277aec1d6eScindi 
12287aec1d6eScindi 	topo_list_append(&node->tn_pgroups, pg);
12290eb822a1Scindi 	topo_node_unlock(node);
12307aec1d6eScindi 
12317aec1d6eScindi 	return (0);
12327aec1d6eScindi }
12337aec1d6eScindi 
12347aec1d6eScindi void
topo_pgroup_destroy(tnode_t * node,const char * pname)12357aec1d6eScindi topo_pgroup_destroy(tnode_t *node, const char *pname)
12367aec1d6eScindi {
12377aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
12387aec1d6eScindi 	topo_pgroup_t *pg;
12397aec1d6eScindi 	topo_proplist_t *pvl;
12400eb822a1Scindi 	topo_ipgroup_info_t *pip;
12417aec1d6eScindi 
12427aec1d6eScindi 	topo_node_lock(node);
12437aec1d6eScindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
12447aec1d6eScindi 	    pg = topo_list_next(pg)) {
12450eb822a1Scindi 		if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
12467aec1d6eScindi 			break;
12477aec1d6eScindi 		}
12487aec1d6eScindi 	}
12497aec1d6eScindi 
12507aec1d6eScindi 	if (pg == NULL) {
12517aec1d6eScindi 		topo_node_unlock(node);
12527aec1d6eScindi 		return;
12537aec1d6eScindi 	}
12547aec1d6eScindi 
12557aec1d6eScindi 	while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
12567aec1d6eScindi 		topo_list_delete(&pg->tpg_pvals, pvl);
12577aec1d6eScindi 		topo_prop_rele(pvl->tp_pval);
12587aec1d6eScindi 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
12597aec1d6eScindi 	}
12607aec1d6eScindi 
12617aec1d6eScindi 	topo_list_delete(&node->tn_pgroups, pg);
12620eb822a1Scindi 	topo_node_unlock(node);
12637aec1d6eScindi 
12640eb822a1Scindi 	pip = pg->tpg_info;
12650eb822a1Scindi 	if (pip != NULL) {
12660eb822a1Scindi 		if (pip->tpi_name != NULL)
12670eb822a1Scindi 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
12680eb822a1Scindi 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
12690eb822a1Scindi 	}
12707aec1d6eScindi 
12710eb822a1Scindi 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
12727aec1d6eScindi }
12737aec1d6eScindi 
12747aec1d6eScindi void
topo_pgroup_destroy_all(tnode_t * node)12757aec1d6eScindi topo_pgroup_destroy_all(tnode_t *node)
12767aec1d6eScindi {
12777aec1d6eScindi 	topo_hdl_t *thp = node->tn_hdl;
12787aec1d6eScindi 	topo_pgroup_t *pg;
12797aec1d6eScindi 	topo_proplist_t *pvl;
12800eb822a1Scindi 	topo_ipgroup_info_t *pip;
12817aec1d6eScindi 
12827aec1d6eScindi 	topo_node_lock(node);
12837aec1d6eScindi 	while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
12847aec1d6eScindi 		while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
12857aec1d6eScindi 			topo_list_delete(&pg->tpg_pvals, pvl);
12867aec1d6eScindi 			topo_prop_rele(pvl->tp_pval);
12877aec1d6eScindi 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
12887aec1d6eScindi 		}
12897aec1d6eScindi 
12907aec1d6eScindi 		topo_list_delete(&node->tn_pgroups, pg);
12917aec1d6eScindi 
12920eb822a1Scindi 		pip = pg->tpg_info;
12930eb822a1Scindi 		if (pip != NULL) {
12940eb822a1Scindi 			if (pip->tpi_name != NULL)
12950eb822a1Scindi 				topo_hdl_strfree(thp, (char *)pip->tpi_name);
12960eb822a1Scindi 			topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
12970eb822a1Scindi 		}
12980eb822a1Scindi 
12997aec1d6eScindi 		topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
13007aec1d6eScindi 	}
13017aec1d6eScindi 	topo_node_unlock(node);
13027aec1d6eScindi }
1303c40d7343Scindi 
1304c40d7343Scindi static void
propmethod_destroy(topo_hdl_t * thp,topo_propval_t * pv)1305c40d7343Scindi propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
1306c40d7343Scindi {
1307c40d7343Scindi 	topo_propmethod_t *pm;
1308c40d7343Scindi 
1309c40d7343Scindi 	pm = pv->tp_method;
1310c40d7343Scindi 	if (pm != NULL) {
1311c40d7343Scindi 		if (pm->tpm_name != NULL)
1312c40d7343Scindi 			topo_hdl_strfree(thp, pm->tpm_name);
1313aab83bb8SJosef 'Jeff' Sipek 		nvlist_free(pm->tpm_args);
1314c40d7343Scindi 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
1315c40d7343Scindi 		pv->tp_method = NULL;
1316c40d7343Scindi 	}
1317c40d7343Scindi }
1318c40d7343Scindi 
13197aec1d6eScindi static void
topo_propval_destroy(topo_propval_t * pv)13207aec1d6eScindi topo_propval_destroy(topo_propval_t *pv)
13217aec1d6eScindi {
1322c40d7343Scindi 	topo_hdl_t *thp;
1323c40d7343Scindi 
1324c40d7343Scindi 	if (pv == NULL)
1325c40d7343Scindi 		return;
1326c40d7343Scindi 
1327c40d7343Scindi 	thp = pv->tp_hdl;
13287aec1d6eScindi 
13297aec1d6eScindi 	if (pv->tp_name != NULL)
13307aec1d6eScindi 		topo_hdl_strfree(thp, pv->tp_name);
13317aec1d6eScindi 
1332aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(pv->tp_val);
13337aec1d6eScindi 
1334c40d7343Scindi 	propmethod_destroy(thp, pv);
1335c40d7343Scindi 
13367aec1d6eScindi 	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
13377aec1d6eScindi }
13387aec1d6eScindi 
13397aec1d6eScindi void
topo_prop_hold(topo_propval_t * pv)13407aec1d6eScindi topo_prop_hold(topo_propval_t *pv)
13417aec1d6eScindi {
13427aec1d6eScindi 	pv->tp_refs++;
13437aec1d6eScindi }
13447aec1d6eScindi 
13457aec1d6eScindi void
topo_prop_rele(topo_propval_t * pv)13467aec1d6eScindi topo_prop_rele(topo_propval_t *pv)
13477aec1d6eScindi {
13487aec1d6eScindi 	pv->tp_refs--;
13497aec1d6eScindi 
13507aec1d6eScindi 	assert(pv->tp_refs >= 0);
13517aec1d6eScindi 
13527aec1d6eScindi 	if (pv->tp_refs == 0)
13537aec1d6eScindi 		topo_propval_destroy(pv);
13547aec1d6eScindi }
1355c40d7343Scindi 
1356c40d7343Scindi /*
1357c40d7343Scindi  * topo_prop_getprop() and topo_prop_getprops() are private project functions
1358c40d7343Scindi  * for fmtopo
1359c40d7343Scindi  */
1360c40d7343Scindi int
topo_prop_getprop(tnode_t * node,const char * pgname,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)1361c40d7343Scindi topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname,
1362c40d7343Scindi     nvlist_t *args, nvlist_t **prop, int *err)
1363c40d7343Scindi {
1364c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
1365c40d7343Scindi 	topo_propval_t *pv;
1366c40d7343Scindi 
1367c40d7343Scindi 	topo_node_lock(node);
1368c40d7343Scindi 	if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) {
1369c40d7343Scindi 		(void) get_properror(node, err, *err);
1370c40d7343Scindi 		return (-1);
1371c40d7343Scindi 	}
1372c40d7343Scindi 
1373c40d7343Scindi 	if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) {
1374c40d7343Scindi 		(void) get_properror(node, err, ETOPO_NOMEM);
1375c40d7343Scindi 		return (-1);
1376c40d7343Scindi 	}
1377c40d7343Scindi 	topo_node_unlock(node);
1378c40d7343Scindi 
1379c40d7343Scindi 	return (0);
1380c40d7343Scindi }
1381c40d7343Scindi 
1382c40d7343Scindi static int
prop_val_add(tnode_t * node,nvlist_t ** nvl,topo_propval_t * pv,int * err)1383c40d7343Scindi prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err)
1384c40d7343Scindi {
1385c40d7343Scindi 	if (pv->tp_method != NULL)
1386c40d7343Scindi 		if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0)
1387c40d7343Scindi 			return (-1);
1388c40d7343Scindi 
1389c40d7343Scindi 	if (pv->tp_val == NULL) {
1390c40d7343Scindi 		*err = ETOPO_PROP_NOENT;
1391c40d7343Scindi 		return (-1);
1392c40d7343Scindi 	}
1393c40d7343Scindi 
1394c40d7343Scindi 	if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) {
1395c40d7343Scindi 		*err = ETOPO_PROP_NOMEM;
1396c40d7343Scindi 		return (-1);
1397c40d7343Scindi 	}
1398c40d7343Scindi 
1399c40d7343Scindi 	return (0);
1400c40d7343Scindi }
1401c40d7343Scindi 
1402c40d7343Scindi static int
get_pgrp_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)1403c40d7343Scindi get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1404c40d7343Scindi {
1405c40d7343Scindi 	topo_node_unlock(node);
1406c40d7343Scindi 
1407aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(nvl);
1408c40d7343Scindi 
1409c40d7343Scindi 	*errp = err;
1410c40d7343Scindi 
1411c40d7343Scindi 	return (-1);
1412c40d7343Scindi }
1413c40d7343Scindi 
1414c40d7343Scindi int
topo_prop_getpgrp(tnode_t * node,const char * pgname,nvlist_t ** pgrp,int * err)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 *
get_all_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)1475c40d7343Scindi get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1476c40d7343Scindi {
1477c40d7343Scindi 	topo_node_unlock(node);
1478c40d7343Scindi 
1479aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(nvl);
1480c40d7343Scindi 
1481c40d7343Scindi 	*errp = err;
1482c40d7343Scindi 
1483c40d7343Scindi 	return (NULL);
1484c40d7343Scindi }
1485c40d7343Scindi 
1486c40d7343Scindi nvlist_t *
topo_prop_getprops(tnode_t * node,int * err)1487c40d7343Scindi topo_prop_getprops(tnode_t *node, int *err)
1488c40d7343Scindi {
1489c40d7343Scindi 	int ret;
1490c40d7343Scindi 	topo_hdl_t *thp = node->tn_hdl;
1491c40d7343Scindi 	nvlist_t *nvl, *pgnvl, *pvnvl;
1492c40d7343Scindi 	topo_pgroup_t *pg;
1493c40d7343Scindi 	topo_propval_t *pv;
1494c40d7343Scindi 	topo_proplist_t *pvl;
1495c40d7343Scindi 
1496c40d7343Scindi 	topo_node_lock(node);
1497c40d7343Scindi 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1498c40d7343Scindi 		return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
1499c40d7343Scindi 	}
1500c40d7343Scindi 
1501c40d7343Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1502c40d7343Scindi 	    pg = topo_list_next(pg)) {
1503c40d7343Scindi 		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
1504c40d7343Scindi 			return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
1505c40d7343Scindi 
1506c40d7343Scindi 		if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
1507c40d7343Scindi 		    pg->tpg_info->tpi_name) != 0 ||
1508c40d7343Scindi 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
1509c40d7343Scindi 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1510c40d7343Scindi 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
1511c40d7343Scindi 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1512c40d7343Scindi 		    nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
1513c40d7343Scindi 		    pg->tpg_info->tpi_version) != 0)
1514c40d7343Scindi 			return (get_all_seterror(node, nvl, err,
1515c40d7343Scindi 			    ETOPO_PROP_NVL));
1516c40d7343Scindi 
1517c40d7343Scindi 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1518c40d7343Scindi 		    pvl = topo_list_next(pvl)) {
1519c40d7343Scindi 
1520c40d7343Scindi 			pv = pvl->tp_pval;
1521c40d7343Scindi 			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1522c40d7343Scindi 				nvlist_free(pgnvl);
1523c40d7343Scindi 				return (get_all_seterror(node, nvl, err, *err));
1524c40d7343Scindi 			}
1525c40d7343Scindi 			if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
1526c40d7343Scindi 			    pvnvl)) != 0) {
1527c40d7343Scindi 				nvlist_free(pgnvl);
1528c40d7343Scindi 				nvlist_free(pvnvl);
1529c40d7343Scindi 				return (get_all_seterror(node, nvl, err, ret));
1530c40d7343Scindi 			}
1531c40d7343Scindi 
1532c40d7343Scindi 			nvlist_free(pvnvl);
1533c40d7343Scindi 		}
1534c40d7343Scindi 		if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
1535c40d7343Scindi 		    != 0) {
1536c40d7343Scindi 			nvlist_free(pgnvl);
1537c40d7343Scindi 			return (get_all_seterror(node, nvl, err, ret));
1538c40d7343Scindi 		}
1539c40d7343Scindi 
1540c40d7343Scindi 		nvlist_free(pgnvl);
1541c40d7343Scindi 	}
1542c40d7343Scindi 
1543c40d7343Scindi 	topo_node_unlock(node);
1544c40d7343Scindi 
1545c40d7343Scindi 	return (nvl);
1546c40d7343Scindi }
1547*dd23d762SRobert Mustacchi 
1548*dd23d762SRobert Mustacchi /*
1549*dd23d762SRobert Mustacchi  * This is a convenience function for modules in the spirit of
1550*dd23d762SRobert Mustacchi  * nvlist_get_pairs(). Most modules want to create a property group (which may
1551*dd23d762SRobert Mustacchi  * already exist) and then set a number of properties. If setting any one
1552*dd23d762SRobert Mustacchi  * property fails then the operation will fail and they are responsible for
1553*dd23d762SRobert Mustacchi  * tearing down the node or failing the operation.
1554*dd23d762SRobert Mustacchi  */
1555*dd23d762SRobert Mustacchi int
topo_create_props(topo_mod_t * mod,tnode_t * tn,int prop_flags,const topo_pgroup_info_t * grp,...)1556*dd23d762SRobert Mustacchi topo_create_props(topo_mod_t *mod, tnode_t *tn, int prop_flags,
1557*dd23d762SRobert Mustacchi     const topo_pgroup_info_t *grp, ...)
1558*dd23d762SRobert Mustacchi {
1559*dd23d762SRobert Mustacchi 	va_list ap;
1560*dd23d762SRobert Mustacchi 	const char *prop;
1561*dd23d762SRobert Mustacchi 	int ret = 0, err;
1562*dd23d762SRobert Mustacchi 
1563*dd23d762SRobert Mustacchi 	if (topo_pgroup_create(tn, grp, &err) != 0 && err != ETOPO_PROP_DEFD) {
1564*dd23d762SRobert Mustacchi 		topo_mod_dprintf(mod, "failed to create property group %s: %s",
1565*dd23d762SRobert Mustacchi 		    grp->tpi_name, topo_strerror(err));
1566*dd23d762SRobert Mustacchi 		return (topo_mod_seterrno(mod, err));
1567*dd23d762SRobert Mustacchi 	}
1568*dd23d762SRobert Mustacchi 
1569*dd23d762SRobert Mustacchi 	va_start(ap, grp);
1570*dd23d762SRobert Mustacchi 	while ((prop = va_arg(ap, const char *)) != NULL) {
1571*dd23d762SRobert Mustacchi 		topo_type_t type = va_arg(ap, topo_type_t);
1572*dd23d762SRobert Mustacchi 
1573*dd23d762SRobert Mustacchi 		switch (type) {
1574*dd23d762SRobert Mustacchi 		case TOPO_TYPE_INT32: {
1575*dd23d762SRobert Mustacchi 			int32_t val = va_arg(ap, int32_t);
1576*dd23d762SRobert Mustacchi 			ret = topo_prop_set_int32(tn, grp->tpi_name, prop,
1577*dd23d762SRobert Mustacchi 			    prop_flags, val, &err);
1578*dd23d762SRobert Mustacchi 			break;
1579*dd23d762SRobert Mustacchi 		}
1580*dd23d762SRobert Mustacchi 		case TOPO_TYPE_UINT32: {
1581*dd23d762SRobert Mustacchi 			uint32_t val = va_arg(ap, uint32_t);
1582*dd23d762SRobert Mustacchi 			ret = topo_prop_set_uint32(tn, grp->tpi_name, prop,
1583*dd23d762SRobert Mustacchi 			    prop_flags, val, &err);
1584*dd23d762SRobert Mustacchi 			break;
1585*dd23d762SRobert Mustacchi 		}
1586*dd23d762SRobert Mustacchi 		case TOPO_TYPE_INT64: {
1587*dd23d762SRobert Mustacchi 			int64_t val = va_arg(ap, int64_t);
1588*dd23d762SRobert Mustacchi 			ret = topo_prop_set_int64(tn, grp->tpi_name, prop,
1589*dd23d762SRobert Mustacchi 			    prop_flags, val, &err);
1590*dd23d762SRobert Mustacchi 			break;
1591*dd23d762SRobert Mustacchi 		}
1592*dd23d762SRobert Mustacchi 		case TOPO_TYPE_UINT64: {
1593*dd23d762SRobert Mustacchi 			uint64_t val = va_arg(ap, uint64_t);
1594*dd23d762SRobert Mustacchi 			ret = topo_prop_set_uint64(tn, grp->tpi_name, prop,
1595*dd23d762SRobert Mustacchi 			    prop_flags, val, &err);
1596*dd23d762SRobert Mustacchi 			break;
1597*dd23d762SRobert Mustacchi 		}
1598*dd23d762SRobert Mustacchi 		case TOPO_TYPE_STRING: {
1599*dd23d762SRobert Mustacchi 			const char *val = va_arg(ap, const char *);
1600*dd23d762SRobert Mustacchi 			ret = topo_prop_set_string(tn, grp->tpi_name, prop,
1601*dd23d762SRobert Mustacchi 			    prop_flags, val, &err);
1602*dd23d762SRobert Mustacchi 			break;
1603*dd23d762SRobert Mustacchi 		}
1604*dd23d762SRobert Mustacchi 		case TOPO_TYPE_FMRI: {
1605*dd23d762SRobert Mustacchi 			const nvlist_t *val = va_arg(ap, const nvlist_t *);
1606*dd23d762SRobert Mustacchi 			ret = topo_prop_set_fmri(tn, grp->tpi_name, prop,
1607*dd23d762SRobert Mustacchi 			    prop_flags, val, &err);
1608*dd23d762SRobert Mustacchi 			break;
1609*dd23d762SRobert Mustacchi 		}
1610*dd23d762SRobert Mustacchi 		case TOPO_TYPE_INT32_ARRAY: {
1611*dd23d762SRobert Mustacchi 			int32_t *vals = va_arg(ap, int32_t *);
1612*dd23d762SRobert Mustacchi 			uint_t count = va_arg(ap, uint_t);
1613*dd23d762SRobert Mustacchi 			ret = topo_prop_set_int32_array(tn, grp->tpi_name,
1614*dd23d762SRobert Mustacchi 			    prop, prop_flags, vals, count, &err);
1615*dd23d762SRobert Mustacchi 			break;
1616*dd23d762SRobert Mustacchi 		}
1617*dd23d762SRobert Mustacchi 		case TOPO_TYPE_UINT32_ARRAY: {
1618*dd23d762SRobert Mustacchi 			uint32_t *vals = va_arg(ap, uint32_t *);
1619*dd23d762SRobert Mustacchi 			uint_t count = va_arg(ap, uint_t);
1620*dd23d762SRobert Mustacchi 			ret = topo_prop_set_uint32_array(tn, grp->tpi_name,
1621*dd23d762SRobert Mustacchi 			    prop, prop_flags, vals, count, &err);
1622*dd23d762SRobert Mustacchi 			break;
1623*dd23d762SRobert Mustacchi 		}
1624*dd23d762SRobert Mustacchi 		case TOPO_TYPE_INT64_ARRAY: {
1625*dd23d762SRobert Mustacchi 			int64_t *vals = va_arg(ap, int64_t *);
1626*dd23d762SRobert Mustacchi 			uint_t count = va_arg(ap, uint_t);
1627*dd23d762SRobert Mustacchi 			ret = topo_prop_set_int64_array(tn, grp->tpi_name,
1628*dd23d762SRobert Mustacchi 			    prop, prop_flags, vals, count, &err);
1629*dd23d762SRobert Mustacchi 			break;
1630*dd23d762SRobert Mustacchi 		}
1631*dd23d762SRobert Mustacchi 		case TOPO_TYPE_UINT64_ARRAY: {
1632*dd23d762SRobert Mustacchi 			uint64_t *vals = va_arg(ap, uint64_t *);
1633*dd23d762SRobert Mustacchi 			uint_t count = va_arg(ap, uint_t);
1634*dd23d762SRobert Mustacchi 			ret = topo_prop_set_uint64_array(tn, grp->tpi_name,
1635*dd23d762SRobert Mustacchi 			    prop, prop_flags, vals, count, &err);
1636*dd23d762SRobert Mustacchi 			break;
1637*dd23d762SRobert Mustacchi 		}
1638*dd23d762SRobert Mustacchi 		case TOPO_TYPE_STRING_ARRAY: {
1639*dd23d762SRobert Mustacchi 			const char **vals = va_arg(ap, const char **);
1640*dd23d762SRobert Mustacchi 			uint_t count = va_arg(ap, uint_t);
1641*dd23d762SRobert Mustacchi 			ret = topo_prop_set_string_array(tn, grp->tpi_name,
1642*dd23d762SRobert Mustacchi 			    prop, prop_flags, vals, count, &err);
1643*dd23d762SRobert Mustacchi 			break;
1644*dd23d762SRobert Mustacchi 		}
1645*dd23d762SRobert Mustacchi 		case TOPO_TYPE_FMRI_ARRAY: {
1646*dd23d762SRobert Mustacchi 			const nvlist_t **vals = va_arg(ap, const nvlist_t **);
1647*dd23d762SRobert Mustacchi 			uint_t count = va_arg(ap, uint_t);
1648*dd23d762SRobert Mustacchi 			ret = topo_prop_set_fmri_array(tn, grp->tpi_name,
1649*dd23d762SRobert Mustacchi 			    prop, prop_flags, vals, count, &err);
1650*dd23d762SRobert Mustacchi 			break;
1651*dd23d762SRobert Mustacchi 		}
1652*dd23d762SRobert Mustacchi 		case TOPO_TYPE_DOUBLE: {
1653*dd23d762SRobert Mustacchi 			double val = va_arg(ap, double);
1654*dd23d762SRobert Mustacchi 			ret = topo_prop_set_double(tn, grp->tpi_name, prop,
1655*dd23d762SRobert Mustacchi 			    prop_flags, val, &err);
1656*dd23d762SRobert Mustacchi 			break;
1657*dd23d762SRobert Mustacchi 		}
1658*dd23d762SRobert Mustacchi 		default:
1659*dd23d762SRobert Mustacchi 			topo_mod_dprintf(mod, "cannot set property %s with "
1660*dd23d762SRobert Mustacchi 			    "unsupported and unknown type 0x%x\n", prop,
1661*dd23d762SRobert Mustacchi 			    type);
1662*dd23d762SRobert Mustacchi 			va_end(ap);
1663*dd23d762SRobert Mustacchi 			return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
1664*dd23d762SRobert Mustacchi 		}
1665*dd23d762SRobert Mustacchi 
1666*dd23d762SRobert Mustacchi 		if (ret != 0) {
1667*dd23d762SRobert Mustacchi 			topo_mod_dprintf(mod, "failed to create %s property "
1668*dd23d762SRobert Mustacchi 			    "%s: %s\n", grp->tpi_name, prop,
1669*dd23d762SRobert Mustacchi 			    topo_strerror(err));
1670*dd23d762SRobert Mustacchi 			va_end(ap);
1671*dd23d762SRobert Mustacchi 			return (topo_mod_seterrno(mod, err));
1672*dd23d762SRobert Mustacchi 		}
1673*dd23d762SRobert Mustacchi 	}
1674*dd23d762SRobert Mustacchi 
1675*dd23d762SRobert Mustacchi 	va_end(ap);
1676*dd23d762SRobert Mustacchi 	return (0);
1677*dd23d762SRobert Mustacchi }
1678