xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_prop.c (revision 4e93fb0f6383eaac21897dcdae56b87118131e4d)
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 2006 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 
36 static topo_pgroup_t *
37 pgroup_get(tnode_t *node, const char *pgname)
38 {
39 	topo_pgroup_t *pg;
40 	/*
41 	 * Check for an existing pgroup
42 	 */
43 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
44 	    pg = topo_list_next(pg)) {
45 		if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
46 			return (pg);
47 		}
48 	}
49 
50 	return (NULL);
51 }
52 
53 static topo_propval_t *
54 propval_get(topo_pgroup_t *pg, const char *pname)
55 {
56 	topo_proplist_t *pvl;
57 
58 	for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
59 	    pvl = topo_list_next(pvl)) {
60 		if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
61 			return (pvl->tp_pval);
62 	}
63 
64 	return (NULL);
65 }
66 
67 static topo_propval_t *
68 topo_prop_get(tnode_t *node, const char *pgname, const char *pname, int *err)
69 {
70 	topo_pgroup_t *pg = NULL;
71 	topo_propval_t *pv = NULL;
72 
73 	if ((pg = pgroup_get(node, pgname)) == NULL) {
74 		*err = ETOPO_PROP_NOENT;
75 		return (NULL);
76 	}
77 
78 	if ((pv = propval_get(pg, pname)) == NULL) {
79 		*err = ETOPO_PROP_NOENT;
80 		return (NULL);
81 	}
82 
83 	return (pv);
84 }
85 
86 static int
87 prop_val_add(nvlist_t *nvl, topo_propval_t *pv, int *err)
88 {
89 	int ret = 0;
90 	uint_t nelems;
91 
92 	if (nvlist_add_int32(nvl, TOPO_PROP_VAL_TYPE, pv->tp_type) != 0)
93 		return (-1);
94 
95 	switch (pv->tp_type) {
96 		case TOPO_TYPE_INT32:
97 		{
98 			int32_t val;
99 			if ((ret = nvlist_lookup_int32(pv->tp_val,
100 			    TOPO_PROP_VAL_VAL, &val)) < 0)
101 				break;
102 			ret = nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, val);
103 		}
104 		break;
105 		case TOPO_TYPE_UINT32:
106 		{
107 			uint32_t val;
108 			if ((ret = nvlist_lookup_uint32(pv->tp_val,
109 			    TOPO_PROP_VAL_VAL, &val)) < 0)
110 				break;
111 			ret = nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, val);
112 		}
113 		break;
114 		case TOPO_TYPE_INT64:
115 		{
116 			int64_t val;
117 			if ((ret = nvlist_lookup_int64(pv->tp_val,
118 			    TOPO_PROP_VAL_VAL, &val)) < 0)
119 				break;
120 			ret = nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, val);
121 		}
122 		break;
123 		case TOPO_TYPE_UINT64:
124 		{
125 			uint64_t val;
126 			if ((ret = nvlist_lookup_uint64(pv->tp_val,
127 			    TOPO_PROP_VAL_VAL, &val)) < 0)
128 				break;
129 			ret = nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, val);
130 		}
131 		break;
132 		case TOPO_TYPE_STRING:
133 		{
134 			char *val;
135 			if ((ret = nvlist_lookup_string(pv->tp_val,
136 			    TOPO_PROP_VAL_VAL, &val)) < 0)
137 				break;
138 			ret = nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, val);
139 		}
140 		break;
141 		case TOPO_TYPE_FMRI:
142 		{
143 			nvlist_t *val;
144 			if ((ret = nvlist_lookup_nvlist(pv->tp_val,
145 			    TOPO_PROP_VAL_VAL, &val)) < 0)
146 				break;
147 			ret =  nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, val);
148 		}
149 		break;
150 		case TOPO_TYPE_INT32_ARRAY:
151 		{
152 			int32_t *val;
153 			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
154 			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
155 				break;
156 			ret = nvlist_add_int32_array(nvl, TOPO_PROP_VAL_VAL,
157 			    val, nelems);
158 		}
159 		break;
160 		case TOPO_TYPE_UINT32_ARRAY:
161 		{
162 			uint32_t *val;
163 			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
164 			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
165 				break;
166 			ret = nvlist_add_uint32_array(nvl, TOPO_PROP_VAL_VAL,
167 			    val, nelems);
168 		}
169 		break;
170 		case TOPO_TYPE_INT64_ARRAY:
171 		{
172 			int64_t *val;
173 			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
174 			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
175 				break;
176 			ret = nvlist_add_int64_array(nvl, TOPO_PROP_VAL_VAL,
177 			    val, nelems);
178 		}
179 		break;
180 		case TOPO_TYPE_UINT64_ARRAY:
181 		{
182 			uint64_t *val;
183 			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
184 			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
185 				break;
186 			ret = nvlist_add_uint64_array(nvl, TOPO_PROP_VAL_VAL,
187 			    val, nelems);
188 		}
189 		break;
190 		case TOPO_TYPE_STRING_ARRAY:
191 		{
192 			char **val;
193 			if ((ret = nvlist_lookup_string_array(pv->tp_val,
194 			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
195 				break;
196 			ret = nvlist_add_string_array(nvl, TOPO_PROP_VAL_VAL,
197 			    val, nelems);
198 		}
199 		break;
200 		case TOPO_TYPE_FMRI_ARRAY:
201 		{
202 			nvlist_t **val;
203 			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
204 			    TOPO_PROP_VAL_VAL, &val, &nelems)) < 0)
205 				break;
206 			ret = nvlist_add_nvlist_array(nvl, TOPO_PROP_VAL_VAL,
207 			    val, nelems);
208 		}
209 		break;
210 		default:
211 			ret = ETOPO_PROP_TYPE;
212 	}
213 
214 	if (ret != 0) {
215 		if (ret == ENOMEM)
216 			*err = ETOPO_NOMEM;
217 		else
218 			*err = ETOPO_PROP_NVL;
219 		return (-1);
220 	}
221 
222 	return (0);
223 }
224 
225 nvlist_t *
226 get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
227 {
228 	topo_node_unlock(node);
229 
230 	if (nvl != NULL)
231 		nvlist_free(nvl);
232 
233 	*errp = err;
234 
235 	return (NULL);
236 }
237 
238 nvlist_t *
239 topo_prop_getprops(tnode_t *node, int *err)
240 {
241 	int ret;
242 	topo_hdl_t *thp = node->tn_hdl;
243 	nvlist_t *nvl, *pgnvl, *pvnvl;
244 	topo_pgroup_t *pg;
245 	topo_propval_t *pv;
246 	topo_proplist_t *pvl;
247 
248 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
249 		return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
250 	}
251 
252 	topo_node_lock(node);
253 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
254 	    pg = topo_list_next(pg)) {
255 		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
256 			return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
257 
258 		if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
259 		    pg->tpg_info->tpi_name) != 0 ||
260 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
261 		    topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
262 		    nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
263 		    topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
264 		    nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
265 		    pg->tpg_info->tpi_version) != 0)
266 			return (get_all_seterror(node, nvl, err,
267 			    ETOPO_PROP_NVL));
268 
269 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
270 		    pvl = topo_list_next(pvl)) {
271 
272 			pv = pvl->tp_pval;
273 			if (topo_hdl_nvalloc(thp, &pvnvl, 0)
274 			    != 0) {
275 				nvlist_free(pgnvl);
276 				return (get_all_seterror(node, nvl, err,
277 				    ETOPO_NOMEM));
278 			}
279 			if ((ret = nvlist_add_string(pvnvl, TOPO_PROP_VAL_NAME,
280 			    pv->tp_name)) != 0) {
281 				nvlist_free(pgnvl);
282 				nvlist_free(pvnvl);
283 				return (get_all_seterror(node, nvl, err, ret));
284 			}
285 			if (prop_val_add(pvnvl, pv, err) < 0) {
286 				nvlist_free(pgnvl);
287 				nvlist_free(pvnvl);
288 				return (get_all_seterror(node, nvl, err, ret));
289 			}
290 			if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
291 			    pvnvl)) != 0) {
292 				nvlist_free(pgnvl);
293 				nvlist_free(pvnvl);
294 				return (get_all_seterror(node, nvl, err, ret));
295 			}
296 
297 			nvlist_free(pvnvl);
298 		}
299 		if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
300 		    != 0) {
301 			nvlist_free(pgnvl);
302 			return (get_all_seterror(node, nvl, err, ret));
303 		}
304 
305 		nvlist_free(pgnvl);
306 	}
307 
308 	topo_node_unlock(node);
309 
310 	return (nvl);
311 }
312 
313 static int
314 get_seterror(tnode_t *node, int *errp, int err)
315 {
316 	topo_node_unlock(node);
317 	*errp = err;
318 	return (-1);
319 }
320 
321 static int
322 prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
323     topo_type_t type, uint_t *nelems, int *err)
324 {
325 	int i, j, ret = 0;
326 	topo_hdl_t *thp = node->tn_hdl;
327 	topo_propval_t *pv;
328 
329 	topo_node_lock(node);
330 	if ((pv = topo_prop_get(node, pgname, pname, err))
331 	    == NULL)
332 		return (get_seterror(node, err, *err));
333 
334 	if (pv->tp_type != type)
335 		return (get_seterror(node, err, ETOPO_PROP_TYPE));
336 
337 	switch (type) {
338 		case TOPO_TYPE_INT32:
339 			ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
340 			    (int32_t *)val);
341 			break;
342 		case TOPO_TYPE_UINT32:
343 			ret = nvlist_lookup_uint32(pv->tp_val,
344 			    TOPO_PROP_VAL_VAL, (uint32_t *)val);
345 			break;
346 		case TOPO_TYPE_INT64:
347 			ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
348 			    (int64_t *)val);
349 			break;
350 		case TOPO_TYPE_UINT64:
351 			ret = nvlist_lookup_uint64(pv->tp_val,
352 			    TOPO_PROP_VAL_VAL, (uint64_t *)val);
353 			break;
354 		case TOPO_TYPE_STRING: {
355 			char *str;
356 
357 			ret = nvlist_lookup_string(pv->tp_val,
358 			    TOPO_PROP_VAL_VAL, &str);
359 			if (ret == 0)
360 				*(char **)val = topo_hdl_strdup(thp, str);
361 			break;
362 		}
363 		case TOPO_TYPE_FMRI: {
364 			nvlist_t *nvl;
365 
366 			ret = nvlist_lookup_nvlist(pv->tp_val,
367 			    TOPO_PROP_VAL_VAL, &nvl);
368 			if (ret == 0)
369 				ret = topo_hdl_nvdup(thp, nvl,
370 				    (nvlist_t **)val);
371 			break;
372 		}
373 		case TOPO_TYPE_INT32_ARRAY: {
374 			int32_t *a1, *a2;
375 
376 			if ((ret = nvlist_lookup_int32_array(pv->tp_val,
377 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
378 				break;
379 			if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
380 			    *nelems)) == NULL) {
381 				ret = ETOPO_NOMEM;
382 				break;
383 			}
384 			for (i = 0; i < *nelems; ++i)
385 				a1[i] = a2[i];
386 			*(int32_t **)val = a1;
387 			break;
388 		}
389 		case TOPO_TYPE_UINT32_ARRAY: {
390 			uint32_t *a1, *a2;
391 
392 			if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
393 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
394 				break;
395 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
396 			    *nelems)) == NULL) {
397 				ret = ETOPO_NOMEM;
398 				break;
399 			}
400 			for (i = 0; i < *nelems; ++i)
401 				a1[i] = a2[i];
402 			*(uint32_t **)val = a1;
403 			break;
404 		}
405 		case TOPO_TYPE_INT64_ARRAY: {
406 			int64_t *a1, *a2;
407 
408 			if ((ret = nvlist_lookup_int64_array(pv->tp_val,
409 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
410 				break;
411 			if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
412 			    *nelems)) == NULL) {
413 				ret = ETOPO_NOMEM;
414 				break;
415 			}
416 			for (i = 0; i < *nelems; ++i)
417 				a1[i] = a2[i];
418 			*(int64_t **)val = a1;
419 			break;
420 		}
421 		case TOPO_TYPE_UINT64_ARRAY: {
422 			uint64_t *a1, *a2;
423 
424 			if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
425 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
426 				break;
427 			if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
428 			    *nelems)) == NULL) {
429 				ret = ETOPO_NOMEM;
430 				break;
431 			}
432 			for (i = 0; i < *nelems; ++i)
433 				a1[i] = a2[i];
434 			*(uint64_t **)val = a1;
435 			break;
436 		}
437 		case TOPO_TYPE_STRING_ARRAY: {
438 			char **a1, **a2;
439 
440 			if ((ret = nvlist_lookup_string_array(pv->tp_val,
441 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
442 				break;
443 			if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
444 			    *nelems)) == NULL) {
445 				ret = ETOPO_NOMEM;
446 				break;
447 			}
448 			for (i = 0; i < *nelems; ++i) {
449 				if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
450 				    == NULL) {
451 					for (j = 0; j < i; ++j)
452 						topo_hdl_free(thp, a1[j],
453 						    sizeof (char *));
454 					topo_hdl_free(thp, a1,
455 					    sizeof (char *) * *nelems);
456 					break;
457 				}
458 			}
459 			*(char ***)val = a1;
460 			break;
461 		}
462 		case TOPO_TYPE_FMRI_ARRAY: {
463 			nvlist_t **a1, **a2;
464 
465 			if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
466 			    TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
467 				break;
468 			if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
469 			    *nelems)) == NULL) {
470 				ret = ETOPO_NOMEM;
471 				break;
472 			}
473 			for (i = 0; i < *nelems; ++i) {
474 				if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
475 					for (j = 0; j < i; ++j)
476 						nvlist_free(a1[j]);
477 					topo_hdl_free(thp, a1,
478 					    sizeof (nvlist_t *) * *nelems);
479 					break;
480 				}
481 			}
482 			*(nvlist_t ***)val = a1;
483 			break;
484 		}
485 		default:
486 			ret = ETOPO_PROP_NOENT;
487 	}
488 
489 	if (ret != 0)
490 		if (ret == ENOENT)
491 			return (get_seterror(node, err, ETOPO_PROP_NOENT));
492 		else if (ret < ETOPO_UNKNOWN)
493 			return (get_seterror(node, err, ETOPO_PROP_NVL));
494 		else
495 			return (get_seterror(node, err, ret));
496 
497 	topo_node_unlock(node);
498 	return (0);
499 }
500 
501 int
502 topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
503     int32_t *val, int *err)
504 {
505 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32,
506 	    NULL, err));
507 }
508 
509 int
510 topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
511     uint32_t *val, int *err)
512 {
513 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32,
514 	    NULL, err));
515 }
516 
517 int
518 topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
519     int64_t *val, int *err)
520 {
521 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64,
522 	    NULL, err));
523 }
524 
525 int
526 topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
527     uint64_t *val, int *err)
528 {
529 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64,
530 	    NULL, err));
531 }
532 
533 int
534 topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
535     char **val, int *err)
536 {
537 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING,
538 	    NULL, err));
539 }
540 
541 int
542 topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
543     nvlist_t **val, int *err)
544 {
545 	return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI,
546 	    NULL, err));
547 }
548 
549 int
550 topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname,
551     int32_t **val, uint_t *nelem, int *err)
552 {
553 	return (prop_getval(node, pgname, pname, (void *)val,
554 	    TOPO_TYPE_INT32_ARRAY, nelem, err));
555 }
556 
557 int
558 topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname,
559     uint32_t **val, uint_t *nelem, int *err)
560 {
561 	return (prop_getval(node, pgname, pname, (void *)val,
562 	    TOPO_TYPE_UINT32_ARRAY, nelem, err));
563 }
564 
565 int
566 topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname,
567     int64_t **val, uint_t *nelem, int *err)
568 {
569 	return (prop_getval(node, pgname, pname, (void *)val,
570 	    TOPO_TYPE_INT64_ARRAY, nelem, err));
571 }
572 
573 int
574 topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname,
575     uint64_t **val, uint_t *nelem, int *err)
576 {
577 	return (prop_getval(node, pgname, pname, (void *)val,
578 	    TOPO_TYPE_UINT64_ARRAY, nelem, err));
579 }
580 
581 int
582 topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname,
583     char ***val, uint_t *nelem, int *err)
584 {
585 	return (prop_getval(node, pgname, pname, (void *)val,
586 	    TOPO_TYPE_STRING_ARRAY, nelem, err));
587 }
588 
589 int
590 topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname,
591     nvlist_t ***val, uint_t *nelem, int *err)
592 {
593 	return (prop_getval(node, pgname, pname, (void *)val,
594 	    TOPO_TYPE_FMRI_ARRAY, nelem, err));
595 }
596 
597 static int
598 set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
599 {
600 	topo_hdl_t *thp = node->tn_hdl;
601 	topo_propval_t *pv;
602 
603 	if (pvl != NULL) {
604 		pv = pvl->tp_pval;
605 		if (pv != NULL) {
606 			if (pv->tp_name != NULL)
607 				topo_hdl_strfree(thp, pv->tp_name);
608 			if (pv->tp_val != NULL)
609 				nvlist_free(pv->tp_val);
610 			topo_hdl_free(thp, pv, sizeof (topo_propval_t));
611 		}
612 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
613 	}
614 
615 	topo_node_unlock(node);
616 	*errp = err;
617 
618 	return (-1);
619 }
620 
621 static int
622 topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
623     topo_type_t type, int flag, void *val, int nelems, int *err)
624 {
625 	int ret, new_prop = 0;
626 	topo_hdl_t *thp = node->tn_hdl;
627 	topo_pgroup_t *pg;
628 	topo_propval_t *pv;
629 	topo_proplist_t *pvl;
630 
631 	topo_node_lock(node);
632 	if ((pg = pgroup_get(node, pgname)) == NULL)
633 		return (set_seterror(node, NULL, err, ETOPO_PROP_NOENT));
634 
635 	/*
636 	 * Replace existing prop value with new one
637 	 */
638 	if ((pv = propval_get(pg, pname)) != NULL) {
639 		if (pv->tp_type != type)
640 			return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
641 		else if (pv->tp_flag == TOPO_PROP_IMMUTABLE)
642 			return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
643 		nvlist_free(pv->tp_val);
644 		pv->tp_val = NULL;
645 	} else {
646 		/*
647 		 * Property values may be a shared resources among
648 		 * different nodes.  We will allocate resources
649 		 * on a per-handle basis.
650 		 */
651 		if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
652 		    == NULL)
653 			return (set_seterror(node, NULL, err, ETOPO_NOMEM));
654 
655 		if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
656 		    == NULL)
657 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
658 		pvl->tp_pval = pv;
659 
660 		if ((pv->tp_name = topo_hdl_strdup(thp, pname))
661 		    == NULL)
662 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
663 		pv->tp_flag = flag;
664 		pv->tp_type = type;
665 		pv->tp_hdl = thp;
666 		topo_prop_hold(pv);
667 		new_prop++;
668 	}
669 
670 	if (topo_hdl_nvalloc(thp, &pv->tp_val, NV_UNIQUE_NAME) < 0)
671 		return (set_seterror(node, pvl, err, ETOPO_PROP_NVL));
672 
673 	ret = 0;
674 	switch (type) {
675 		case TOPO_TYPE_INT32:
676 			ret = nvlist_add_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
677 			    *(int32_t *)val);
678 			break;
679 		case TOPO_TYPE_UINT32:
680 			ret = nvlist_add_uint32(pv->tp_val, TOPO_PROP_VAL_VAL,
681 			    *(uint32_t *)val);
682 			break;
683 		case TOPO_TYPE_INT64:
684 			ret = nvlist_add_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
685 			    *(int64_t *)val);
686 			break;
687 		case TOPO_TYPE_UINT64:
688 			ret = nvlist_add_uint64(pv->tp_val, TOPO_PROP_VAL_VAL,
689 			    *(uint64_t *)val);
690 			break;
691 		case TOPO_TYPE_STRING:
692 			ret = nvlist_add_string(pv->tp_val, TOPO_PROP_VAL_VAL,
693 			    (char *)val);
694 			break;
695 		case TOPO_TYPE_FMRI:
696 			ret = nvlist_add_nvlist(pv->tp_val, TOPO_PROP_VAL_VAL,
697 			    (nvlist_t *)val);
698 			break;
699 		case TOPO_TYPE_INT32_ARRAY:
700 			ret = nvlist_add_int32_array(pv->tp_val,
701 			    TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
702 			break;
703 		case TOPO_TYPE_UINT32_ARRAY:
704 			ret = nvlist_add_uint32_array(pv->tp_val,
705 			    TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
706 			break;
707 		case TOPO_TYPE_INT64_ARRAY:
708 			ret = nvlist_add_int64_array(pv->tp_val,
709 			    TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
710 			break;
711 		case TOPO_TYPE_UINT64_ARRAY:
712 			ret = nvlist_add_uint64_array(pv->tp_val,
713 			    TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
714 			break;
715 		case TOPO_TYPE_STRING_ARRAY:
716 			ret = nvlist_add_string_array(pv->tp_val,
717 			    TOPO_PROP_VAL_VAL, (char **)val, nelems);
718 			break;
719 		case TOPO_TYPE_FMRI_ARRAY:
720 			ret = nvlist_add_nvlist_array(pv->tp_val,
721 			    TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
722 			break;
723 		default:
724 			return (set_seterror(node, pvl, err, ETOPO_PROP_TYPE));
725 	}
726 
727 	if (ret != 0) {
728 		if (ret == ENOMEM)
729 			return (set_seterror(node, pvl, err, ETOPO_NOMEM));
730 		else
731 			return (set_seterror(node, pvl, err, ETOPO_PROP_NVL));
732 	}
733 
734 	if (new_prop > 0)
735 		topo_list_append(&pg->tpg_pvals, pvl);
736 
737 	topo_node_unlock(node);
738 
739 	return (0);
740 }
741 
742 int
743 topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
744     int flag, int32_t val, int *err)
745 {
746 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
747 	    &val, 1, err));
748 }
749 
750 int
751 topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
752     int flag, uint32_t val, int *err)
753 {
754 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
755 	    &val, 1, err));
756 }
757 
758 int
759 topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
760     int flag, int64_t val, int *err)
761 {
762 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
763 	    &val, 1, err));
764 }
765 
766 int
767 topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
768     int flag, uint64_t val, int *err)
769 {
770 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
771 	    &val, 1, err));
772 }
773 
774 int
775 topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
776     int flag, const char *val, int *err)
777 {
778 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
779 	    (void *)val, 1, err));
780 }
781 
782 int
783 topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
784     int flag, const nvlist_t *fmri, int *err)
785 {
786 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
787 	    (void *)fmri, 1, err));
788 }
789 
790 int
791 topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname,
792     int flag, int32_t *val, uint_t nelems, int *err)
793 {
794 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag,
795 	    val, nelems, err));
796 }
797 
798 int
799 topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname,
800     int flag, uint32_t *val, uint_t nelems, int *err)
801 {
802 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag,
803 	    val, nelems, err));
804 }
805 
806 int
807 topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname,
808     int flag, int64_t *val, uint_t nelems, int *err)
809 {
810 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag,
811 	    val, nelems, err));
812 }
813 
814 int
815 topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname,
816     int flag, uint64_t *val, uint_t nelems, int *err)
817 {
818 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag,
819 	    val, nelems, err));
820 }
821 
822 int
823 topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname,
824     int flag, const char **val, uint_t nelems, int *err)
825 {
826 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag,
827 	    (void *)val, nelems, err));
828 }
829 
830 int
831 topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname,
832     int flag, const nvlist_t **fmri, uint_t nelems, int *err)
833 {
834 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag,
835 	    (void *)fmri, nelems, err));
836 }
837 
838 static int
839 inherit_seterror(tnode_t *node, int *errp, int err)
840 {
841 	topo_node_unlock(node);
842 	topo_node_unlock(node->tn_parent);
843 
844 	*errp = err;
845 
846 	return (-1);
847 }
848 
849 int
850 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
851 {
852 	topo_hdl_t *thp = node->tn_hdl;
853 	tnode_t *pnode = node->tn_parent;
854 	topo_pgroup_t *pg;
855 	topo_propval_t *pv;
856 	topo_proplist_t *pvl;
857 
858 	topo_node_lock(pnode);
859 	topo_node_lock(node);
860 	/*
861 	 * Check for an existing property group and prop val
862 	 */
863 	if ((pg = pgroup_get(pnode, pgname)) == NULL)
864 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
865 
866 	if ((pv = propval_get(pg, name)) == NULL)
867 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
868 
869 	/*
870 	 * Can this propval be inherited?
871 	 */
872 	if (pv->tp_flag != TOPO_PROP_IMMUTABLE)
873 		return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
874 
875 	/*
876 	 * Property group should already exist: bump the ref count for this
877 	 * propval and add it to the node's property group
878 	 */
879 	if ((pg = pgroup_get(node, pgname)) == NULL)
880 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
881 
882 	if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
883 	    == NULL)
884 		return (inherit_seterror(node, err, ETOPO_NOMEM));
885 
886 	topo_prop_hold(pv);
887 	pvl->tp_pval = pv;
888 	topo_list_append(&pg->tpg_pvals, pvl);
889 
890 	topo_node_unlock(node);
891 	topo_node_unlock(pnode);
892 
893 	return (0);
894 }
895 
896 topo_pgroup_info_t *
897 topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
898 {
899 	topo_hdl_t *thp = node->tn_hdl;
900 	topo_pgroup_t *pg;
901 	topo_ipgroup_info_t *pip;
902 	topo_pgroup_info_t *info;
903 
904 	topo_node_lock(node);
905 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
906 	    pg = topo_list_next(pg)) {
907 		if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
908 			if ((info = topo_hdl_alloc(thp,
909 			    sizeof (topo_pgroup_info_t))) == NULL)
910 				return (NULL);
911 
912 			pip = pg->tpg_info;
913 			if ((info->tpi_name =
914 				topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
915 				*err = ETOPO_PROP_NOMEM;
916 				topo_hdl_free(thp, info,
917 				    sizeof (topo_pgroup_info_t));
918 				topo_node_unlock(node);
919 				return (NULL);
920 			}
921 			info->tpi_namestab = pip->tpi_namestab;
922 			info->tpi_datastab = pip->tpi_datastab;
923 			info->tpi_version = pip->tpi_version;
924 			topo_node_unlock(node);
925 			return (info);
926 		}
927 	}
928 
929 	*err = ETOPO_PROP_NOENT;
930 	topo_node_unlock(node);
931 	return (NULL);
932 }
933 
934 static int
935 pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
936     int *err)
937 {
938 	topo_hdl_t *thp = node->tn_hdl;
939 
940 	if (pip != NULL) {
941 		if (pip->tpi_name != NULL)
942 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
943 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
944 	}
945 
946 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
947 	*err = ETOPO_NOMEM;
948 
949 	topo_node_unlock(node);
950 
951 	return (-1);
952 }
953 
954 int
955 topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err)
956 {
957 	topo_pgroup_t *pg;
958 	topo_ipgroup_info_t *pip;
959 	topo_hdl_t *thp = node->tn_hdl;
960 
961 	*err = 0;
962 
963 	topo_node_lock(node);
964 	/*
965 	 * Check for an existing pgroup
966 	 */
967 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
968 	    pg = topo_list_next(pg)) {
969 		if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) {
970 			*err = ETOPO_PROP_DEFD;
971 			topo_node_unlock(node);
972 			return (-1);
973 		}
974 	}
975 
976 	if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) {
977 		*err = ETOPO_NOMEM;
978 		topo_node_unlock(node);
979 		return (-1);
980 	}
981 
982 	if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t)))
983 	    == NULL)
984 		return (pgroup_seterr(node, pg, pip, err));
985 
986 	if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name))
987 	    == NULL)
988 		return (pgroup_seterr(node, pg, pip, err));
989 
990 	pip->tpi_namestab = pinfo->tpi_namestab;
991 	pip->tpi_datastab = pinfo->tpi_datastab;
992 	pip->tpi_version = pinfo->tpi_version;
993 
994 	pg->tpg_info = pip;
995 
996 	topo_list_append(&node->tn_pgroups, pg);
997 	topo_node_unlock(node);
998 
999 	return (0);
1000 }
1001 
1002 void
1003 topo_pgroup_destroy(tnode_t *node, const char *pname)
1004 {
1005 	topo_hdl_t *thp = node->tn_hdl;
1006 	topo_pgroup_t *pg;
1007 	topo_proplist_t *pvl;
1008 	topo_ipgroup_info_t *pip;
1009 
1010 	topo_node_lock(node);
1011 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1012 	    pg = topo_list_next(pg)) {
1013 		if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
1014 			break;
1015 		}
1016 	}
1017 
1018 	if (pg == NULL) {
1019 		topo_node_unlock(node);
1020 		return;
1021 	}
1022 
1023 	while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
1024 		topo_list_delete(&pg->tpg_pvals, pvl);
1025 		topo_prop_rele(pvl->tp_pval);
1026 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1027 	}
1028 
1029 	topo_list_delete(&node->tn_pgroups, pg);
1030 	topo_node_unlock(node);
1031 
1032 	pip = pg->tpg_info;
1033 	if (pip != NULL) {
1034 		if (pip->tpi_name != NULL)
1035 			topo_hdl_strfree(thp, (char *)pip->tpi_name);
1036 		topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
1037 	}
1038 
1039 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1040 }
1041 
1042 void
1043 topo_pgroup_destroy_all(tnode_t *node)
1044 {
1045 	topo_hdl_t *thp = node->tn_hdl;
1046 	topo_pgroup_t *pg;
1047 	topo_proplist_t *pvl;
1048 	topo_ipgroup_info_t *pip;
1049 
1050 	topo_node_lock(node);
1051 	while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
1052 		while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
1053 			topo_list_delete(&pg->tpg_pvals, pvl);
1054 			topo_prop_rele(pvl->tp_pval);
1055 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1056 		}
1057 
1058 		topo_list_delete(&node->tn_pgroups, pg);
1059 
1060 		pip = pg->tpg_info;
1061 		if (pip != NULL) {
1062 			if (pip->tpi_name != NULL)
1063 				topo_hdl_strfree(thp, (char *)pip->tpi_name);
1064 			topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
1065 		}
1066 
1067 		topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1068 	}
1069 	topo_node_unlock(node);
1070 }
1071 static void
1072 topo_propval_destroy(topo_propval_t *pv)
1073 {
1074 	topo_hdl_t *thp = pv->tp_hdl;
1075 
1076 	if (pv->tp_name != NULL)
1077 		topo_hdl_strfree(thp, pv->tp_name);
1078 
1079 	if (pv->tp_val != NULL)
1080 		nvlist_free(pv->tp_val);
1081 
1082 	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
1083 }
1084 
1085 void
1086 topo_prop_hold(topo_propval_t *pv)
1087 {
1088 	pv->tp_refs++;
1089 }
1090 
1091 void
1092 topo_prop_rele(topo_propval_t *pv)
1093 {
1094 	pv->tp_refs--;
1095 
1096 	assert(pv->tp_refs >= 0);
1097 
1098 	if (pv->tp_refs == 0)
1099 		topo_propval_destroy(pv);
1100 }
1101