xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_prop.c (revision 60405de4d8688d96dd05157c28db3ade5c9bc234)
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_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)
88 {
89 	switch (pv->tp_type) {
90 		case TOPO_TYPE_INT32:
91 			return (nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
92 			    pv->tp_u.tp_int32));
93 		case TOPO_TYPE_UINT32:
94 			return (nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
95 			    pv->tp_u.tp_uint32));
96 		case TOPO_TYPE_INT64:
97 			return (nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
98 			    pv->tp_u.tp_int64));
99 		case TOPO_TYPE_UINT64:
100 			return (nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
101 			    pv->tp_u.tp_uint64));
102 		case TOPO_TYPE_STRING:
103 			return (nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
104 			    pv->tp_u.tp_string));
105 		case TOPO_TYPE_FMRI:
106 			return (nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
107 			    pv->tp_u.tp_fmri));
108 		default:
109 			return (ETOPO_PROP_TYPE);
110 	}
111 }
112 
113 nvlist_t *
114 get_all_seterror(topo_hdl_t *thp, nvlist_t *nvl, int err)
115 {
116 	if (nvl != NULL)
117 		nvlist_free(nvl);
118 
119 	(void) topo_hdl_seterrno(thp, err);
120 
121 	return (NULL);
122 }
123 
124 nvlist_t *
125 topo_prop_get_all(topo_hdl_t *thp, tnode_t *node)
126 {
127 	int err;
128 	nvlist_t *nvl, *pgnvl, *pvnvl;
129 	topo_pgroup_t *pg;
130 	topo_propval_t *pv;
131 	topo_proplist_t *pvl;
132 
133 	if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
134 		return (get_all_seterror(thp, NULL, ETOPO_NOMEM));
135 	}
136 
137 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
138 	    pg = topo_list_next(pg)) {
139 		err = 0;
140 		if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
141 			return (get_all_seterror(thp, nvl, ETOPO_NOMEM));
142 
143 		if ((err = nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
144 		    pg->tpg_name)) != 0)
145 			return (get_all_seterror(thp, nvl, err));
146 
147 		for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
148 		    pvl = topo_list_next(pvl)) {
149 
150 			pv = pvl->tp_pval;
151 			if (topo_hdl_nvalloc(thp, &pvnvl, 0)
152 			    != 0) {
153 				nvlist_free(pgnvl);
154 				return (get_all_seterror(thp, nvl,
155 				    ETOPO_NOMEM));
156 			}
157 			if ((err = nvlist_add_string(pvnvl, TOPO_PROP_VAL_NAME,
158 			    pv->tp_name)) != 0) {
159 				nvlist_free(pgnvl);
160 				nvlist_free(pvnvl);
161 				return (get_all_seterror(thp, nvl, err));
162 			}
163 			if ((err = prop_val_add(pvnvl, pv)) != 0) {
164 				nvlist_free(pgnvl);
165 				nvlist_free(pvnvl);
166 				return (get_all_seterror(thp, nvl, err));
167 			}
168 			if ((err = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
169 			    pvnvl)) != 0) {
170 				nvlist_free(pgnvl);
171 				nvlist_free(pvnvl);
172 				return (get_all_seterror(thp, nvl, err));
173 			}
174 
175 			nvlist_free(pvnvl);
176 		}
177 		if ((err = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
178 		    != 0) {
179 			nvlist_free(pgnvl);
180 			return (get_all_seterror(thp, nvl, err));
181 		}
182 
183 		nvlist_free(pgnvl);
184 	}
185 
186 	return (nvl);
187 }
188 
189 static int
190 get_seterror(tnode_t *node, int *errp, int err)
191 {
192 	topo_node_unlock(node);
193 	*errp = err;
194 	return (-1);
195 }
196 
197 int
198 topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
199     int32_t *val, int *err)
200 {
201 	topo_propval_t *pv;
202 
203 	topo_node_lock(node);
204 	if ((pv = topo_prop_get(node, pgname, pname, err))
205 	    == NULL)
206 		return (get_seterror(node, err, *err));
207 
208 	if (pv->tp_type != TOPO_TYPE_INT32)
209 		return (get_seterror(node, err, ETOPO_PROP_TYPE));
210 
211 	*val = pv->tp_u.tp_int32;
212 
213 	topo_node_unlock(node);
214 
215 	return (0);
216 }
217 
218 int
219 topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
220     uint32_t *val, int *err)
221 {
222 	topo_propval_t *pv;
223 
224 	topo_node_lock(node);
225 	if ((pv = topo_prop_get(node, pgname, pname, err))
226 	    == NULL)
227 		return (get_seterror(node, err, *err));
228 
229 	if (pv->tp_type != TOPO_TYPE_UINT32)
230 		return (get_seterror(node, err, ETOPO_PROP_TYPE));
231 
232 	*val = pv->tp_u.tp_uint32;
233 
234 	topo_node_unlock(node);
235 
236 	return (0);
237 }
238 
239 int
240 topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
241     int64_t *val, int *err)
242 {
243 	topo_propval_t *pv;
244 
245 	topo_node_lock(node);
246 	if ((pv = topo_prop_get(node, pgname, pname, err))
247 	    == NULL)
248 		return (get_seterror(node, err, *err));
249 
250 	if (pv->tp_type != TOPO_TYPE_INT64)
251 		return (get_seterror(node, err, ETOPO_PROP_TYPE));
252 
253 	*val = pv->tp_u.tp_int64;
254 
255 	topo_node_unlock(node);
256 
257 	return (0);
258 }
259 
260 int
261 topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
262     uint64_t *val, int *err)
263 {
264 	topo_propval_t *pv;
265 
266 	topo_node_lock(node);
267 	if ((pv = topo_prop_get(node, pgname, pname, err))
268 	    == NULL)
269 		return (get_seterror(node, err, *err));
270 
271 	if (pv->tp_type != TOPO_TYPE_UINT64)
272 		return (get_seterror(node, err, ETOPO_PROP_TYPE));
273 
274 	*val = pv->tp_u.tp_int64;
275 
276 	topo_node_unlock(node);
277 
278 	return (0);
279 }
280 
281 int
282 topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
283     char **val, int *err)
284 {
285 	topo_propval_t *pv;
286 
287 	topo_node_lock(node);
288 	if ((pv = topo_prop_get(node, pgname, pname, err)) == NULL)
289 		return (get_seterror(node, err, *err));
290 
291 	if (pv->tp_type != TOPO_TYPE_STRING)
292 		return (get_seterror(node, err, ETOPO_PROP_TYPE));
293 
294 	if ((*val = topo_hdl_strdup(node->tn_hdl, pv->tp_u.tp_string))
295 	    == NULL)
296 		return (get_seterror(node, err, ETOPO_NOMEM));
297 
298 	topo_node_unlock(node);
299 
300 	return (0);
301 }
302 
303 int
304 topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
305     nvlist_t **val, int *err)
306 {
307 	topo_propval_t *pv;
308 
309 	topo_node_lock(node);
310 	if ((pv = topo_prop_get(node, pgname, pname, err)) == NULL)
311 		return (get_seterror(node, err, *err));
312 
313 	if (pv->tp_type != TOPO_TYPE_FMRI)
314 		return (get_seterror(node, err, ETOPO_PROP_TYPE));
315 
316 	if (topo_hdl_nvdup(node->tn_hdl, pv->tp_u.tp_fmri, val) < 0)
317 		return (get_seterror(node, err, ETOPO_NOMEM));
318 
319 	topo_node_unlock(node);
320 
321 	return (0);
322 }
323 
324 static void
325 topo_propval_strfree(topo_propval_t *pv)
326 {
327 	topo_hdl_strfree(pv->tp_hdl, pv->tp_u.tp_string);
328 }
329 
330 static void
331 topo_propval_nvlfree(topo_propval_t *pv)
332 {
333 	nvlist_free(pv->tp_u.tp_fmri);
334 }
335 
336 static int
337 set_seterror(tnode_t *node, int *errp, int err)
338 {
339 	topo_node_unlock(node);
340 
341 	*errp = err;
342 
343 	return (-1);
344 }
345 
346 static int
347 topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
348     topo_type_t type, int flag, void *val, int *err)
349 {
350 	topo_hdl_t *thp = node->tn_hdl;
351 	topo_pgroup_t *pg;
352 	topo_propval_t *pv;
353 	topo_proplist_t *pvl;
354 
355 	topo_node_lock(node);
356 	if ((pg = pgroup_get(node, pgname)) == NULL)
357 		return (set_seterror(node, err, ETOPO_PROP_NOENT));
358 
359 	if ((pv = propval_get(pg, pname)) != NULL) {
360 		if (pv->tp_type != type)
361 			return (set_seterror(node, err, ETOPO_PROP_TYPE));
362 		else if (pv->tp_flag == TOPO_PROP_SET_ONCE)
363 			return (set_seterror(node, err, ETOPO_PROP_DEFD));
364 	} else {
365 		/*
366 		 * Property values may be a shared resources among
367 		 * different nodes.  We will allocate resources
368 		 * on a per-handle basis.
369 		 */
370 		if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
371 		    == NULL)
372 			return (set_seterror(node, err, ETOPO_NOMEM));
373 
374 		if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
375 		    == NULL) {
376 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
377 			return (set_seterror(node, err, ETOPO_NOMEM));
378 		}
379 		if ((pv->tp_name = topo_hdl_strdup(thp, pname))
380 		    == NULL) {
381 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
382 			topo_hdl_free(thp, pv, sizeof (topo_propval_t));
383 			return (set_seterror(node, err, ETOPO_NOMEM));
384 		}
385 		pv->tp_flag = flag;
386 		pv->tp_type = type;
387 		pv->tp_hdl = thp;
388 		topo_prop_hold(pv);
389 		pvl->tp_pval = pv;
390 		topo_list_append(&pg->tpg_pvals, pvl);
391 
392 
393 	}
394 
395 	switch (type) {
396 		case TOPO_TYPE_INT32:
397 			pv->tp_u.tp_int32 = *(int32_t *)val;
398 			break;
399 		case TOPO_TYPE_UINT32:
400 			pv->tp_u.tp_uint32 = *(uint32_t *)val;
401 			break;
402 		case TOPO_TYPE_INT64:
403 			pv->tp_u.tp_int64 = *(int64_t *)val;
404 			break;
405 		case TOPO_TYPE_UINT64:
406 			pv->tp_u.tp_uint64 = *(uint64_t *)val;
407 			break;
408 		case TOPO_TYPE_STRING:
409 			pv->tp_u.tp_string = topo_hdl_strdup(thp, (char *)val);
410 			if (pv->tp_u.tp_string == NULL)
411 				return (set_seterror(node, err, ETOPO_NOMEM));
412 			pv->tp_free = topo_propval_strfree;
413 			break;
414 		case TOPO_TYPE_FMRI:
415 			if (topo_hdl_nvdup(thp,
416 			    (nvlist_t *)val, &pv->tp_u.tp_fmri) < 0)
417 				return (set_seterror(node, err, ETOPO_NOMEM));
418 			pv->tp_free = topo_propval_nvlfree;
419 			break;
420 		default:
421 			return (set_seterror(node, err, ETOPO_PROP_TYPE));
422 	}
423 
424 	topo_node_unlock(node);
425 
426 	return (0);
427 }
428 
429 int
430 topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
431     int flag, int32_t val, int *err)
432 {
433 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
434 	    &val, err));
435 }
436 
437 int
438 topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
439     int flag, uint32_t val, int *err)
440 {
441 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
442 	    &val, err));
443 }
444 
445 int
446 topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
447     int flag, int64_t val, int *err)
448 {
449 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
450 	    &val, err));
451 }
452 
453 int
454 topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
455     int flag, uint64_t val, int *err)
456 {
457 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
458 	    &val, err));
459 }
460 
461 int
462 topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
463     int flag, const char *val, int *err)
464 {
465 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
466 	    (void *)val, err));
467 }
468 
469 int
470 topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
471     int flag, const nvlist_t *fmri, int *err)
472 {
473 	return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
474 	    (void *)fmri, err));
475 }
476 
477 static int
478 inherit_seterror(tnode_t *node, int *errp, int err)
479 {
480 	topo_node_unlock(node);
481 	topo_node_unlock(node->tn_parent);
482 
483 	*errp = err;
484 
485 	return (-1);
486 }
487 
488 int
489 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
490 {
491 	topo_hdl_t *thp = node->tn_hdl;
492 	tnode_t *pnode = node->tn_parent;
493 	topo_pgroup_t *pg;
494 	topo_propval_t *pv;
495 	topo_proplist_t *pvl;
496 
497 	topo_node_lock(pnode);
498 	topo_node_lock(node);
499 	/*
500 	 * Check for an existing property group and prop val
501 	 */
502 	if ((pg = pgroup_get(pnode, pgname)) == NULL)
503 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
504 
505 	if ((pv = propval_get(pg, name)) == NULL)
506 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
507 
508 	/*
509 	 * Can this propval be inherited?
510 	 */
511 	if (pv->tp_flag != TOPO_PROP_SET_ONCE)
512 		return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
513 
514 	/*
515 	 * Property group should already exist: bump the ref count for this
516 	 * propval and add it to the node's property group
517 	 */
518 	if ((pg = pgroup_get(node, pgname)) == NULL)
519 		return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
520 
521 	if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
522 	    == NULL)
523 		return (inherit_seterror(node, err, ETOPO_NOMEM));
524 
525 	topo_prop_hold(pv);
526 	pvl->tp_pval = pv;
527 	topo_list_append(&pg->tpg_pvals, pvl);
528 
529 	topo_node_unlock(node);
530 	topo_node_unlock(pnode);
531 
532 	return (0);
533 }
534 
535 int
536 topo_prop_stability(tnode_t *node, const char *pgname, topo_stability_t *stab)
537 {
538 	topo_pgroup_t *pg;
539 
540 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
541 	    pg = topo_list_next(pg)) {
542 		if (strcmp(pgname, pg->tpg_name) == 0) {
543 			*stab = pg->tpg_stability;
544 			return (0);
545 		}
546 	}
547 
548 	return (-1);
549 }
550 
551 int
552 topo_pgroup_create(tnode_t *node, const char *pname, topo_stability_t stab,
553     int *err)
554 {
555 	topo_pgroup_t *pg;
556 
557 	*err = 0;
558 
559 	/*
560 	 * Check for an existing pgroup
561 	 */
562 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
563 	    pg = topo_list_next(pg)) {
564 		if (strcmp(pg->tpg_name, pname) == 0) {
565 			*err = ETOPO_PROP_DEFD;
566 			return (-1);
567 		}
568 	}
569 
570 	if ((pg = topo_hdl_zalloc(node->tn_hdl,
571 	    sizeof (topo_pgroup_t))) == NULL) {
572 		*err = ETOPO_NOMEM;
573 		return (-1);
574 	}
575 
576 	if ((pg->tpg_name = topo_hdl_strdup(node->tn_hdl, pname)) == NULL) {
577 		topo_hdl_free(node->tn_hdl, pg, sizeof (topo_pgroup_t));
578 		*err = ETOPO_NOMEM;
579 		return (-1);
580 	}
581 
582 	pg->tpg_stability = stab;
583 
584 	topo_list_append(&node->tn_pgroups, pg);
585 
586 	return (0);
587 }
588 
589 void
590 topo_pgroup_destroy(tnode_t *node, const char *pname)
591 {
592 	topo_hdl_t *thp = node->tn_hdl;
593 	topo_pgroup_t *pg;
594 	topo_proplist_t *pvl;
595 
596 	topo_node_lock(node);
597 	for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
598 	    pg = topo_list_next(pg)) {
599 		if (strcmp(pg->tpg_name, pname) == 0) {
600 			break;
601 		}
602 	}
603 
604 	if (pg == NULL) {
605 		topo_node_unlock(node);
606 		return;
607 	}
608 
609 	while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
610 		topo_list_delete(&pg->tpg_pvals, pvl);
611 		topo_prop_rele(pvl->tp_pval);
612 		topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
613 	}
614 
615 	topo_list_delete(&node->tn_pgroups, pg);
616 
617 	if (pg->tpg_name != NULL)
618 		topo_hdl_strfree(thp, pg->tpg_name);
619 	topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
620 
621 	topo_node_unlock(node);
622 }
623 
624 void
625 topo_pgroup_destroy_all(tnode_t *node)
626 {
627 	topo_hdl_t *thp = node->tn_hdl;
628 	topo_pgroup_t *pg;
629 	topo_proplist_t *pvl;
630 
631 	topo_node_lock(node);
632 	while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
633 		while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
634 			topo_list_delete(&pg->tpg_pvals, pvl);
635 			topo_prop_rele(pvl->tp_pval);
636 			topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
637 		}
638 
639 		topo_list_delete(&node->tn_pgroups, pg);
640 
641 		if (pg->tpg_name != NULL)
642 			topo_hdl_strfree(thp, pg->tpg_name);
643 		topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
644 	}
645 	topo_node_unlock(node);
646 }
647 static void
648 topo_propval_destroy(topo_propval_t *pv)
649 {
650 	topo_hdl_t *thp = pv->tp_hdl;
651 
652 	if (pv->tp_name != NULL)
653 		topo_hdl_strfree(thp, pv->tp_name);
654 
655 	if (pv->tp_free != NULL)
656 		pv->tp_free(pv);
657 
658 	topo_hdl_free(thp, pv, sizeof (topo_propval_t));
659 }
660 
661 void
662 topo_prop_hold(topo_propval_t *pv)
663 {
664 	pv->tp_refs++;
665 }
666 
667 void
668 topo_prop_rele(topo_propval_t *pv)
669 {
670 	pv->tp_refs--;
671 
672 	assert(pv->tp_refs >= 0);
673 
674 	if (pv->tp_refs == 0)
675 		topo_propval_destroy(pv);
676 }
677