xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_prop.c (revision 843e19887f64dde75055cf8842fc4db2171eff45)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <strings.h>
29 #include <assert.h>
30 #include <fm/libtopo.h>
31 #include <topo_prop.h>
32 #include <topo_string.h>
33 #include <topo_alloc.h>
34 #include <topo_error.h>
35 #include <topo_method.h>
36 
37 /*
38  * Topology nodes are permitted to contain property information.
39  * Property information is organized according to property grouping.
40  * Each property group defines a name, a stability level for that name,
41  * a stability level for all underlying property data (name, type, values),
42  * a version for the property group definition and and a list of uniquely
43  * defined properties.  Property group versions are incremented when one of
44  * the following changes occurs:
45  *	- a property name changes
46  *	- a property type changes
47  *	- a property definition is removed from the group
48  * Compatible changes such as new property definitions in the group do
49  * not require version changes.
50  *
51  * Each property defines a unique (within the group) name, a type and
52  * a value.  Properties may be statically defined as int32, uint32, int64,
53  * uint64, fmri, string or arrays of each type.  Properties may also be
54  * dynamically exported via module registered methods.  For example, a module
55  * may register a method to export an ASRU property that is dynamically
56  * contructed when a call to topo_node_fmri() is invoked for a particular
57  * topology node.
58  *
59  * Static properties are persistently attached to topology nodes during
60  * enumeration by an enumeration module or as part of XML statements in a
61  * toplogy map file using the topo_prop_set* family of routines.  Similarly,
62  * property methods are registered during enumeration or as part of
63  * statements in topololgy map files.  Set-up of property methods is performed
64  * by calling topo_prop_method_register().
65  *
66  * All properties, whether statically persisted in a snapshot or dynamically
67  * obtained, may be read via the topo_prop_get* family of interfaces.
68  * Callers wishing to receive all property groups and properties for a given
69  * node may use topo_prop_getall().  This routine returns a nested nvlist
70  * of all groupings and property (name, type, value) sets.  Groupings
71  * are defined by TOPO_PROP_GROUP (name, data stability, name stability and
72  * version) and a nested nvlist of properties (TOPO_PROP_VAL).  Each property
73  * value is defined by its name, type and value.
74  */
75 static void topo_propval_destroy(topo_propval_t *);
76 
77 static topo_pgroup_t *
78 pgroup_get(tnode_t *node, const char *pgname)
79 {
80 	topo_pgroup_t *pg;
81 	/*
82 	 * Check for an existing pgroup
83 	 */
84 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
85 	    pg = topo_list_next(pg)) {
86 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
87 			return (pg);
88 		}
89 	}
90 
91 	return (NULL);
92 }
93 
94 static topo_propval_t *
95 propval_get(topo_pgroup_t *pg, const char *pname)
96 {
97 	topo_proplist_t *pvl;
98 
99 	if (pg == NULL)
100 		return (NULL);
101 
102 	for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
103 	    pvl = topo_list_next(pvl)) {
104 		if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
105 			return (pvl->tp_pval);
106 	}
107 
108 	return (NULL);
109 }
110 
111 static int
112 method_geterror(nvlist_t *nvl, int err, int *errp)
113 {
114 	if (nvl != NULL)
115 		nvlist_free(nvl);
116 
117 	*errp = err;
118 
119 	return (-1);
120 }
121 
122 static int
123 prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm,
124     nvlist_t *pargs, int *err)
125 {
126 	int ret;
127 	nvlist_t *args, *nvl;
128 	char *name;
129 	topo_type_t type;
130 
131 	if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 ||
132 	    nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0)
133 		return (method_geterror(NULL, ETOPO_PROP_NVL, err));
134 
135 	if (pargs != NULL)
136 		if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0)
137 			return (method_geterror(args, ETOPO_PROP_NVL, err));
138 
139 	/* Now, get the latest value */
140 	if (topo_method_call(node, pm->tpm_name, pm->tpm_version,
141 	    args, &nvl, err) < 0)
142 		return (method_geterror(args, *err, err));
143 
144 	nvlist_free(args);
145 
146 	/* Verify the property contents */
147 	ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name);
148 	if (ret != 0 || strcmp(name, pv->tp_name) != 0)
149 		return (method_geterror(nvl, ETOPO_PROP_NAME, err));
150 
151 	ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type);
152 	if (ret != 0 || type != pv->tp_type)
153 		return (method_geterror(nvl, ETOPO_PROP_TYPE, err));
154 
155 	/* Release the last value and re-assign to the new value */
156 	if (pv->tp_val != NULL)
157 		nvlist_free(pv->tp_val);
158 	pv->tp_val = nvl;
159 
160 	return (0);
161 }
162 
163 static topo_propval_t *
164 prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs,
165     int *err)
166 {
167 	topo_propval_t *pv = NULL;
168 
169 	if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
170 		*err = ETOPO_PROP_NOENT;
171 		return (NULL);
172 	}
173 
174 	if (pv->tp_method != NULL) {
175 		if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0)
176 			return (NULL);
177 	}
178 
179 	return (pv);
180 }
181 
182 static int
183 get_properror(tnode_t *node, int *errp, int err)
184 {
185 	topo_node_unlock(node);
186 	*errp = err;
187 	return (-1);
188 }
189 
190 static int
191 prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
192     topo_type_t type, uint_t *nelems, int *err)
193 {
194 	int i, j, ret = 0;
195 	topo_hdl_t *thp = node->tn_hdl;
196 	topo_propval_t *pv;
197 
198 	topo_node_lock(node);
199 	if ((pv = prop_get(node, pgname, pname, NULL, err))
200 	    == NULL)
201 		return (get_properror(node, err, *err));
202 
203 	if (pv->tp_type != type)
204 		return (get_properror(node, err, ETOPO_PROP_TYPE));
205 
206 	switch (type) {
207 		case TOPO_TYPE_INT32:
208 			ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
209 			    (int32_t *)val);
210 			break;
211 		case TOPO_TYPE_UINT32:
212 			ret = nvlist_lookup_uint32(pv->tp_val,
213 			    TOPO_PROP_VAL_VAL, (uint32_t *)val);
214 			break;
215 		case TOPO_TYPE_INT64:
216 			ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
217 			    (int64_t *)val);
218 			break;
219 		case TOPO_TYPE_UINT64:
220 			ret = nvlist_lookup_uint64(pv->tp_val,
221 			    TOPO_PROP_VAL_VAL, (uint64_t *)val);
222 			break;
223 		case TOPO_TYPE_STRING: {
224 			char *str;
225 
226 			ret = nvlist_lookup_string(pv->tp_val,
227 			    TOPO_PROP_VAL_VAL, &str);
228 			if (ret == 0) {
229 				char *s2;
230 				if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
231 					ret = -1;
232 				else
233 					*(char **)val = s2;
234 			}
235 			break;
236 		}
237 		case TOPO_TYPE_FMRI: {
238 			nvlist_t *nvl;
239 
240 			ret = nvlist_lookup_nvlist(pv->tp_val,
241 			    TOPO_PROP_VAL_VAL, &nvl);
242 			if (ret == 0)
243 				ret = topo_hdl_nvdup(thp, nvl,
244 				    (nvlist_t **)val);
245 			break;
246 		}
247 		case TOPO_TYPE_INT32_ARRAY: {
248 			int32_t *a1, *a2;
249 
250 			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
251 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
252 				break;
253 			if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
254 			    *nelems)) == NULL) {
255 				ret = ETOPO_NOMEM;
256 				break;
257 			}
258 			for (i = 0; i < *nelems; ++i)
259 				a1[i] = a2[i];
260 			*(int32_t **)val = a1;
261 			break;
262 		}
263 		case TOPO_TYPE_UINT32_ARRAY: {
264 			uint32_t *a1, *a2;
265 
266 			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
267 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
268 				break;
269 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
270 			    *nelems)) == NULL) {
271 				ret = ETOPO_NOMEM;
272 				break;
273 			}
274 			for (i = 0; i < *nelems; ++i)
275 				a1[i] = a2[i];
276 			*(uint32_t **)val = a1;
277 			break;
278 		}
279 		case TOPO_TYPE_INT64_ARRAY: {
280 			int64_t *a1, *a2;
281 
282 			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
283 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
284 				break;
285 			if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
286 			    *nelems)) == NULL) {
287 				ret = ETOPO_NOMEM;
288 				break;
289 			}
290 			for (i = 0; i < *nelems; ++i)
291 				a1[i] = a2[i];
292 			*(int64_t **)val = a1;
293 			break;
294 		}
295 		case TOPO_TYPE_UINT64_ARRAY: {
296 			uint64_t *a1, *a2;
297 
298 			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
299 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
300 				break;
301 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
302 			    *nelems)) == NULL) {
303 				ret = ETOPO_NOMEM;
304 				break;
305 			}
306 			for (i = 0; i < *nelems; ++i)
307 				a1[i] = a2[i];
308 			*(uint64_t **)val = a1;
309 			break;
310 		}
311 		case TOPO_TYPE_STRING_ARRAY: {
312 			char **a1, **a2;
313 
314 			if ((ret = nvlist_lookup_string_array(pv->tp_val,
315 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
316 				break;
317 			if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
318 			    *nelems)) == NULL) {
319 				ret = ETOPO_NOMEM;
320 				break;
321 			}
322 			for (i = 0; i < *nelems; ++i) {
323 				if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
324 				    == NULL) {
325 					for (j = 0; j < i; ++j)
326 						topo_hdl_free(thp, a1[j],
327 						    sizeof (char *));
328 					topo_hdl_free(thp, a1,
329 					    sizeof (char *) * *nelems);
330 					break;
331 				}
332 			}
333 			*(char ***)val = a1;
334 			break;
335 		}
336 		case TOPO_TYPE_FMRI_ARRAY: {
337 			nvlist_t **a1, **a2;
338 
339 			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
340 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
341 				break;
342 			if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
343 			    *nelems)) == NULL) {
344 				ret = ETOPO_NOMEM;
345 				break;
346 			}
347 			for (i = 0; i < *nelems; ++i) {
348 				if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
349 					for (j = 0; j < i; ++j)
350 						nvlist_free(a1[j]);
351 					topo_hdl_free(thp, a1,
352 					    sizeof (nvlist_t *) * *nelems);
353 					break;
354 				}
355 			}
356 			*(nvlist_t ***)val = a1;
357 			break;
358 		}
359 		default:
360 			ret = ETOPO_PROP_NOENT;
361 	}
362 
363 	if (ret != 0)
364 		if (ret == ENOENT)
365 			return (get_properror(node, err, ETOPO_PROP_NOENT));
366 		else if (ret < ETOPO_UNKNOWN)
367 			return (get_properror(node, err, ETOPO_PROP_NVL));
368 		else
369 			return (get_properror(node, err, ret));
370 
371 	topo_node_unlock(node);
372 	return (0);
373 }
374 
375 int
376 topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
377     int32_t *val, int *err)
378 {
379 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32,
380 	    NULL, err));
381 }
382 
383 int
384 topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
385     uint32_t *val, int *err)
386 {
387 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32,
388 	    NULL, err));
389 }
390 
391 int
392 topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
393     int64_t *val, int *err)
394 {
395 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64,
396 	    NULL, err));
397 }
398 
399 int
400 topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
401     uint64_t *val, int *err)
402 {
403 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64,
404 	    NULL, err));
405 }
406 
407 int
408 topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
409     char **val, int *err)
410 {
411 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING,
412 	    NULL, err));
413 }
414 
415 int
416 topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
417     nvlist_t **val, int *err)
418 {
419 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI,
420 	    NULL, err));
421 }
422 
423 int
424 topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname,
425     int32_t **val, uint_t *nelem, int *err)
426 {
427 	return (prop_getval(node, pgname, pname, (void *)val,
428 	    TOPO_TYPE_INT32_ARRAY, nelem, err));
429 }
430 
431 int
432 topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname,
433     uint32_t **val, uint_t *nelem, int *err)
434 {
435 	return (prop_getval(node, pgname, pname, (void *)val,
436 	    TOPO_TYPE_UINT32_ARRAY, nelem, err));
437 }
438 
439 int
440 topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname,
441     int64_t **val, uint_t *nelem, int *err)
442 {
443 	return (prop_getval(node, pgname, pname, (void *)val,
444 	    TOPO_TYPE_INT64_ARRAY, nelem, err));
445 }
446 
447 int
448 topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname,
449     uint64_t **val, uint_t *nelem, int *err)
450 {
451 	return (prop_getval(node, pgname, pname, (void *)val,
452 	    TOPO_TYPE_UINT64_ARRAY, nelem, err));
453 }
454 
455 int
456 topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname,
457     char ***val, uint_t *nelem, int *err)
458 {
459 	return (prop_getval(node, pgname, pname, (void *)val,
460 	    TOPO_TYPE_STRING_ARRAY, nelem, err));
461 }
462 
463 int
464 topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname,
465     nvlist_t ***val, uint_t *nelem, int *err)
466 {
467 	return (prop_getval(node, pgname, pname, (void *)val,
468 	    TOPO_TYPE_FMRI_ARRAY, nelem, err));
469 }
470 
471 static topo_propval_t *
472 set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
473 {
474 	topo_hdl_t *thp = node->tn_hdl;
475 	topo_propval_t *pv;
476 
477 	if (pvl != NULL) {
478 		pv = pvl->tp_pval;
479 		topo_propval_destroy(pv);
480 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
481 	}
482 
483 	topo_node_unlock(node);
484 	*errp = err;
485 
486 	return (NULL);
487 }
488 
489 static topo_propval_t *
490 prop_create(tnode_t *node, const char *pgname, const char *pname,
491     topo_type_t type, int flag, int *err)
492 {
493 	topo_hdl_t *thp = node->tn_hdl;
494 	topo_pgroup_t *pg;
495 	topo_propval_t *pv;
496 	topo_proplist_t *pvl;
497 
498 	/*
499 	 * Replace existing prop value with new one
500 	 */
501 	if ((pg = pgroup_get(node, pgname)) == NULL) {
502 		topo_node_unlock(node);
503 		*err = ETOPO_PROP_NOENT;
504 		return (NULL);
505 	}
506 
507 	if ((pv = propval_get(pg, pname)) != NULL) {
508 		if (pv->tp_type != type)
509 			return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
510 		else if (pv->tp_flag == TOPO_PROP_IMMUTABLE)
511 			return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
512 
513 		nvlist_free(pv->tp_val);
514 		pv->tp_val = NULL;
515 	} else {
516 		if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
517 		    == NULL)
518 			return (set_seterror(node, NULL, err, ETOPO_NOMEM));
519 
520 		if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
521 		    == NULL)
522 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
523 
524 		pv->tp_hdl = thp;
525 		pvl->tp_pval = pv;
526 
527 		if ((pv->tp_name = topo_hdl_strdup(thp, pname))
528 		    == NULL)
529 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
530 		pv->tp_flag = flag;
531 		pv->tp_type = type;
532 		topo_prop_hold(pv);
533 		topo_list_append(&pg->tpg_pvals, pvl);
534 	}
535 
536 	return (pv);
537 }
538 
539 static int
540 topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
541     topo_type_t type, int flag, void *val, int nelems, int *err)
542 {
543 	int ret;
544 	topo_hdl_t *thp = node->tn_hdl;
545 	nvlist_t *nvl;
546 	topo_propval_t *pv;
547 
548 	if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) {
549 		*err = ETOPO_PROP_NVL;
550 		return (-1);
551 	}
552 
553 	ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname);
554 	ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
555 	switch (type) {
556 		case TOPO_TYPE_INT32:
557 			ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
558 			    *(int32_t *)val);
559 			break;
560 		case TOPO_TYPE_UINT32:
561 			ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
562 			    *(uint32_t *)val);
563 			break;
564 		case TOPO_TYPE_INT64:
565 			ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
566 			    *(int64_t *)val);
567 			break;
568 		case TOPO_TYPE_UINT64:
569 			ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
570 			    *(uint64_t *)val);
571 			break;
572 		case TOPO_TYPE_STRING:
573 			ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
574 			    (char *)val);
575 			break;
576 		case TOPO_TYPE_FMRI:
577 			ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
578 			    (nvlist_t *)val);
579 			break;
580 		case TOPO_TYPE_INT32_ARRAY:
581 			ret |= nvlist_add_int32_array(nvl,
582 			    TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
583 			break;
584 		case TOPO_TYPE_UINT32_ARRAY:
585 			ret |= nvlist_add_uint32_array(nvl,
586 			    TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
587 			break;
588 		case TOPO_TYPE_INT64_ARRAY:
589 			ret |= nvlist_add_int64_array(nvl,
590 			    TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
591 			break;
592 		case TOPO_TYPE_UINT64_ARRAY:
593 			ret |= nvlist_add_uint64_array(nvl,
594 			    TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
595 			break;
596 		case TOPO_TYPE_STRING_ARRAY:
597 			ret |= nvlist_add_string_array(nvl,
598 			    TOPO_PROP_VAL_VAL, (char **)val, nelems);
599 			break;
600 		case TOPO_TYPE_FMRI_ARRAY:
601 			ret |= nvlist_add_nvlist_array(nvl,
602 			    TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
603 			break;
604 		default:
605 			*err = ETOPO_PROP_TYPE;
606 			return (-1);
607 	}
608 
609 	if (ret != 0) {
610 		nvlist_free(nvl);
611 		if (ret == ENOMEM) {
612 			*err = ETOPO_PROP_NOMEM;
613 			return (-1);
614 		} else {
615 			*err = ETOPO_PROP_NVL;
616 			return (-1);
617 		}
618 	}
619 
620 	topo_node_lock(node);
621 	if ((pv = prop_create(node, pgname, pname, type, flag, err)) == NULL) {
622 		nvlist_free(nvl);
623 		return (-1); /* unlocked and err set */
624 	}
625 
626 	pv->tp_val = nvl;
627 
628 	topo_node_unlock(node);
629 
630 	return (ret);
631 }
632 
633 int
634 topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
635     int flag, int32_t val, int *err)
636 {
637 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
638 	    &val, 1, err));
639 }
640 
641 int
642 topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
643     int flag, uint32_t val, int *err)
644 {
645 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
646 	    &val, 1, err));
647 }
648 
649 int
650 topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
651     int flag, int64_t val, int *err)
652 {
653 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
654 	    &val, 1, err));
655 }
656 
657 int
658 topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
659     int flag, uint64_t val, int *err)
660 {
661 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
662 	    &val, 1, err));
663 }
664 
665 int
666 topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
667     int flag, const char *val, int *err)
668 {
669 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
670 	    (void *)val, 1, err));
671 }
672 
673 int
674 topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
675     int flag, const nvlist_t *fmri, int *err)
676 {
677 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
678 	    (void *)fmri, 1, err));
679 }
680 
681 int
682 topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname,
683     int flag, int32_t *val, uint_t nelems, int *err)
684 {
685 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag,
686 	    val, nelems, err));
687 }
688 
689 int
690 topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname,
691     int flag, uint32_t *val, uint_t nelems, int *err)
692 {
693 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag,
694 	    val, nelems, err));
695 }
696 
697 int
698 topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname,
699     int flag, int64_t *val, uint_t nelems, int *err)
700 {
701 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag,
702 	    val, nelems, err));
703 }
704 
705 int
706 topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname,
707     int flag, uint64_t *val, uint_t nelems, int *err)
708 {
709 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag,
710 	    val, nelems, err));
711 }
712 
713 int
714 topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname,
715     int flag, const char **val, uint_t nelems, int *err)
716 {
717 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag,
718 	    (void *)val, nelems, err));
719 }
720 
721 int
722 topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname,
723     int flag, const nvlist_t **fmri, uint_t nelems, int *err)
724 {
725 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag,
726 	    (void *)fmri, nelems, err));
727 }
728 
729 /*
730  * topo_prop_setprop() is a private project function for fmtopo
731  */
732 int
733 topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop,
734     int flag, nvlist_t *pargs, int *err)
735 {
736 	int ret;
737 	topo_hdl_t *thp = node->tn_hdl;
738 	topo_propval_t *pv;
739 	nvlist_t *nvl, *args;
740 	char *name;
741 	topo_type_t type;
742 
743 	if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) {
744 		*err = ETOPO_PROP_NAME;
745 		return (-1);
746 	}
747 	if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type)
748 	    != 0) {
749 		*err = ETOPO_PROP_TYPE;
750 		return (-1);
751 	}
752 
753 	topo_node_lock(node);
754 	if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL)
755 		return (-1); /* unlocked and err set */
756 
757 	/*
758 	 * Set by method or set to new prop value.  If we fail, leave
759 	 * property in list with old value.
760 	 */
761 	if (pv->tp_method != NULL) {
762 		topo_propmethod_t *pm = pv->tp_method;
763 
764 		if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) {
765 			topo_node_unlock(node);
766 			*err = ETOPO_PROP_NOMEM;
767 			return (-1);
768 		}
769 		ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args);
770 		if (pargs != NULL)
771 			ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs);
772 
773 		if (ret != 0) {
774 			topo_node_unlock(node);
775 			nvlist_free(args);
776 			*err = ETOPO_PROP_NVL;
777 			return (-1);
778 		}
779 
780 		ret = topo_method_call(node, pm->tpm_name, pm->tpm_version,
781 		    args, &nvl, err);
782 		nvlist_free(args);
783 	} else {
784 		if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0)
785 			*err = ETOPO_PROP_NOMEM;
786 	}
787 
788 	if (ret != 0) {
789 		topo_node_unlock(node);
790 		return (-1);
791 	}
792 
793 	pv->tp_val = nvl;
794 	topo_node_unlock(node);
795 	return (0);
796 }
797 
798 static int
799 register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
800     int err)
801 {
802 	topo_hdl_t *thp = node->tn_hdl;
803 
804 	if (pm != NULL) {
805 		if (pm->tpm_name != NULL)
806 			topo_hdl_strfree(thp, pm->tpm_name);
807 		if (pm->tpm_args != NULL)
808 			nvlist_free(pm->tpm_args);
809 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
810 	}
811 
812 	*errp = err;
813 
814 	if (l != 0)
815 		topo_node_unlock(node);
816 
817 	return (-1);
818 }
819 
820 int
821 prop_method_register(tnode_t *node, const char *pgname, const char *pname,
822     topo_type_t ptype, const char *mname, topo_version_t version,
823     const nvlist_t *args, int *err)
824 {
825 	topo_hdl_t *thp = node->tn_hdl;
826 	topo_propmethod_t *pm = NULL;
827 	topo_propval_t *pv = NULL;
828 
829 	if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL)
830 		return (register_methoderror(node, pm, err, 1,
831 		    ETOPO_PROP_NOMEM));
832 
833 	if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL)
834 		return (register_methoderror(node, pm, err, 1,
835 		    ETOPO_PROP_NOMEM));
836 
837 	pm->tpm_version = version;
838 
839 	if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0)
840 		return (register_methoderror(node, pm, err, 1,
841 		    ETOPO_PROP_NOMEM));
842 
843 	if ((pv = prop_create(node, pgname, pname, ptype, TOPO_PROP_MUTABLE,
844 	    err)) == NULL) {
845 		/* node unlocked */
846 		return (register_methoderror(node, pm, err, 0, *err));
847 	}
848 
849 	if (pv->tp_method != NULL)
850 		return (register_methoderror(node, pm, err, 1,
851 		    ETOPO_METHOD_DEFD));
852 
853 	pv->tp_val = NULL;
854 	pv->tp_method = pm;
855 
856 	topo_node_unlock(node);
857 
858 	return (0);
859 }
860 
861 int
862 topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname,
863     topo_type_t ptype, const char *mname, const nvlist_t *args, int *err)
864 {
865 	topo_imethod_t *mp;
866 
867 	topo_node_lock(node);
868 
869 	if ((mp = topo_method_lookup(node, mname)) == NULL)
870 		return (register_methoderror(node, NULL, err, 1,
871 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
872 
873 	topo_node_lock(node);
874 
875 	return (prop_method_register(node, pgname, pname, ptype, mname,
876 	    mp->tim_version, args, err)); /* err set and node unlocked */
877 }
878 
879 int
880 topo_prop_method_version_register(tnode_t *node, const char *pgname,
881     const char *pname, topo_type_t ptype, const char *mname,
882     topo_version_t version, const nvlist_t *args, int *err)
883 {
884 	topo_imethod_t *mp;
885 
886 	topo_node_lock(node);
887 
888 	if ((mp = topo_method_lookup(node, mname)) == NULL)
889 		return (register_methoderror(node, NULL, err, 1,
890 		    ETOPO_METHOD_NOTSUP)); /* node unlocked */
891 
892 	topo_node_lock(node);
893 
894 	if (version < mp->tim_version)
895 		return (register_methoderror(node, NULL, err, 1,
896 		    ETOPO_METHOD_VEROLD));
897 	if (version > mp->tim_version)
898 		return (register_methoderror(node, NULL, err, 1,
899 		    ETOPO_METHOD_VERNEW));
900 
901 	return (prop_method_register(node, pgname, pname, ptype, mname,
902 	    version, args, err)); /* err set and node unlocked */
903 }
904 
905 void
906 topo_prop_method_unregister(tnode_t *node, const char *pgname,
907     const char *pname)
908 {
909 	topo_propval_t *pv;
910 	topo_pgroup_t *pg;
911 	topo_proplist_t *pvl;
912 	topo_hdl_t *thp = node->tn_hdl;
913 
914 	topo_node_lock(node);
915 
916 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
917 	    pg = topo_list_next(pg)) {
918 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
919 			break;
920 		}
921 	}
922 
923 	if (pg == NULL) {
924 		topo_node_unlock(node);
925 		return;
926 	}
927 
928 	for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
929 	    pvl = topo_list_next(pvl)) {
930 		pv = pvl->tp_pval;
931 		if (strcmp(pv->tp_name, pname) == 0) {
932 			topo_list_delete(&pg->tpg_pvals, pvl);
933 			assert(pv->tp_refs == 1);
934 			topo_prop_rele(pv);
935 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
936 			break;
937 		}
938 	}
939 
940 	topo_node_unlock(node);
941 }
942 
943 static int
944 inherit_seterror(tnode_t *node, int *errp, int err)
945 {
946 	topo_node_unlock(node);
947 	topo_node_unlock(node->tn_parent);
948 
949 	*errp = err;
950 
951 	return (-1);
952 }
953 
954 int
955 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
956 {
957 	topo_hdl_t *thp = node->tn_hdl;
958 	tnode_t *pnode = node->tn_parent;
959 	topo_pgroup_t *pg;
960 	topo_propval_t *pv;
961 	topo_proplist_t *pvl;
962 
963 	topo_node_lock(pnode);
964 	topo_node_lock(node);
965 	/*
966 	 * Check for an existing property group and prop val
967 	 */
968 	if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
969 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
970 
971 	/*
972 	 * Can this propval be inherited?
973 	 */
974 	if (pv->tp_flag != TOPO_PROP_IMMUTABLE)
975 		return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
976 
977 	/*
978 	 * Property group should already exist: bump the ref count for this
979 	 * propval and add it to the node's property group
980 	 */
981 	if ((pg = pgroup_get(node, pgname)) == NULL)
982 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
983 
984 	if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
985 	    == NULL)
986 		return (inherit_seterror(node, err, ETOPO_NOMEM));
987 
988 	topo_prop_hold(pv);
989 	pvl->tp_pval = pv;
990 	topo_list_append(&pg->tpg_pvals, pvl);
991 
992 	topo_node_unlock(node);
993 	topo_node_unlock(pnode);
994 
995 	return (0);
996 }
997 
998 topo_pgroup_info_t *
999 topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
1000 {
1001 	topo_hdl_t *thp = node->tn_hdl;
1002 	topo_pgroup_t *pg;
1003 	topo_ipgroup_info_t *pip;
1004 	topo_pgroup_info_t *info;
1005 
1006 	topo_node_lock(node);
1007 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1008 	    pg = topo_list_next(pg)) {
1009 		if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
1010 			if ((info = topo_hdl_alloc(thp,
1011 			    sizeof (topo_pgroup_info_t))) == NULL)
1012 				return (NULL);
1013 
1014 			pip = pg->tpg_info;
1015 			if ((info->tpi_name =
1016 			    topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
1017 				*err = ETOPO_PROP_NOMEM;
1018 				topo_hdl_free(thp, info,
1019 				    sizeof (topo_pgroup_info_t));
1020 				topo_node_unlock(node);
1021 				return (NULL);
1022 			}
1023 			info->tpi_namestab = pip->tpi_namestab;
1024 			info->tpi_datastab = pip->tpi_datastab;
1025 			info->tpi_version = pip->tpi_version;
1026 			topo_node_unlock(node);
1027 			return (info);
1028 		}
1029 	}
1030 
1031 	*err = ETOPO_PROP_NOENT;
1032 	topo_node_unlock(node);
1033 	return (NULL);
1034 }
1035 
1036 static int
1037 pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
1038     int *err)
1039 {
1040 	topo_hdl_t *thp = node->tn_hdl;
1041 
1042 	if (pip != NULL) {
1043 		if (pip->tpi_name != NULL)
1044 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
1045 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
1046 	}
1047 
1048 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1049 	*err = ETOPO_NOMEM;
1050 
1051 	topo_node_unlock(node);
1052 
1053 	return (-1);
1054 }
1055 
1056 int
1057 topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err)
1058 {
1059 	topo_pgroup_t *pg;
1060 	topo_ipgroup_info_t *pip;
1061 	topo_hdl_t *thp = node->tn_hdl;
1062 
1063 	*err = 0;
1064 
1065 	topo_node_lock(node);
1066 	/*
1067 	 * Check for an existing pgroup
1068 	 */
1069 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1070 	    pg = topo_list_next(pg)) {
1071 		if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) {
1072 			*err = ETOPO_PROP_DEFD;
1073 			topo_node_unlock(node);
1074 			return (-1);
1075 		}
1076 	}
1077 
1078 	if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) {
1079 		*err = ETOPO_NOMEM;
1080 		topo_node_unlock(node);
1081 		return (-1);
1082 	}
1083 
1084 	if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t)))
1085 	    == NULL)
1086 		return (pgroup_seterr(node, pg, pip, err));
1087 
1088 	if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name))
1089 	    == NULL)
1090 		return (pgroup_seterr(node, pg, pip, err));
1091 
1092 	pip->tpi_namestab = pinfo->tpi_namestab;
1093 	pip->tpi_datastab = pinfo->tpi_datastab;
1094 	pip->tpi_version = pinfo->tpi_version;
1095 
1096 	pg->tpg_info = pip;
1097 
1098 	topo_list_append(&node->tn_pgroups, pg);
1099 	topo_node_unlock(node);
1100 
1101 	return (0);
1102 }
1103 
1104 void
1105 topo_pgroup_destroy(tnode_t *node, const char *pname)
1106 {
1107 	topo_hdl_t *thp = node->tn_hdl;
1108 	topo_pgroup_t *pg;
1109 	topo_proplist_t *pvl;
1110 	topo_ipgroup_info_t *pip;
1111 
1112 	topo_node_lock(node);
1113 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1114 	    pg = topo_list_next(pg)) {
1115 		if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
1116 			break;
1117 		}
1118 	}
1119 
1120 	if (pg == NULL) {
1121 		topo_node_unlock(node);
1122 		return;
1123 	}
1124 
1125 	while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
1126 		topo_list_delete(&pg->tpg_pvals, pvl);
1127 		topo_prop_rele(pvl->tp_pval);
1128 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1129 	}
1130 
1131 	topo_list_delete(&node->tn_pgroups, pg);
1132 	topo_node_unlock(node);
1133 
1134 	pip = pg->tpg_info;
1135 	if (pip != NULL) {
1136 		if (pip->tpi_name != NULL)
1137 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
1138 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
1139 	}
1140 
1141 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1142 }
1143 
1144 void
1145 topo_pgroup_destroy_all(tnode_t *node)
1146 {
1147 	topo_hdl_t *thp = node->tn_hdl;
1148 	topo_pgroup_t *pg;
1149 	topo_proplist_t *pvl;
1150 	topo_ipgroup_info_t *pip;
1151 
1152 	topo_node_lock(node);
1153 	while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
1154 		while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
1155 			topo_list_delete(&pg->tpg_pvals, pvl);
1156 			topo_prop_rele(pvl->tp_pval);
1157 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1158 		}
1159 
1160 		topo_list_delete(&node->tn_pgroups, pg);
1161 
1162 		pip = pg->tpg_info;
1163 		if (pip != NULL) {
1164 			if (pip->tpi_name != NULL)
1165 				topo_hdl_strfree(thp, (char *)pip->tpi_name);
1166 			topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
1167 		}
1168 
1169 		topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1170 	}
1171 	topo_node_unlock(node);
1172 }
1173 
1174 static void
1175 propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
1176 {
1177 	topo_propmethod_t *pm;
1178 
1179 	pm = pv->tp_method;
1180 	if (pm != NULL) {
1181 		if (pm->tpm_name != NULL)
1182 			topo_hdl_strfree(thp, pm->tpm_name);
1183 		if (pm->tpm_args != NULL)
1184 			nvlist_free(pm->tpm_args);
1185 		topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
1186 		pv->tp_method = NULL;
1187 	}
1188 }
1189 
1190 static void
1191 topo_propval_destroy(topo_propval_t *pv)
1192 {
1193 	topo_hdl_t *thp;
1194 
1195 	if (pv == NULL)
1196 		return;
1197 
1198 	thp = pv->tp_hdl;
1199 
1200 	if (pv->tp_name != NULL)
1201 		topo_hdl_strfree(thp, pv->tp_name);
1202 
1203 	if (pv->tp_val != NULL)
1204 		nvlist_free(pv->tp_val);
1205 
1206 	propmethod_destroy(thp, pv);
1207 
1208 	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
1209 }
1210 
1211 void
1212 topo_prop_hold(topo_propval_t *pv)
1213 {
1214 	pv->tp_refs++;
1215 }
1216 
1217 void
1218 topo_prop_rele(topo_propval_t *pv)
1219 {
1220 	pv->tp_refs--;
1221 
1222 	assert(pv->tp_refs >= 0);
1223 
1224 	if (pv->tp_refs == 0)
1225 		topo_propval_destroy(pv);
1226 }
1227 
1228 /*
1229  * topo_prop_getprop() and topo_prop_getprops() are private project functions
1230  * for fmtopo
1231  */
1232 int
1233 topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname,
1234     nvlist_t *args, nvlist_t **prop, int *err)
1235 {
1236 	topo_hdl_t *thp = node->tn_hdl;
1237 	topo_propval_t *pv;
1238 
1239 	topo_node_lock(node);
1240 	if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) {
1241 		(void) get_properror(node, err, *err);
1242 		return (-1);
1243 	}
1244 
1245 	if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) {
1246 		(void) get_properror(node, err, ETOPO_NOMEM);
1247 		return (-1);
1248 	}
1249 	topo_node_unlock(node);
1250 
1251 	return (0);
1252 }
1253 
1254 static int
1255 prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err)
1256 {
1257 	if (pv->tp_method != NULL)
1258 		if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0)
1259 			return (-1);
1260 
1261 	if (pv->tp_val == NULL) {
1262 		*err = ETOPO_PROP_NOENT;
1263 		return (-1);
1264 	}
1265 
1266 	if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) {
1267 		*err = ETOPO_PROP_NOMEM;
1268 		return (-1);
1269 	}
1270 
1271 	return (0);
1272 }
1273 
1274 static int
1275 get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1276 {
1277 	topo_node_unlock(node);
1278 
1279 	if (nvl != NULL)
1280 		nvlist_free(nvl);
1281 
1282 	*errp = err;
1283 
1284 	return (-1);
1285 }
1286 
1287 int
1288 topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp,
1289     int *err)
1290 {
1291 	int ret;
1292 	topo_hdl_t *thp = node->tn_hdl;
1293 	nvlist_t *nvl, *pvnvl;
1294 	topo_pgroup_t *pg;
1295 	topo_propval_t *pv;
1296 	topo_proplist_t *pvl;
1297 
1298 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1299 		*err = ETOPO_NOMEM;
1300 		return (-1);
1301 	}
1302 
1303 	topo_node_lock(node);
1304 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1305 	    pg = topo_list_next(pg)) {
1306 
1307 		if (strcmp(pgname, pg->tpg_info->tpi_name) != 0)
1308 			continue;
1309 
1310 		if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME,
1311 		    pg->tpg_info->tpi_name) != 0 ||
1312 		    nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB,
1313 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1314 		    nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB,
1315 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1316 		    nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION,
1317 		    pg->tpg_info->tpi_version) != 0)
1318 			return (get_pgrp_seterror(node, nvl, err,
1319 			    ETOPO_PROP_NVL));
1320 
1321 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1322 		    pvl = topo_list_next(pvl)) {
1323 
1324 			pv = pvl->tp_pval;
1325 			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1326 				return (get_pgrp_seterror(node, nvl, err,
1327 				    *err));
1328 			}
1329 			if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL,
1330 			    pvnvl)) != 0) {
1331 				nvlist_free(pvnvl);
1332 				return (get_pgrp_seterror(node, nvl, err, ret));
1333 			}
1334 
1335 			nvlist_free(pvnvl);
1336 		}
1337 		topo_node_unlock(node);
1338 		*pgrp = nvl;
1339 		return (0);
1340 	}
1341 
1342 	topo_node_unlock(node);
1343 	*err = ETOPO_PROP_NOENT;
1344 	return (-1);
1345 }
1346 
1347 static nvlist_t *
1348 get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1349 {
1350 	topo_node_unlock(node);
1351 
1352 	if (nvl != NULL)
1353 		nvlist_free(nvl);
1354 
1355 	*errp = err;
1356 
1357 	return (NULL);
1358 }
1359 
1360 nvlist_t *
1361 topo_prop_getprops(tnode_t *node, int *err)
1362 {
1363 	int ret;
1364 	topo_hdl_t *thp = node->tn_hdl;
1365 	nvlist_t *nvl, *pgnvl, *pvnvl;
1366 	topo_pgroup_t *pg;
1367 	topo_propval_t *pv;
1368 	topo_proplist_t *pvl;
1369 
1370 	topo_node_lock(node);
1371 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1372 		return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
1373 	}
1374 
1375 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1376 	    pg = topo_list_next(pg)) {
1377 		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
1378 			return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
1379 
1380 		if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
1381 		    pg->tpg_info->tpi_name) != 0 ||
1382 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
1383 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1384 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
1385 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1386 		    nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
1387 		    pg->tpg_info->tpi_version) != 0)
1388 			return (get_all_seterror(node, nvl, err,
1389 			    ETOPO_PROP_NVL));
1390 
1391 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1392 		    pvl = topo_list_next(pvl)) {
1393 
1394 			pv = pvl->tp_pval;
1395 			if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1396 				nvlist_free(pgnvl);
1397 				return (get_all_seterror(node, nvl, err, *err));
1398 			}
1399 			if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
1400 			    pvnvl)) != 0) {
1401 				nvlist_free(pgnvl);
1402 				nvlist_free(pvnvl);
1403 				return (get_all_seterror(node, nvl, err, ret));
1404 			}
1405 
1406 			nvlist_free(pvnvl);
1407 		}
1408 		if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
1409 		    != 0) {
1410 			nvlist_free(pgnvl);
1411 			return (get_all_seterror(node, nvl, err, ret));
1412 		}
1413 
1414 		nvlist_free(pgnvl);
1415 	}
1416 
1417 	topo_node_unlock(node);
1418 
1419 	return (nvl);
1420 }
1421