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