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