xref: /onnv-gate/usr/src/lib/fm/topo/libtopo/common/topo_prop.c (revision 8526:8159d305568c)
11414Scindi /*
21414Scindi  * CDDL HEADER START
31414Scindi  *
41414Scindi  * The contents of this file are subject to the terms of the
51414Scindi  * Common Development and Distribution License (the "License").
61414Scindi  * You may not use this file except in compliance with the License.
71414Scindi  *
81414Scindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91414Scindi  * or http://www.opensolaris.org/os/licensing.
101414Scindi  * See the License for the specific language governing permissions
111414Scindi  * and limitations under the License.
121414Scindi  *
131414Scindi  * When distributing Covered Code, include this CDDL HEADER in each
141414Scindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151414Scindi  * If applicable, add the following below this CDDL HEADER, with the
161414Scindi  * fields enclosed by brackets "[]" replaced with your own identifying
171414Scindi  * information: Portions Copyright [yyyy] [name of copyright owner]
181414Scindi  *
191414Scindi  * CDDL HEADER END
201414Scindi  */
211414Scindi /*
22*8526SRobert.Johnston@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
231414Scindi  * Use is subject to license terms.
241414Scindi  */
251414Scindi 
261414Scindi #include <strings.h>
271414Scindi #include <assert.h>
281414Scindi #include <fm/libtopo.h>
291414Scindi #include <topo_prop.h>
301414Scindi #include <topo_string.h>
311414Scindi #include <topo_alloc.h>
321414Scindi #include <topo_error.h>
334087Scindi #include <topo_method.h>
344087Scindi 
354087Scindi /*
364087Scindi  * Topology nodes are permitted to contain property information.
374087Scindi  * Property information is organized according to property grouping.
384087Scindi  * Each property group defines a name, a stability level for that name,
394087Scindi  * a stability level for all underlying property data (name, type, values),
404087Scindi  * a version for the property group definition and and a list of uniquely
414087Scindi  * defined properties.  Property group versions are incremented when one of
424087Scindi  * the following changes occurs:
434087Scindi  *	- a property name changes
444087Scindi  *	- a property type changes
454087Scindi  *	- a property definition is removed from the group
464087Scindi  * Compatible changes such as new property definitions in the group do
474087Scindi  * not require version changes.
484087Scindi  *
494087Scindi  * Each property defines a unique (within the group) name, a type and
504087Scindi  * a value.  Properties may be statically defined as int32, uint32, int64,
514087Scindi  * uint64, fmri, string or arrays of each type.  Properties may also be
524087Scindi  * dynamically exported via module registered methods.  For example, a module
534087Scindi  * may register a method to export an ASRU property that is dynamically
544087Scindi  * contructed when a call to topo_node_fmri() is invoked for a particular
554087Scindi  * topology node.
564087Scindi  *
574087Scindi  * Static properties are persistently attached to topology nodes during
584087Scindi  * enumeration by an enumeration module or as part of XML statements in a
594087Scindi  * toplogy map file using the topo_prop_set* family of routines.  Similarly,
604087Scindi  * property methods are registered during enumeration or as part of
614087Scindi  * statements in topololgy map files.  Set-up of property methods is performed
624087Scindi  * by calling topo_prop_method_register().
634087Scindi  *
644087Scindi  * All properties, whether statically persisted in a snapshot or dynamically
654087Scindi  * obtained, may be read via the topo_prop_get* family of interfaces.
664087Scindi  * Callers wishing to receive all property groups and properties for a given
674087Scindi  * node may use topo_prop_getall().  This routine returns a nested nvlist
684087Scindi  * of all groupings and property (name, type, value) sets.  Groupings
694087Scindi  * are defined by TOPO_PROP_GROUP (name, data stability, name stability and
704087Scindi  * version) and a nested nvlist of properties (TOPO_PROP_VAL).  Each property
714087Scindi  * value is defined by its name, type and value.
724087Scindi  */
734087Scindi static void topo_propval_destroy(topo_propval_t *);
741414Scindi 
751414Scindi static topo_pgroup_t *
pgroup_get(tnode_t * node,const char * pgname)761414Scindi pgroup_get(tnode_t *node, const char *pgname)
771414Scindi {
781414Scindi 	topo_pgroup_t *pg;
791414Scindi 	/*
801414Scindi 	 * Check for an existing pgroup
811414Scindi 	 */
821414Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
831414Scindi 	    pg = topo_list_next(pg)) {
843062Scindi 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
851414Scindi 			return (pg);
861414Scindi 		}
871414Scindi 	}
881414Scindi 
891414Scindi 	return (NULL);
901414Scindi }
911414Scindi 
921414Scindi static topo_propval_t *
propval_get(topo_pgroup_t * pg,const char * pname)931414Scindi propval_get(topo_pgroup_t *pg, const char *pname)
941414Scindi {
951414Scindi 	topo_proplist_t *pvl;
961414Scindi 
974087Scindi 	if (pg == NULL)
984087Scindi 		return (NULL);
994087Scindi 
1001414Scindi 	for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1011414Scindi 	    pvl = topo_list_next(pvl)) {
1021414Scindi 		if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
1031414Scindi 			return (pvl->tp_pval);
1041414Scindi 	}
1051414Scindi 
1061414Scindi 	return (NULL);
1071414Scindi }
1081414Scindi 
1094087Scindi static int
method_geterror(nvlist_t * nvl,int err,int * errp)1104087Scindi method_geterror(nvlist_t *nvl, int err, int *errp)
1114087Scindi {
1124087Scindi 	if (nvl != NULL)
1134087Scindi 		nvlist_free(nvl);
1144087Scindi 
1154087Scindi 	*errp = err;
1164087Scindi 
1174087Scindi 	return (-1);
1184087Scindi }
1194087Scindi 
1204087Scindi static int
prop_method_get(tnode_t * node,topo_propval_t * pv,topo_propmethod_t * pm,nvlist_t * pargs,int * err)1214087Scindi prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm,
1224087Scindi     nvlist_t *pargs, int *err)
1234087Scindi {
1244087Scindi 	int ret;
1254087Scindi 	nvlist_t *args, *nvl;
1264087Scindi 	char *name;
1274087Scindi 	topo_type_t type;
1284087Scindi 
1294087Scindi 	if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 ||
1304087Scindi 	    nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0)
1314087Scindi 		return (method_geterror(NULL, ETOPO_PROP_NVL, err));
1324087Scindi 
1334087Scindi 	if (pargs != NULL)
1344087Scindi 		if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0)
1354087Scindi 			return (method_geterror(args, ETOPO_PROP_NVL, err));
1364087Scindi 
1375590Srobj 	/*
1385590Srobj 	 * Now, get the latest value
1395590Srobj 	 *
1405590Srobj 	 * Grab a reference to the property and then unlock the node.  This will
1415590Srobj 	 * allow property methods to safely re-enter the prop_get codepath,
1425590Srobj 	 * making it possible for property methods to access other property
1435590Srobj 	 * values on the same node w\o causing a deadlock.
1445590Srobj 	 */
1455590Srobj 	topo_prop_hold(pv);
1465590Srobj 	topo_node_unlock(node);
1474087Scindi 	if (topo_method_call(node, pm->tpm_name, pm->tpm_version,
1485590Srobj 	    args, &nvl, err) < 0) {
1495646Srobj 		topo_node_lock(node);
1505590Srobj 		topo_prop_rele(pv);
1514087Scindi 		return (method_geterror(args, *err, err));
1525590Srobj 	}
1535590Srobj 	topo_node_lock(node);
1545590Srobj 	topo_prop_rele(pv);
1554087Scindi 
1564087Scindi 	nvlist_free(args);
1574087Scindi 
1584087Scindi 	/* Verify the property contents */
1594087Scindi 	ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name);
1604087Scindi 	if (ret != 0 || strcmp(name, pv->tp_name) != 0)
1614087Scindi 		return (method_geterror(nvl, ETOPO_PROP_NAME, err));
1624087Scindi 
1634087Scindi 	ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type);
1644087Scindi 	if (ret != 0 || type != pv->tp_type)
1654087Scindi 		return (method_geterror(nvl, ETOPO_PROP_TYPE, err));
1664087Scindi 
1674087Scindi 	/* Release the last value and re-assign to the new value */
1684087Scindi 	if (pv->tp_val != NULL)
1694087Scindi 		nvlist_free(pv->tp_val);
1704087Scindi 	pv->tp_val = nvl;
1714087Scindi 
1724087Scindi 	return (0);
1734087Scindi }
1744087Scindi 
1751414Scindi static topo_propval_t *
prop_get(tnode_t * node,const char * pgname,const char * pname,nvlist_t * pargs,int * err)1764087Scindi prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs,
1774087Scindi     int *err)
1781414Scindi {
1791414Scindi 	topo_propval_t *pv = NULL;
1801414Scindi 
1814087Scindi 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1821414Scindi 		*err = ETOPO_PROP_NOENT;
1831414Scindi 		return (NULL);
1841414Scindi 	}
1851414Scindi 
186*8526SRobert.Johnston@Sun.COM 	if (pv->tp_flag & TOPO_PROP_NONVOLATILE && pv->tp_val != NULL)
187*8526SRobert.Johnston@Sun.COM 		return (pv);
188*8526SRobert.Johnston@Sun.COM 
1894087Scindi 	if (pv->tp_method != NULL) {
1904087Scindi 		if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0)
1914087Scindi 			return (NULL);
1921414Scindi 	}
1931414Scindi 
1941414Scindi 	return (pv);
1951414Scindi }
1961414Scindi 
1971414Scindi static int
get_properror(tnode_t * node,int * errp,int err)1984087Scindi get_properror(tnode_t *node, int *errp, int err)
1991414Scindi {
2001414Scindi 	topo_node_unlock(node);
2011414Scindi 	*errp = err;
2021414Scindi 	return (-1);
2031414Scindi }
2041414Scindi 
2053062Scindi static int
prop_getval(tnode_t * node,const char * pgname,const char * pname,void * val,topo_type_t type,uint_t * nelems,int * err)2063062Scindi prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
2073062Scindi     topo_type_t type, uint_t *nelems, int *err)
2081414Scindi {
2093062Scindi 	int i, j, ret = 0;
2103062Scindi 	topo_hdl_t *thp = node->tn_hdl;
2111414Scindi 	topo_propval_t *pv;
2121414Scindi 
2131414Scindi 	topo_node_lock(node);
2144087Scindi 	if ((pv = prop_get(node, pgname, pname, NULL, err))
2151414Scindi 	    == NULL)
2164087Scindi 		return (get_properror(node, err, *err));
2171414Scindi 
2183062Scindi 	if (pv->tp_type != type)
2194087Scindi 		return (get_properror(node, err, ETOPO_PROP_TYPE));
2201414Scindi 
2213062Scindi 	switch (type) {
2223062Scindi 		case TOPO_TYPE_INT32:
2233062Scindi 			ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
2243062Scindi 			    (int32_t *)val);
2253062Scindi 			break;
2263062Scindi 		case TOPO_TYPE_UINT32:
2273062Scindi 			ret = nvlist_lookup_uint32(pv->tp_val,
2283062Scindi 			    TOPO_PROP_VAL_VAL, (uint32_t *)val);
2293062Scindi 			break;
2303062Scindi 		case TOPO_TYPE_INT64:
2313062Scindi 			ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
2323062Scindi 			    (int64_t *)val);
2333062Scindi 			break;
2343062Scindi 		case TOPO_TYPE_UINT64:
2353062Scindi 			ret = nvlist_lookup_uint64(pv->tp_val,
2363062Scindi 			    TOPO_PROP_VAL_VAL, (uint64_t *)val);
2373062Scindi 			break;
2387243Srobj 		case TOPO_TYPE_DOUBLE:
2397243Srobj 			ret = nvlist_lookup_double(pv->tp_val,
2407243Srobj 			    TOPO_PROP_VAL_VAL, (double *)val);
2417243Srobj 			break;
2423062Scindi 		case TOPO_TYPE_STRING: {
2433062Scindi 			char *str;
2443062Scindi 
2453062Scindi 			ret = nvlist_lookup_string(pv->tp_val,
2463062Scindi 			    TOPO_PROP_VAL_VAL, &str);
2474087Scindi 			if (ret == 0) {
2484087Scindi 				char *s2;
2494087Scindi 				if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
2504087Scindi 					ret = -1;
2514087Scindi 				else
2524087Scindi 					*(char **)val = s2;
2534087Scindi 			}
2543062Scindi 			break;
2553062Scindi 		}
2563062Scindi 		case TOPO_TYPE_FMRI: {
2573062Scindi 			nvlist_t *nvl;
2583062Scindi 
2593062Scindi 			ret = nvlist_lookup_nvlist(pv->tp_val,
2603062Scindi 			    TOPO_PROP_VAL_VAL, &nvl);
2613062Scindi 			if (ret == 0)
2623062Scindi 				ret = topo_hdl_nvdup(thp, nvl,
2633062Scindi 				    (nvlist_t **)val);
2643062Scindi 			break;
2653062Scindi 		}
2663062Scindi 		case TOPO_TYPE_INT32_ARRAY: {
2673062Scindi 			int32_t *a1, *a2;
2683062Scindi 
2693062Scindi 			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
2703062Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
2713062Scindi 				break;
2723062Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
2733062Scindi 			    *nelems)) == NULL) {
2743062Scindi 				ret = ETOPO_NOMEM;
2753062Scindi 				break;
2763062Scindi 			}
2773062Scindi 			for (i = 0; i < *nelems; ++i)
2783062Scindi 				a1[i] = a2[i];
2793062Scindi 			*(int32_t **)val = a1;
2803062Scindi 			break;
2813062Scindi 		}
2823062Scindi 		case TOPO_TYPE_UINT32_ARRAY: {
2833062Scindi 			uint32_t *a1, *a2;
2843062Scindi 
2853062Scindi 			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
2863062Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
2873062Scindi 				break;
2883062Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
2893062Scindi 			    *nelems)) == NULL) {
2903062Scindi 				ret = ETOPO_NOMEM;
2913062Scindi 				break;
2923062Scindi 			}
2933062Scindi 			for (i = 0; i < *nelems; ++i)
2943062Scindi 				a1[i] = a2[i];
2953062Scindi 			*(uint32_t **)val = a1;
2963062Scindi 			break;
2973062Scindi 		}
2983062Scindi 		case TOPO_TYPE_INT64_ARRAY: {
2993062Scindi 			int64_t *a1, *a2;
3003062Scindi 
3013062Scindi 			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
3023062Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3033062Scindi 				break;
3043062Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
3053062Scindi 			    *nelems)) == NULL) {
3063062Scindi 				ret = ETOPO_NOMEM;
3073062Scindi 				break;
3083062Scindi 			}
3093062Scindi 			for (i = 0; i < *nelems; ++i)
3103062Scindi 				a1[i] = a2[i];
3113062Scindi 			*(int64_t **)val = a1;
3123062Scindi 			break;
3133062Scindi 		}
3143062Scindi 		case TOPO_TYPE_UINT64_ARRAY: {
3153062Scindi 			uint64_t *a1, *a2;
3163062Scindi 
3173062Scindi 			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
3183062Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3193062Scindi 				break;
3203062Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
3213062Scindi 			    *nelems)) == NULL) {
3223062Scindi 				ret = ETOPO_NOMEM;
3233062Scindi 				break;
3243062Scindi 			}
3253062Scindi 			for (i = 0; i < *nelems; ++i)
3263062Scindi 				a1[i] = a2[i];
3273062Scindi 			*(uint64_t **)val = a1;
3283062Scindi 			break;
3293062Scindi 		}
3303062Scindi 		case TOPO_TYPE_STRING_ARRAY: {
3313062Scindi 			char **a1, **a2;
3323062Scindi 
3333062Scindi 			if ((ret = nvlist_lookup_string_array(pv->tp_val,
3343062Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3353062Scindi 				break;
3363062Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
3373062Scindi 			    *nelems)) == NULL) {
3383062Scindi 				ret = ETOPO_NOMEM;
3393062Scindi 				break;
3403062Scindi 			}
3413062Scindi 			for (i = 0; i < *nelems; ++i) {
3423062Scindi 				if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
3433062Scindi 				    == NULL) {
3443062Scindi 					for (j = 0; j < i; ++j)
3453062Scindi 						topo_hdl_free(thp, a1[j],
3463062Scindi 						    sizeof (char *));
3473062Scindi 					topo_hdl_free(thp, a1,
3483062Scindi 					    sizeof (char *) * *nelems);
3493062Scindi 					break;
3503062Scindi 				}
3513062Scindi 			}
3523062Scindi 			*(char ***)val = a1;
3533062Scindi 			break;
3543062Scindi 		}
3553062Scindi 		case TOPO_TYPE_FMRI_ARRAY: {
3563062Scindi 			nvlist_t **a1, **a2;
3573062Scindi 
3583062Scindi 			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
3593062Scindi 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
3603062Scindi 				break;
3613062Scindi 			if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
3623062Scindi 			    *nelems)) == NULL) {
3633062Scindi 				ret = ETOPO_NOMEM;
3643062Scindi 				break;
3653062Scindi 			}
3663062Scindi 			for (i = 0; i < *nelems; ++i) {
3673062Scindi 				if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
3683062Scindi 					for (j = 0; j < i; ++j)
3693062Scindi 						nvlist_free(a1[j]);
3703062Scindi 					topo_hdl_free(thp, a1,
3713062Scindi 					    sizeof (nvlist_t *) * *nelems);
3723062Scindi 					break;
3733062Scindi 				}
3743062Scindi 			}
3753062Scindi 			*(nvlist_t ***)val = a1;
3763062Scindi 			break;
3773062Scindi 		}
3783062Scindi 		default:
3793062Scindi 			ret = ETOPO_PROP_NOENT;
3803062Scindi 	}
3813062Scindi 
3823062Scindi 	if (ret != 0)
3833062Scindi 		if (ret == ENOENT)
3844087Scindi 			return (get_properror(node, err, ETOPO_PROP_NOENT));
3853062Scindi 		else if (ret < ETOPO_UNKNOWN)
3864087Scindi 			return (get_properror(node, err, ETOPO_PROP_NVL));
3873062Scindi 		else
3884087Scindi 			return (get_properror(node, err, ret));
3891414Scindi 
3901414Scindi 	topo_node_unlock(node);
3913062Scindi 	return (0);
3923062Scindi }
3931414Scindi 
3943062Scindi int
topo_prop_get_int32(tnode_t * node,const char * pgname,const char * pname,int32_t * val,int * err)3953062Scindi topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
3963062Scindi     int32_t *val, int *err)
3973062Scindi {
3983062Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32,
3993062Scindi 	    NULL, err));
4003062Scindi }
4013062Scindi 
4023062Scindi int
topo_prop_get_uint32(tnode_t * node,const char * pgname,const char * pname,uint32_t * val,int * err)4033062Scindi topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
4043062Scindi     uint32_t *val, int *err)
4053062Scindi {
4063062Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32,
4073062Scindi 	    NULL, err));
4083062Scindi }
4093062Scindi 
4103062Scindi int
topo_prop_get_int64(tnode_t * node,const char * pgname,const char * pname,int64_t * val,int * err)4113062Scindi topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
4123062Scindi     int64_t *val, int *err)
4133062Scindi {
4143062Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64,
4153062Scindi 	    NULL, err));
4163062Scindi }
4173062Scindi 
4183062Scindi int
topo_prop_get_uint64(tnode_t * node,const char * pgname,const char * pname,uint64_t * val,int * err)4193062Scindi topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
4203062Scindi     uint64_t *val, int *err)
4213062Scindi {
4223062Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64,
4233062Scindi 	    NULL, err));
4241414Scindi }
4251414Scindi 
4261414Scindi int
topo_prop_get_double(tnode_t * node,const char * pgname,const char * pname,double * val,int * err)4277243Srobj topo_prop_get_double(tnode_t *node, const char *pgname, const char *pname,
4287243Srobj     double *val, int *err)
4297243Srobj {
4307243Srobj 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_DOUBLE,
4317243Srobj 	    NULL, err));
4327243Srobj }
4337243Srobj 
4347243Srobj int
topo_prop_get_string(tnode_t * node,const char * pgname,const char * pname,char ** val,int * err)4351414Scindi topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
4361414Scindi     char **val, int *err)
4371414Scindi {
4383062Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING,
4393062Scindi 	    NULL, err));
4401414Scindi }
4411414Scindi 
4421414Scindi int
topo_prop_get_fmri(tnode_t * node,const char * pgname,const char * pname,nvlist_t ** val,int * err)4431414Scindi topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
4441414Scindi     nvlist_t **val, int *err)
4451414Scindi {
4463062Scindi 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI,
4473062Scindi 	    NULL, err));
4483062Scindi }
4491414Scindi 
4503062Scindi int
topo_prop_get_int32_array(tnode_t * node,const char * pgname,const char * pname,int32_t ** val,uint_t * nelem,int * err)4513062Scindi topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname,
4523062Scindi     int32_t **val, uint_t *nelem, int *err)
4533062Scindi {
4543062Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4553062Scindi 	    TOPO_TYPE_INT32_ARRAY, nelem, err));
4563062Scindi }
4571414Scindi 
4583062Scindi int
topo_prop_get_uint32_array(tnode_t * node,const char * pgname,const char * pname,uint32_t ** val,uint_t * nelem,int * err)4593062Scindi topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname,
4603062Scindi     uint32_t **val, uint_t *nelem, int *err)
4613062Scindi {
4623062Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4633062Scindi 	    TOPO_TYPE_UINT32_ARRAY, nelem, err));
4641414Scindi }
4651414Scindi 
4663062Scindi int
topo_prop_get_int64_array(tnode_t * node,const char * pgname,const char * pname,int64_t ** val,uint_t * nelem,int * err)4673062Scindi topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname,
4683062Scindi     int64_t **val, uint_t *nelem, int *err)
4691414Scindi {
4703062Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4713062Scindi 	    TOPO_TYPE_INT64_ARRAY, nelem, err));
4721414Scindi }
4731414Scindi 
4743062Scindi int
topo_prop_get_uint64_array(tnode_t * node,const char * pgname,const char * pname,uint64_t ** val,uint_t * nelem,int * err)4753062Scindi topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname,
4763062Scindi     uint64_t **val, uint_t *nelem, int *err)
4771414Scindi {
4783062Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4793062Scindi 	    TOPO_TYPE_UINT64_ARRAY, nelem, err));
4803062Scindi }
4813062Scindi 
4823062Scindi int
topo_prop_get_string_array(tnode_t * node,const char * pgname,const char * pname,char *** val,uint_t * nelem,int * err)4833062Scindi topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname,
4843062Scindi     char ***val, uint_t *nelem, int *err)
4853062Scindi {
4863062Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4873062Scindi 	    TOPO_TYPE_STRING_ARRAY, nelem, err));
4883062Scindi }
4893062Scindi 
4903062Scindi int
topo_prop_get_fmri_array(tnode_t * node,const char * pgname,const char * pname,nvlist_t *** val,uint_t * nelem,int * err)4913062Scindi topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname,
4923062Scindi     nvlist_t ***val, uint_t *nelem, int *err)
4933062Scindi {
4943062Scindi 	return (prop_getval(node, pgname, pname, (void *)val,
4953062Scindi 	    TOPO_TYPE_FMRI_ARRAY, nelem, err));
4961414Scindi }
4971414Scindi 
4984087Scindi static topo_propval_t *
set_seterror(tnode_t * node,topo_proplist_t * pvl,int * errp,int err)4993062Scindi set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
5001414Scindi {
5013062Scindi 	topo_hdl_t *thp = node->tn_hdl;
5023062Scindi 	topo_propval_t *pv;
5033062Scindi 
5043062Scindi 	if (pvl != NULL) {
5053062Scindi 		pv = pvl->tp_pval;
5064087Scindi 		topo_propval_destroy(pv);
5073062Scindi 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
5083062Scindi 	}
5093062Scindi 
5101414Scindi 	topo_node_unlock(node);
5111414Scindi 	*errp = err;
5121414Scindi 
5134087Scindi 	return (NULL);
5141414Scindi }
5151414Scindi 
5164087Scindi static topo_propval_t *
prop_create(tnode_t * node,const char * pgname,const char * pname,topo_type_t type,int flag,int * err)5174087Scindi prop_create(tnode_t *node, const char *pgname, const char *pname,
5184087Scindi     topo_type_t type, int flag, int *err)
5191414Scindi {
5201414Scindi 	topo_hdl_t *thp = node->tn_hdl;
5211414Scindi 	topo_pgroup_t *pg;
5221414Scindi 	topo_propval_t *pv;
5231414Scindi 	topo_proplist_t *pvl;
5241414Scindi 
5253062Scindi 	/*
5263062Scindi 	 * Replace existing prop value with new one
5273062Scindi 	 */
5284328Scindi 	if ((pg = pgroup_get(node, pgname)) == NULL) {
5294328Scindi 		topo_node_unlock(node);
5304328Scindi 		*err = ETOPO_PROP_NOENT;
5314087Scindi 		return (NULL);
5324328Scindi 	}
5334087Scindi 
5341414Scindi 	if ((pv = propval_get(pg, pname)) != NULL) {
5351414Scindi 		if (pv->tp_type != type)
5363062Scindi 			return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
537*8526SRobert.Johnston@Sun.COM 		else if (! (pv->tp_flag & TOPO_PROP_MUTABLE))
5383062Scindi 			return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
5394087Scindi 
5403062Scindi 		nvlist_free(pv->tp_val);
5413062Scindi 		pv->tp_val = NULL;
5421414Scindi 	} else {
5431414Scindi 		if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
5441414Scindi 		    == NULL)
5453062Scindi 			return (set_seterror(node, NULL, err, ETOPO_NOMEM));
5461414Scindi 
5471414Scindi 		if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
5483062Scindi 		    == NULL)
5493062Scindi 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
5504328Scindi 
5514328Scindi 		pv->tp_hdl = thp;
5523062Scindi 		pvl->tp_pval = pv;
5533062Scindi 
5541414Scindi 		if ((pv->tp_name = topo_hdl_strdup(thp, pname))
5553062Scindi 		    == NULL)
5563062Scindi 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
5571414Scindi 		pv->tp_flag = flag;
5581414Scindi 		pv->tp_type = type;
5591414Scindi 		topo_prop_hold(pv);
5604087Scindi 		topo_list_append(&pg->tpg_pvals, pvl);
5611414Scindi 	}
5621414Scindi 
5634087Scindi 	return (pv);
5644087Scindi }
5653062Scindi 
5664087Scindi 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)5674087Scindi topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
5684087Scindi     topo_type_t type, int flag, void *val, int nelems, int *err)
5694087Scindi {
5704087Scindi 	int ret;
5714087Scindi 	topo_hdl_t *thp = node->tn_hdl;
5724087Scindi 	nvlist_t *nvl;
5734087Scindi 
5744087Scindi 	if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) {
5754087Scindi 		*err = ETOPO_PROP_NVL;
5764087Scindi 		return (-1);
5774087Scindi 	}
5784087Scindi 
5794087Scindi 	ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname);
5804087Scindi 	ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
5811414Scindi 	switch (type) {
5821414Scindi 		case TOPO_TYPE_INT32:
5834087Scindi 			ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
5843062Scindi 			    *(int32_t *)val);
5851414Scindi 			break;
5861414Scindi 		case TOPO_TYPE_UINT32:
5874087Scindi 			ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
5883062Scindi 			    *(uint32_t *)val);
5891414Scindi 			break;
5901414Scindi 		case TOPO_TYPE_INT64:
5914087Scindi 			ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
5923062Scindi 			    *(int64_t *)val);
5931414Scindi 			break;
5941414Scindi 		case TOPO_TYPE_UINT64:
5954087Scindi 			ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
5963062Scindi 			    *(uint64_t *)val);
5971414Scindi 			break;
5987243Srobj 		case TOPO_TYPE_DOUBLE:
5997243Srobj 			ret |= nvlist_add_double(nvl, TOPO_PROP_VAL_VAL,
6007243Srobj 			    *(double *)val);
6017243Srobj 			break;
6021414Scindi 		case TOPO_TYPE_STRING:
6034087Scindi 			ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
6043062Scindi 			    (char *)val);
6051414Scindi 			break;
6061414Scindi 		case TOPO_TYPE_FMRI:
6074087Scindi 			ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
6083062Scindi 			    (nvlist_t *)val);
6093062Scindi 			break;
6103062Scindi 		case TOPO_TYPE_INT32_ARRAY:
6114087Scindi 			ret |= nvlist_add_int32_array(nvl,
6123062Scindi 			    TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
6133062Scindi 			break;
6143062Scindi 		case TOPO_TYPE_UINT32_ARRAY:
6154087Scindi 			ret |= nvlist_add_uint32_array(nvl,
6163062Scindi 			    TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
6173062Scindi 			break;
6183062Scindi 		case TOPO_TYPE_INT64_ARRAY:
6194087Scindi 			ret |= nvlist_add_int64_array(nvl,
6203062Scindi 			    TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
6213062Scindi 			break;
6223062Scindi 		case TOPO_TYPE_UINT64_ARRAY:
6234087Scindi 			ret |= nvlist_add_uint64_array(nvl,
6243062Scindi 			    TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
6253062Scindi 			break;
6263062Scindi 		case TOPO_TYPE_STRING_ARRAY:
6274087Scindi 			ret |= nvlist_add_string_array(nvl,
6283062Scindi 			    TOPO_PROP_VAL_VAL, (char **)val, nelems);
6293062Scindi 			break;
6303062Scindi 		case TOPO_TYPE_FMRI_ARRAY:
6314087Scindi 			ret |= nvlist_add_nvlist_array(nvl,
6323062Scindi 			    TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
6331414Scindi 			break;
6341414Scindi 		default:
6354087Scindi 			*err = ETOPO_PROP_TYPE;
6364087Scindi 			return (-1);
6371414Scindi 	}
6381414Scindi 
6393062Scindi 	if (ret != 0) {
6404087Scindi 		nvlist_free(nvl);
6414087Scindi 		if (ret == ENOMEM) {
6424087Scindi 			*err = ETOPO_PROP_NOMEM;
6434087Scindi 			return (-1);
6444087Scindi 		} else {
6454087Scindi 			*err = ETOPO_PROP_NVL;
6464087Scindi 			return (-1);
6474087Scindi 		}
6483062Scindi 	}
6493062Scindi 
6507243Srobj 	if (topo_prop_setprop(node, pgname, nvl, flag, nvl, err) != 0) {
6514087Scindi 		nvlist_free(nvl);
6527243Srobj 		return (-1); /* err set */
6534087Scindi 	}
6547243Srobj 	nvlist_free(nvl);
6554087Scindi 	return (ret);
6561414Scindi }
6571414Scindi 
6581414Scindi int
topo_prop_set_int32(tnode_t * node,const char * pgname,const char * pname,int flag,int32_t val,int * err)6591414Scindi topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
6601414Scindi     int flag, int32_t val, int *err)
6611414Scindi {
6621414Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
6633062Scindi 	    &val, 1, err));
6641414Scindi }
6651414Scindi 
6661414Scindi int
topo_prop_set_uint32(tnode_t * node,const char * pgname,const char * pname,int flag,uint32_t val,int * err)6671414Scindi topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
6681414Scindi     int flag, uint32_t val, int *err)
6691414Scindi {
6701414Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
6713062Scindi 	    &val, 1, err));
6721414Scindi }
6731414Scindi 
6741414Scindi int
topo_prop_set_int64(tnode_t * node,const char * pgname,const char * pname,int flag,int64_t val,int * err)6751414Scindi topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
6761414Scindi     int flag, int64_t val, int *err)
6771414Scindi {
6781414Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
6793062Scindi 	    &val, 1, err));
6801414Scindi }
6811414Scindi 
6821414Scindi int
topo_prop_set_uint64(tnode_t * node,const char * pgname,const char * pname,int flag,uint64_t val,int * err)6831414Scindi topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
6841414Scindi     int flag, uint64_t val, int *err)
6851414Scindi {
6861414Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
6873062Scindi 	    &val, 1, err));
6881414Scindi }
6891414Scindi 
6901414Scindi int
topo_prop_set_double(tnode_t * node,const char * pgname,const char * pname,int flag,double val,int * err)6917243Srobj topo_prop_set_double(tnode_t *node, const char *pgname, const char *pname,
6927243Srobj     int flag, double val, int *err)
6937243Srobj {
6947243Srobj 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_DOUBLE, flag,
6957243Srobj 	    &val, 1, err));
6967243Srobj }
6977243Srobj 
6987243Srobj int
topo_prop_set_string(tnode_t * node,const char * pgname,const char * pname,int flag,const char * val,int * err)6991414Scindi topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
7001414Scindi     int flag, const char *val, int *err)
7011414Scindi {
7021414Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
7033062Scindi 	    (void *)val, 1, err));
7041414Scindi }
7051414Scindi 
7061414Scindi int
topo_prop_set_fmri(tnode_t * node,const char * pgname,const char * pname,int flag,const nvlist_t * fmri,int * err)7071414Scindi topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
7081414Scindi     int flag, const nvlist_t *fmri, int *err)
7091414Scindi {
7101414Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
7113062Scindi 	    (void *)fmri, 1, err));
7123062Scindi }
7133062Scindi 
7143062Scindi 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)7153062Scindi topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname,
7163062Scindi     int flag, int32_t *val, uint_t nelems, int *err)
7173062Scindi {
7183062Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag,
7193062Scindi 	    val, nelems, err));
7203062Scindi }
7213062Scindi 
7223062Scindi 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)7233062Scindi topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname,
7243062Scindi     int flag, uint32_t *val, uint_t nelems, int *err)
7253062Scindi {
7263062Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag,
7273062Scindi 	    val, nelems, err));
7283062Scindi }
7293062Scindi 
7303062Scindi 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)7313062Scindi topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname,
7323062Scindi     int flag, int64_t *val, uint_t nelems, int *err)
7333062Scindi {
7343062Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag,
7353062Scindi 	    val, nelems, err));
7363062Scindi }
7373062Scindi 
7383062Scindi 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)7393062Scindi topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname,
7403062Scindi     int flag, uint64_t *val, uint_t nelems, int *err)
7413062Scindi {
7423062Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag,
7433062Scindi 	    val, nelems, err));
7443062Scindi }
7453062Scindi 
7463062Scindi 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)7473062Scindi topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname,
7483062Scindi     int flag, const char **val, uint_t nelems, int *err)
7493062Scindi {
7503062Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag,
7513062Scindi 	    (void *)val, nelems, err));
7523062Scindi }
7533062Scindi 
7543062Scindi 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)7553062Scindi topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname,
7563062Scindi     int flag, const nvlist_t **fmri, uint_t nelems, int *err)
7573062Scindi {
7583062Scindi 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag,
7593062Scindi 	    (void *)fmri, nelems, err));
7601414Scindi }
7611414Scindi 
7624087Scindi /*
7634087Scindi  * topo_prop_setprop() is a private project function for fmtopo
7644087Scindi  */
7654087Scindi int
topo_prop_setprop(tnode_t * node,const char * pgname,nvlist_t * prop,int flag,nvlist_t * pargs,int * err)7664087Scindi topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop,
7674087Scindi     int flag, nvlist_t *pargs, int *err)
7684087Scindi {
7694087Scindi 	int ret;
7704087Scindi 	topo_hdl_t *thp = node->tn_hdl;
7714087Scindi 	topo_propval_t *pv;
7724087Scindi 	nvlist_t *nvl, *args;
7734087Scindi 	char *name;
7744087Scindi 	topo_type_t type;
7754087Scindi 
7764087Scindi 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) {
7774087Scindi 		*err = ETOPO_PROP_NAME;
7784087Scindi 		return (-1);
7794087Scindi 	}
7804087Scindi 	if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type)
7814087Scindi 	    != 0) {
7824087Scindi 		*err = ETOPO_PROP_TYPE;
7834087Scindi 		return (-1);
7844087Scindi 	}
7854087Scindi 
7864087Scindi 	topo_node_lock(node);
7874087Scindi 	if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL)
7884087Scindi 		return (-1); /* unlocked and err set */
7894087Scindi 
7904087Scindi 	/*
7914087Scindi 	 * Set by method or set to new prop value.  If we fail, leave
7924087Scindi 	 * property in list with old value.
7934087Scindi 	 */
7944087Scindi 	if (pv->tp_method != NULL) {
7954087Scindi 		topo_propmethod_t *pm = pv->tp_method;
7964087Scindi 
7974087Scindi 		if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) {
7984087Scindi 			topo_node_unlock(node);
7994087Scindi 			*err = ETOPO_PROP_NOMEM;
8004087Scindi 			return (-1);
8014087Scindi 		}
8024087Scindi 		ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args);
8034087Scindi 		if (pargs != NULL)
8044087Scindi 			ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs);
8054087Scindi 
8064087Scindi 		if (ret != 0) {
8074087Scindi 			topo_node_unlock(node);
8084087Scindi 			nvlist_free(args);
8094087Scindi 			*err = ETOPO_PROP_NVL;
8104087Scindi 			return (-1);
8114087Scindi 		}
8124087Scindi 
8135590Srobj 		/*
8145590Srobj 		 *
8155590Srobj 		 * Grab a reference to the property and then unlock the node.
8165590Srobj 		 * This will allow property methods to safely re-enter the
8175590Srobj 		 * prop_get codepath, making it possible for property methods
8185590Srobj 		 * to access other property values on the same node w\o causing
8195590Srobj 		 * a deadlock.
8205590Srobj 		 *
8215590Srobj 		 * We don't technically need this now, since this interface is
8225590Srobj 		 * currently only used by fmtopo (which is single-threaded), but
8235590Srobj 		 * we may make this interface available to other parts of
8245590Srobj 		 * libtopo in the future, so best to make it MT-safe now.
8255590Srobj 		 */
8265590Srobj 		topo_prop_hold(pv);
8275590Srobj 		topo_node_unlock(node);
8284087Scindi 		ret = topo_method_call(node, pm->tpm_name, pm->tpm_version,
8294087Scindi 		    args, &nvl, err);
8305590Srobj 		topo_node_lock(node);
8315590Srobj 		topo_prop_rele(pv);
8325590Srobj 
8334087Scindi 		nvlist_free(args);
8344087Scindi 	} else {
8354087Scindi 		if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0)
8364087Scindi 			*err = ETOPO_PROP_NOMEM;
8374087Scindi 	}
8384087Scindi 
8394087Scindi 	if (ret != 0) {
8404087Scindi 		topo_node_unlock(node);
8414087Scindi 		return (-1);
8424087Scindi 	}
8434087Scindi 
8444087Scindi 	pv->tp_val = nvl;
8454087Scindi 	topo_node_unlock(node);
8464087Scindi 	return (0);
8474087Scindi }
8484087Scindi 
8494087Scindi static int
register_methoderror(tnode_t * node,topo_propmethod_t * pm,int * errp,int l,int err)8504087Scindi register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
8514087Scindi     int err)
8524087Scindi {
8534087Scindi 	topo_hdl_t *thp = node->tn_hdl;
8544087Scindi 
8554087Scindi 	if (pm != NULL) {
8564087Scindi 		if (pm->tpm_name != NULL)
8574087Scindi 			topo_hdl_strfree(thp, pm->tpm_name);
8584087Scindi 		if (pm->tpm_args != NULL)
8594087Scindi 			nvlist_free(pm->tpm_args);
8604087Scindi 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
8614087Scindi 	}
8624087Scindi 
8634087Scindi 	*errp = err;
8644087Scindi 
8654087Scindi 	if (l != 0)
8664087Scindi 		topo_node_unlock(node);
8674087Scindi 
8684087Scindi 	return (-1);
8694087Scindi }
8704087Scindi 
8714087Scindi 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)8724087Scindi prop_method_register(tnode_t *node, const char *pgname, const char *pname,
8734087Scindi     topo_type_t ptype, const char *mname, topo_version_t version,
8744087Scindi     const nvlist_t *args, int *err)
8754087Scindi {
8764087Scindi 	topo_hdl_t *thp = node->tn_hdl;
8774087Scindi 	topo_propmethod_t *pm = NULL;
8784087Scindi 	topo_propval_t *pv = NULL;
8794087Scindi 
8804087Scindi 	if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL)
8814087Scindi 		return (register_methoderror(node, pm, err, 1,
8824087Scindi 		    ETOPO_PROP_NOMEM));
8834087Scindi 
8844087Scindi 	if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL)
8854087Scindi 		return (register_methoderror(node, pm, err, 1,
8864087Scindi 		    ETOPO_PROP_NOMEM));
8874087Scindi 
8884087Scindi 	pm->tpm_version = version;
8894087Scindi 
8904087Scindi 	if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0)
8914087Scindi 		return (register_methoderror(node, pm, err, 1,
8924087Scindi 		    ETOPO_PROP_NOMEM));
8934087Scindi 
8946070Srobj 	/*
8956070Srobj 	 * It's possible the property may already exist.  However we still want
8966070Srobj 	 * to allow the method to be registered.  This is to handle the case
897*8526SRobert.Johnston@Sun.COM 	 * where we specify a prop method in an xml map to override the value
8986070Srobj 	 * that was set by the enumerator.
8997243Srobj 	 *
900*8526SRobert.Johnston@Sun.COM 	 * By default, propmethod-backed properties are not MUTABLE.  This is
901*8526SRobert.Johnston@Sun.COM 	 * done to simplify the programming model for modules that implement
902*8526SRobert.Johnston@Sun.COM 	 * property methods as most propmethods tend to only support get
903*8526SRobert.Johnston@Sun.COM 	 * operations.  Enumerator modules can override this by calling
904*8526SRobert.Johnston@Sun.COM 	 * topo_prop_setmutable().  Propmethods that are registered via XML can
905*8526SRobert.Johnston@Sun.COM 	 * be set as mutable via the optional "mutable" attribute, which will
906*8526SRobert.Johnston@Sun.COM 	 * result in the xml parser calling topo_prop_setflags() after
907*8526SRobert.Johnston@Sun.COM 	 * registering the propmethod.
9086070Srobj 	 */
9096070Srobj 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL)
9106070Srobj 		if ((pv = prop_create(node, pgname, pname, ptype,
9117243Srobj 		    TOPO_PROP_IMMUTABLE, err)) == NULL) {
9126070Srobj 			/* node unlocked */
9136070Srobj 			return (register_methoderror(node, pm, err, 0, *err));
9146070Srobj 		}
9154087Scindi 
9165068Srobj 	if (pv->tp_method != NULL)
9174087Scindi 		return (register_methoderror(node, pm, err, 1,
9184087Scindi 		    ETOPO_METHOD_DEFD));
9194087Scindi 
9206070Srobj 	if (pv->tp_val != NULL) {
9216070Srobj 		nvlist_free(pv->tp_val);
9226070Srobj 		pv->tp_val = NULL;
9236070Srobj 	}
9244087Scindi 	pv->tp_method = pm;
9254087Scindi 
9264087Scindi 	topo_node_unlock(node);
9274087Scindi 
9284087Scindi 	return (0);
9294087Scindi }
9304087Scindi 
9314087Scindi 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)9324087Scindi topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname,
9334087Scindi     topo_type_t ptype, const char *mname, const nvlist_t *args, int *err)
9344087Scindi {
9354087Scindi 	topo_imethod_t *mp;
9364087Scindi 
9374087Scindi 	topo_node_lock(node);
9384087Scindi 
9394087Scindi 	if ((mp = topo_method_lookup(node, mname)) == NULL)
9404087Scindi 		return (register_methoderror(node, NULL, err, 1,
9415068Srobj 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
9425068Srobj 
9435068Srobj 	topo_node_lock(node);
9444087Scindi 
9454087Scindi 	return (prop_method_register(node, pgname, pname, ptype, mname,
9464087Scindi 	    mp->tim_version, args, err)); /* err set and node unlocked */
9474087Scindi }
9484087Scindi 
9494087Scindi 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)9504087Scindi topo_prop_method_version_register(tnode_t *node, const char *pgname,
9514087Scindi     const char *pname, topo_type_t ptype, const char *mname,
9524087Scindi     topo_version_t version, const nvlist_t *args, int *err)
9534087Scindi {
9544087Scindi 	topo_imethod_t *mp;
9554087Scindi 
9564087Scindi 	topo_node_lock(node);
9574087Scindi 
9584087Scindi 	if ((mp = topo_method_lookup(node, mname)) == NULL)
9594087Scindi 		return (register_methoderror(node, NULL, err, 1,
9605068Srobj 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
9615068Srobj 
9625068Srobj 	topo_node_lock(node);
9634087Scindi 
9644087Scindi 	if (version < mp->tim_version)
9654087Scindi 		return (register_methoderror(node, NULL, err, 1,
9664087Scindi 		    ETOPO_METHOD_VEROLD));
9674087Scindi 	if (version > mp->tim_version)
9684087Scindi 		return (register_methoderror(node, NULL, err, 1,
9694087Scindi 		    ETOPO_METHOD_VERNEW));
9704087Scindi 
9714087Scindi 	return (prop_method_register(node, pgname, pname, ptype, mname,
9724087Scindi 	    version, args, err)); /* err set and node unlocked */
9734087Scindi }
9744087Scindi 
9754087Scindi void
topo_prop_method_unregister(tnode_t * node,const char * pgname,const char * pname)9764087Scindi topo_prop_method_unregister(tnode_t *node, const char *pgname,
9774087Scindi     const char *pname)
9784087Scindi {
9794087Scindi 	topo_propval_t *pv;
9804087Scindi 	topo_pgroup_t *pg;
9814087Scindi 	topo_proplist_t *pvl;
9824087Scindi 	topo_hdl_t *thp = node->tn_hdl;
9834087Scindi 
9844087Scindi 	topo_node_lock(node);
9854087Scindi 
9864087Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
9874087Scindi 	    pg = topo_list_next(pg)) {
9884087Scindi 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
9894087Scindi 			break;
9904087Scindi 		}
9914087Scindi 	}
9924087Scindi 
9934087Scindi 	if (pg == NULL) {
9944087Scindi 		topo_node_unlock(node);
9954087Scindi 		return;
9964087Scindi 	}
9974087Scindi 
9984087Scindi 	for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
9994087Scindi 	    pvl = topo_list_next(pvl)) {
10004087Scindi 		pv = pvl->tp_pval;
10014087Scindi 		if (strcmp(pv->tp_name, pname) == 0) {
10024087Scindi 			topo_list_delete(&pg->tpg_pvals, pvl);
10034087Scindi 			assert(pv->tp_refs == 1);
10044087Scindi 			topo_prop_rele(pv);
10054087Scindi 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
10064087Scindi 			break;
10074087Scindi 		}
10084087Scindi 	}
10094087Scindi 
10104087Scindi 	topo_node_unlock(node);
10114087Scindi }
10124087Scindi 
10137243Srobj int
topo_prop_setmutable(tnode_t * node,const char * pgname,const char * pname,int * err)10147243Srobj topo_prop_setmutable(tnode_t *node, const char *pgname, const char *pname,
10157243Srobj     int *err)
10167243Srobj {
10177243Srobj 	topo_propval_t *pv = NULL;
10187243Srobj 
10197243Srobj 	topo_node_lock(node);
10207243Srobj 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
10217243Srobj 		topo_node_unlock(node);
10227243Srobj 		*err = ETOPO_PROP_NOENT;
10237243Srobj 		return (-1);
10247243Srobj 	}
10257243Srobj 
10267243Srobj 	/*
10277243Srobj 	 * If the property is being inherited then we don't want to allow a
10287243Srobj 	 * change from IMMUTABLE to MUTABLE.
10297243Srobj 	 */
10307243Srobj 	if (pv->tp_refs > 1) {
10317243Srobj 		topo_node_unlock(node);
10327243Srobj 		*err = ETOPO_PROP_DEFD;
10337243Srobj 		return (-1);
10347243Srobj 	}
1035*8526SRobert.Johnston@Sun.COM 	pv->tp_flag |= TOPO_PROP_MUTABLE;
1036*8526SRobert.Johnston@Sun.COM 
1037*8526SRobert.Johnston@Sun.COM 	topo_node_unlock(node);
1038*8526SRobert.Johnston@Sun.COM 
1039*8526SRobert.Johnston@Sun.COM 	return (0);
1040*8526SRobert.Johnston@Sun.COM }
1041*8526SRobert.Johnston@Sun.COM int
topo_prop_setnonvolatile(tnode_t * node,const char * pgname,const char * pname,int * err)1042*8526SRobert.Johnston@Sun.COM topo_prop_setnonvolatile(tnode_t *node, const char *pgname, const char *pname,
1043*8526SRobert.Johnston@Sun.COM     int *err)
1044*8526SRobert.Johnston@Sun.COM {
1045*8526SRobert.Johnston@Sun.COM 	topo_propval_t *pv = NULL;
1046*8526SRobert.Johnston@Sun.COM 
1047*8526SRobert.Johnston@Sun.COM 	topo_node_lock(node);
1048*8526SRobert.Johnston@Sun.COM 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1049*8526SRobert.Johnston@Sun.COM 		topo_node_unlock(node);
1050*8526SRobert.Johnston@Sun.COM 		*err = ETOPO_PROP_NOENT;
1051*8526SRobert.Johnston@Sun.COM 		return (-1);
1052*8526SRobert.Johnston@Sun.COM 	}
1053*8526SRobert.Johnston@Sun.COM 
1054*8526SRobert.Johnston@Sun.COM 	pv->tp_flag |= TOPO_PROP_NONVOLATILE;
10557243Srobj 
10567243Srobj 	topo_node_unlock(node);
10577243Srobj 
10587243Srobj 	return (0);
10597243Srobj }
10607243Srobj 
10611414Scindi static int
inherit_seterror(tnode_t * node,int * errp,int err)10621414Scindi inherit_seterror(tnode_t *node, int *errp, int err)
10631414Scindi {
10641414Scindi 	topo_node_unlock(node);
10651414Scindi 	topo_node_unlock(node->tn_parent);
10661414Scindi 
10671414Scindi 	*errp = err;
10681414Scindi 
10691414Scindi 	return (-1);
10701414Scindi }
10711414Scindi 
10721414Scindi int
topo_prop_inherit(tnode_t * node,const char * pgname,const char * name,int * err)10731414Scindi topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
10741414Scindi {
10751414Scindi 	topo_hdl_t *thp = node->tn_hdl;
10761414Scindi 	tnode_t *pnode = node->tn_parent;
10771414Scindi 	topo_pgroup_t *pg;
10781414Scindi 	topo_propval_t *pv;
10791414Scindi 	topo_proplist_t *pvl;
10801414Scindi 
10811414Scindi 	topo_node_lock(pnode);
10821414Scindi 	topo_node_lock(node);
10836070Srobj 
10841414Scindi 	/*
10856070Srobj 	 * Check if the requested property group and prop val are already set
10866070Srobj 	 * on the node.
10876070Srobj 	 */
10886070Srobj 	if (propval_get(pgroup_get(node, pgname), name) != NULL)
10896070Srobj 		return (inherit_seterror(node, err, ETOPO_PROP_DEFD));
10906070Srobj 
10916070Srobj 	/*
10926070Srobj 	 * Check if the requested property group and prop val exists on the
10936070Srobj 	 * parent node
10941414Scindi 	 */
10954087Scindi 	if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
10961414Scindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
10971414Scindi 
10981414Scindi 	/*
10991414Scindi 	 * Can this propval be inherited?
11001414Scindi 	 */
1101*8526SRobert.Johnston@Sun.COM 	if (pv->tp_flag & TOPO_PROP_MUTABLE)
11021414Scindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
11031414Scindi 
11041414Scindi 	/*
11051414Scindi 	 * Property group should already exist: bump the ref count for this
11061414Scindi 	 * propval and add it to the node's property group
11071414Scindi 	 */
11081414Scindi 	if ((pg = pgroup_get(node, pgname)) == NULL)
11091414Scindi 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
11101414Scindi 
11111414Scindi 	if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
11121414Scindi 	    == NULL)
11131414Scindi 		return (inherit_seterror(node, err, ETOPO_NOMEM));
11141414Scindi 
11151414Scindi 	topo_prop_hold(pv);
11161414Scindi 	pvl->tp_pval = pv;
11171414Scindi 	topo_list_append(&pg->tpg_pvals, pvl);
11181414Scindi 
11191414Scindi 	topo_node_unlock(node);
11201414Scindi 	topo_node_unlock(pnode);
11211414Scindi 
11221414Scindi 	return (0);
11231414Scindi }
11241414Scindi 
11253062Scindi topo_pgroup_info_t *
topo_pgroup_info(tnode_t * node,const char * pgname,int * err)11263062Scindi topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
11271414Scindi {
11283062Scindi 	topo_hdl_t *thp = node->tn_hdl;
11291414Scindi 	topo_pgroup_t *pg;
11303062Scindi 	topo_ipgroup_info_t *pip;
11313062Scindi 	topo_pgroup_info_t *info;
11321414Scindi 
11333062Scindi 	topo_node_lock(node);
11341414Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
11351414Scindi 	    pg = topo_list_next(pg)) {
11363062Scindi 		if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
11373062Scindi 			if ((info = topo_hdl_alloc(thp,
11383062Scindi 			    sizeof (topo_pgroup_info_t))) == NULL)
11393062Scindi 				return (NULL);
11403062Scindi 
11413062Scindi 			pip = pg->tpg_info;
11423062Scindi 			if ((info->tpi_name =
11434328Scindi 			    topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
11443062Scindi 				*err = ETOPO_PROP_NOMEM;
11453062Scindi 				topo_hdl_free(thp, info,
11463062Scindi 				    sizeof (topo_pgroup_info_t));
11473062Scindi 				topo_node_unlock(node);
11483062Scindi 				return (NULL);
11493062Scindi 			}
11503062Scindi 			info->tpi_namestab = pip->tpi_namestab;
11513062Scindi 			info->tpi_datastab = pip->tpi_datastab;
11523062Scindi 			info->tpi_version = pip->tpi_version;
11533062Scindi 			topo_node_unlock(node);
11543062Scindi 			return (info);
11551414Scindi 		}
11561414Scindi 	}
11571414Scindi 
11583062Scindi 	*err = ETOPO_PROP_NOENT;
11593062Scindi 	topo_node_unlock(node);
11603062Scindi 	return (NULL);
11613062Scindi }
11623062Scindi 
11633062Scindi static int
pgroup_seterr(tnode_t * node,topo_pgroup_t * pg,topo_ipgroup_info_t * pip,int * err)11643062Scindi pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
11653062Scindi     int *err)
11663062Scindi {
11673062Scindi 	topo_hdl_t *thp = node->tn_hdl;
11683062Scindi 
11693062Scindi 	if (pip != NULL) {
11703062Scindi 		if (pip->tpi_name != NULL)
11713062Scindi 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
11723062Scindi 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
11733062Scindi 	}
11743062Scindi 
11753062Scindi 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
11763062Scindi 	*err = ETOPO_NOMEM;
11773062Scindi 
11783062Scindi 	topo_node_unlock(node);
11793062Scindi 
11801414Scindi 	return (-1);
11811414Scindi }
11821414Scindi 
11831414Scindi int
topo_pgroup_create(tnode_t * node,const topo_pgroup_info_t * pinfo,int * err)11843062Scindi topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err)
11851414Scindi {
11861414Scindi 	topo_pgroup_t *pg;
11873062Scindi 	topo_ipgroup_info_t *pip;
11883062Scindi 	topo_hdl_t *thp = node->tn_hdl;
11891414Scindi 
11901414Scindi 	*err = 0;
11911414Scindi 
11923062Scindi 	topo_node_lock(node);
11931414Scindi 	/*
11941414Scindi 	 * Check for an existing pgroup
11951414Scindi 	 */
11961414Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
11971414Scindi 	    pg = topo_list_next(pg)) {
11983062Scindi 		if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) {
11991414Scindi 			*err = ETOPO_PROP_DEFD;
12003062Scindi 			topo_node_unlock(node);
12011414Scindi 			return (-1);
12021414Scindi 		}
12031414Scindi 	}
12041414Scindi 
12053062Scindi 	if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) {
12061414Scindi 		*err = ETOPO_NOMEM;
12073062Scindi 		topo_node_unlock(node);
12081414Scindi 		return (-1);
12091414Scindi 	}
12101414Scindi 
12113062Scindi 	if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t)))
12123062Scindi 	    == NULL)
12133062Scindi 		return (pgroup_seterr(node, pg, pip, err));
12141414Scindi 
12153062Scindi 	if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name))
12163062Scindi 	    == NULL)
12173062Scindi 		return (pgroup_seterr(node, pg, pip, err));
12183062Scindi 
12193062Scindi 	pip->tpi_namestab = pinfo->tpi_namestab;
12203062Scindi 	pip->tpi_datastab = pinfo->tpi_datastab;
12213062Scindi 	pip->tpi_version = pinfo->tpi_version;
12223062Scindi 
12233062Scindi 	pg->tpg_info = pip;
12241414Scindi 
12251414Scindi 	topo_list_append(&node->tn_pgroups, pg);
12263062Scindi 	topo_node_unlock(node);
12271414Scindi 
12281414Scindi 	return (0);
12291414Scindi }
12301414Scindi 
12311414Scindi void
topo_pgroup_destroy(tnode_t * node,const char * pname)12321414Scindi topo_pgroup_destroy(tnode_t *node, const char *pname)
12331414Scindi {
12341414Scindi 	topo_hdl_t *thp = node->tn_hdl;
12351414Scindi 	topo_pgroup_t *pg;
12361414Scindi 	topo_proplist_t *pvl;
12373062Scindi 	topo_ipgroup_info_t *pip;
12381414Scindi 
12391414Scindi 	topo_node_lock(node);
12401414Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
12411414Scindi 	    pg = topo_list_next(pg)) {
12423062Scindi 		if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
12431414Scindi 			break;
12441414Scindi 		}
12451414Scindi 	}
12461414Scindi 
12471414Scindi 	if (pg == NULL) {
12481414Scindi 		topo_node_unlock(node);
12491414Scindi 		return;
12501414Scindi 	}
12511414Scindi 
12521414Scindi 	while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
12531414Scindi 		topo_list_delete(&pg->tpg_pvals, pvl);
12541414Scindi 		topo_prop_rele(pvl->tp_pval);
12551414Scindi 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
12561414Scindi 	}
12571414Scindi 
12581414Scindi 	topo_list_delete(&node->tn_pgroups, pg);
12593062Scindi 	topo_node_unlock(node);
12601414Scindi 
12613062Scindi 	pip = pg->tpg_info;
12623062Scindi 	if (pip != NULL) {
12633062Scindi 		if (pip->tpi_name != NULL)
12643062Scindi 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
12653062Scindi 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
12663062Scindi 	}
12673062Scindi 
12681414Scindi 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
12691414Scindi }
12701414Scindi 
12711414Scindi void
topo_pgroup_destroy_all(tnode_t * node)12721414Scindi topo_pgroup_destroy_all(tnode_t *node)
12731414Scindi {
12741414Scindi 	topo_hdl_t *thp = node->tn_hdl;
12751414Scindi 	topo_pgroup_t *pg;
12761414Scindi 	topo_proplist_t *pvl;
12773062Scindi 	topo_ipgroup_info_t *pip;
12781414Scindi 
12791414Scindi 	topo_node_lock(node);
12801414Scindi 	while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
12811414Scindi 		while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
12821414Scindi 			topo_list_delete(&pg->tpg_pvals, pvl);
12831414Scindi 			topo_prop_rele(pvl->tp_pval);
12841414Scindi 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
12851414Scindi 		}
12861414Scindi 
12871414Scindi 		topo_list_delete(&node->tn_pgroups, pg);
12881414Scindi 
12893062Scindi 		pip = pg->tpg_info;
12903062Scindi 		if (pip != NULL) {
12913062Scindi 			if (pip->tpi_name != NULL)
12923062Scindi 				topo_hdl_strfree(thp, (char *)pip->tpi_name);
12933062Scindi 			topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
12943062Scindi 		}
12953062Scindi 
12961414Scindi 		topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
12971414Scindi 	}
12981414Scindi 	topo_node_unlock(node);
12991414Scindi }
13004087Scindi 
13014087Scindi static void
propmethod_destroy(topo_hdl_t * thp,topo_propval_t * pv)13024087Scindi propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
13034087Scindi {
13044087Scindi 	topo_propmethod_t *pm;
13054087Scindi 
13064087Scindi 	pm = pv->tp_method;
13074087Scindi 	if (pm != NULL) {
13084087Scindi 		if (pm->tpm_name != NULL)
13094087Scindi 			topo_hdl_strfree(thp, pm->tpm_name);
13104087Scindi 		if (pm->tpm_args != NULL)
13114087Scindi 			nvlist_free(pm->tpm_args);
13124087Scindi 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
13134087Scindi 		pv->tp_method = NULL;
13144087Scindi 	}
13154087Scindi }
13164087Scindi 
13171414Scindi static void
topo_propval_destroy(topo_propval_t * pv)13181414Scindi topo_propval_destroy(topo_propval_t *pv)
13191414Scindi {
13204087Scindi 	topo_hdl_t *thp;
13214087Scindi 
13224087Scindi 	if (pv == NULL)
13234087Scindi 		return;
13244087Scindi 
13254087Scindi 	thp = pv->tp_hdl;
13261414Scindi 
13271414Scindi 	if (pv->tp_name != NULL)
13281414Scindi 		topo_hdl_strfree(thp, pv->tp_name);
13291414Scindi 
13303062Scindi 	if (pv->tp_val != NULL)
13313062Scindi 		nvlist_free(pv->tp_val);
13321414Scindi 
13334087Scindi 	propmethod_destroy(thp, pv);
13344087Scindi 
13351414Scindi 	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
13361414Scindi }
13371414Scindi 
13381414Scindi void
topo_prop_hold(topo_propval_t * pv)13391414Scindi topo_prop_hold(topo_propval_t *pv)
13401414Scindi {
13411414Scindi 	pv->tp_refs++;
13421414Scindi }
13431414Scindi 
13441414Scindi void
topo_prop_rele(topo_propval_t * pv)13451414Scindi topo_prop_rele(topo_propval_t *pv)
13461414Scindi {
13471414Scindi 	pv->tp_refs--;
13481414Scindi 
13491414Scindi 	assert(pv->tp_refs >= 0);
13501414Scindi 
13511414Scindi 	if (pv->tp_refs == 0)
13521414Scindi 		topo_propval_destroy(pv);
13531414Scindi }
13544087Scindi 
13554087Scindi /*
13564087Scindi  * topo_prop_getprop() and topo_prop_getprops() are private project functions
13574087Scindi  * for fmtopo
13584087Scindi  */
13594087Scindi int
topo_prop_getprop(tnode_t * node,const char * pgname,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)13604087Scindi topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname,
13614087Scindi     nvlist_t *args, nvlist_t **prop, int *err)
13624087Scindi {
13634087Scindi 	topo_hdl_t *thp = node->tn_hdl;
13644087Scindi 	topo_propval_t *pv;
13654087Scindi 
13664087Scindi 	topo_node_lock(node);
13674087Scindi 	if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) {
13684087Scindi 		(void) get_properror(node, err, *err);
13694087Scindi 		return (-1);
13704087Scindi 	}
13714087Scindi 
13724087Scindi 	if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) {
13734087Scindi 		(void) get_properror(node, err, ETOPO_NOMEM);
13744087Scindi 		return (-1);
13754087Scindi 	}
13764087Scindi 	topo_node_unlock(node);
13774087Scindi 
13784087Scindi 	return (0);
13794087Scindi }
13804087Scindi 
13814087Scindi static int
prop_val_add(tnode_t * node,nvlist_t ** nvl,topo_propval_t * pv,int * err)13824087Scindi prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err)
13834087Scindi {
13844087Scindi 	if (pv->tp_method != NULL)
13854087Scindi 		if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0)
13864087Scindi 			return (-1);
13874087Scindi 
13884087Scindi 	if (pv->tp_val == NULL) {
13894087Scindi 		*err = ETOPO_PROP_NOENT;
13904087Scindi 		return (-1);
13914087Scindi 	}
13924087Scindi 
13934087Scindi 	if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) {
13944087Scindi 		*err = ETOPO_PROP_NOMEM;
13954087Scindi 		return (-1);
13964087Scindi 	}
13974087Scindi 
13984087Scindi 	return (0);
13994087Scindi }
14004087Scindi 
14014087Scindi static int
get_pgrp_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)14024087Scindi get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
14034087Scindi {
14044087Scindi 	topo_node_unlock(node);
14054087Scindi 
14064087Scindi 	if (nvl != NULL)
14074087Scindi 		nvlist_free(nvl);
14084087Scindi 
14094087Scindi 	*errp = err;
14104087Scindi 
14114087Scindi 	return (-1);
14124087Scindi }
14134087Scindi 
14144087Scindi int
topo_prop_getpgrp(tnode_t * node,const char * pgname,nvlist_t ** pgrp,int * err)14154087Scindi topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp,
14164087Scindi     int *err)
14174087Scindi {
14184087Scindi 	int ret;
14194087Scindi 	topo_hdl_t *thp = node->tn_hdl;
14204087Scindi 	nvlist_t *nvl, *pvnvl;
14214087Scindi 	topo_pgroup_t *pg;
14224087Scindi 	topo_propval_t *pv;
14234087Scindi 	topo_proplist_t *pvl;
14244087Scindi 
14254087Scindi 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
14264087Scindi 		*err = ETOPO_NOMEM;
14274087Scindi 		return (-1);
14284087Scindi 	}
14294087Scindi 
14304087Scindi 	topo_node_lock(node);
14314087Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
14324087Scindi 	    pg = topo_list_next(pg)) {
14334087Scindi 
14344087Scindi 		if (strcmp(pgname, pg->tpg_info->tpi_name) != 0)
14354087Scindi 			continue;
14364087Scindi 
14374087Scindi 		if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME,
14384087Scindi 		    pg->tpg_info->tpi_name) != 0 ||
14394087Scindi 		    nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB,
14404087Scindi 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
14414087Scindi 		    nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB,
14424087Scindi 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
14434087Scindi 		    nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION,
14444087Scindi 		    pg->tpg_info->tpi_version) != 0)
14454087Scindi 			return (get_pgrp_seterror(node, nvl, err,
14464087Scindi 			    ETOPO_PROP_NVL));
14474087Scindi 
14484087Scindi 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
14494087Scindi 		    pvl = topo_list_next(pvl)) {
14504087Scindi 
14514087Scindi 			pv = pvl->tp_pval;
14524087Scindi 			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
14534087Scindi 				return (get_pgrp_seterror(node, nvl, err,
14544087Scindi 				    *err));
14554087Scindi 			}
14564087Scindi 			if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL,
14574087Scindi 			    pvnvl)) != 0) {
14584087Scindi 				nvlist_free(pvnvl);
14594087Scindi 				return (get_pgrp_seterror(node, nvl, err, ret));
14604087Scindi 			}
14614087Scindi 
14624087Scindi 			nvlist_free(pvnvl);
14634087Scindi 		}
14644087Scindi 		topo_node_unlock(node);
14654087Scindi 		*pgrp = nvl;
14664087Scindi 		return (0);
14674087Scindi 	}
14684087Scindi 
14694087Scindi 	topo_node_unlock(node);
14704087Scindi 	*err = ETOPO_PROP_NOENT;
14714087Scindi 	return (-1);
14724087Scindi }
14734087Scindi 
14744087Scindi static nvlist_t *
get_all_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)14754087Scindi get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
14764087Scindi {
14774087Scindi 	topo_node_unlock(node);
14784087Scindi 
14794087Scindi 	if (nvl != NULL)
14804087Scindi 		nvlist_free(nvl);
14814087Scindi 
14824087Scindi 	*errp = err;
14834087Scindi 
14844087Scindi 	return (NULL);
14854087Scindi }
14864087Scindi 
14874087Scindi nvlist_t *
topo_prop_getprops(tnode_t * node,int * err)14884087Scindi topo_prop_getprops(tnode_t *node, int *err)
14894087Scindi {
14904087Scindi 	int ret;
14914087Scindi 	topo_hdl_t *thp = node->tn_hdl;
14924087Scindi 	nvlist_t *nvl, *pgnvl, *pvnvl;
14934087Scindi 	topo_pgroup_t *pg;
14944087Scindi 	topo_propval_t *pv;
14954087Scindi 	topo_proplist_t *pvl;
14964087Scindi 
14974087Scindi 	topo_node_lock(node);
14984087Scindi 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
14994087Scindi 		return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
15004087Scindi 	}
15014087Scindi 
15024087Scindi 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
15034087Scindi 	    pg = topo_list_next(pg)) {
15044087Scindi 		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
15054087Scindi 			return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
15064087Scindi 
15074087Scindi 		if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
15084087Scindi 		    pg->tpg_info->tpi_name) != 0 ||
15094087Scindi 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
15104087Scindi 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
15114087Scindi 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
15124087Scindi 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
15134087Scindi 		    nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
15144087Scindi 		    pg->tpg_info->tpi_version) != 0)
15154087Scindi 			return (get_all_seterror(node, nvl, err,
15164087Scindi 			    ETOPO_PROP_NVL));
15174087Scindi 
15184087Scindi 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
15194087Scindi 		    pvl = topo_list_next(pvl)) {
15204087Scindi 
15214087Scindi 			pv = pvl->tp_pval;
15224087Scindi 			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
15234087Scindi 				nvlist_free(pgnvl);
15244087Scindi 				return (get_all_seterror(node, nvl, err, *err));
15254087Scindi 			}
15264087Scindi 			if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
15274087Scindi 			    pvnvl)) != 0) {
15284087Scindi 				nvlist_free(pgnvl);
15294087Scindi 				nvlist_free(pvnvl);
15304087Scindi 				return (get_all_seterror(node, nvl, err, ret));
15314087Scindi 			}
15324087Scindi 
15334087Scindi 			nvlist_free(pvnvl);
15344087Scindi 		}
15354087Scindi 		if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
15364087Scindi 		    != 0) {
15374087Scindi 			nvlist_free(pgnvl);
15384087Scindi 			return (get_all_seterror(node, nvl, err, ret));
15394087Scindi 		}
15404087Scindi 
15414087Scindi 		nvlist_free(pgnvl);
15424087Scindi 	}
15434087Scindi 
15444087Scindi 	topo_node_unlock(node);
15454087Scindi 
15464087Scindi 	return (nvl);
15474087Scindi }
1548