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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright 2023 Oxide Computer Company
28 */
29
30 #include <strings.h>
31 #include <stdarg.h>
32 #include <assert.h>
33 #include <fm/libtopo.h>
34 #include <topo_prop.h>
35 #include <topo_string.h>
36 #include <topo_alloc.h>
37 #include <topo_error.h>
38 #include <topo_method.h>
39
40 /*
41 * Topology nodes are permitted to contain property information.
42 * Property information is organized according to property grouping.
43 * Each property group defines a name, a stability level for that name,
44 * a stability level for all underlying property data (name, type, values),
45 * a version for the property group definition and and a list of uniquely
46 * defined properties. Property group versions are incremented when one of
47 * the following changes occurs:
48 * - a property name changes
49 * - a property type changes
50 * - a property definition is removed from the group
51 * Compatible changes such as new property definitions in the group do
52 * not require version changes.
53 *
54 * Each property defines a unique (within the group) name, a type and
55 * a value. Properties may be statically defined as int32, uint32, int64,
56 * uint64, fmri, string or arrays of each type. Properties may also be
57 * dynamically exported via module registered methods. For example, a module
58 * may register a method to export an ASRU property that is dynamically
59 * contructed when a call to topo_node_fmri() is invoked for a particular
60 * topology node.
61 *
62 * Static properties are persistently attached to topology nodes during
63 * enumeration by an enumeration module or as part of XML statements in a
64 * toplogy map file using the topo_prop_set* family of routines. Similarly,
65 * property methods are registered during enumeration or as part of
66 * statements in topololgy map files. Set-up of property methods is performed
67 * by calling topo_prop_method_register().
68 *
69 * All properties, whether statically persisted in a snapshot or dynamically
70 * obtained, may be read via the topo_prop_get* family of interfaces.
71 * Callers wishing to receive all property groups and properties for a given
72 * node may use topo_prop_getall(). This routine returns a nested nvlist
73 * of all groupings and property (name, type, value) sets. Groupings
74 * are defined by TOPO_PROP_GROUP (name, data stability, name stability and
75 * version) and a nested nvlist of properties (TOPO_PROP_VAL). Each property
76 * value is defined by its name, type and value.
77 */
78 static void topo_propval_destroy(topo_propval_t *);
79
80 static topo_pgroup_t *
pgroup_get(tnode_t * node,const char * pgname)81 pgroup_get(tnode_t *node, const char *pgname)
82 {
83 topo_pgroup_t *pg;
84 /*
85 * Check for an existing pgroup
86 */
87 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
88 pg = topo_list_next(pg)) {
89 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
90 return (pg);
91 }
92 }
93
94 return (NULL);
95 }
96
97 static topo_propval_t *
propval_get(topo_pgroup_t * pg,const char * pname)98 propval_get(topo_pgroup_t *pg, const char *pname)
99 {
100 topo_proplist_t *pvl;
101
102 if (pg == NULL)
103 return (NULL);
104
105 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
106 pvl = topo_list_next(pvl)) {
107 if (strcmp(pvl->tp_pval->tp_name, pname) == 0)
108 return (pvl->tp_pval);
109 }
110
111 return (NULL);
112 }
113
114 static int
method_geterror(nvlist_t * nvl,int err,int * errp)115 method_geterror(nvlist_t *nvl, int err, int *errp)
116 {
117 nvlist_free(nvl);
118
119 *errp = err;
120
121 return (-1);
122 }
123
124 static int
prop_method_get(tnode_t * node,topo_propval_t * pv,topo_propmethod_t * pm,nvlist_t * pargs,int * err)125 prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm,
126 nvlist_t *pargs, int *err)
127 {
128 int ret;
129 nvlist_t *args, *nvl;
130 char *name;
131 topo_type_t type;
132
133 if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 ||
134 nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0)
135 return (method_geterror(NULL, ETOPO_PROP_NVL, err));
136
137 if (pargs != NULL)
138 if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0)
139 return (method_geterror(args, ETOPO_PROP_NVL, err));
140
141 /*
142 * Now, get the latest value
143 *
144 * Grab a reference to the property and then unlock the node. This will
145 * allow property methods to safely re-enter the prop_get codepath,
146 * making it possible for property methods to access other property
147 * values on the same node w\o causing a deadlock.
148 */
149 topo_prop_hold(pv);
150 topo_node_unlock(node);
151 if (topo_method_call(node, pm->tpm_name, pm->tpm_version,
152 args, &nvl, err) < 0) {
153 topo_node_lock(node);
154 topo_prop_rele(pv);
155 return (method_geterror(args, *err, err));
156 }
157 topo_node_lock(node);
158 topo_prop_rele(pv);
159
160 nvlist_free(args);
161
162 /* Verify the property contents */
163 ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name);
164 if (ret != 0 || strcmp(name, pv->tp_name) != 0)
165 return (method_geterror(nvl, ETOPO_PROP_NAME, err));
166
167 ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type);
168 if (ret != 0 || type != pv->tp_type)
169 return (method_geterror(nvl, ETOPO_PROP_TYPE, err));
170
171 /* Release the last value and re-assign to the new value */
172 nvlist_free(pv->tp_val);
173 pv->tp_val = nvl;
174
175 return (0);
176 }
177
178 static topo_propval_t *
prop_get(tnode_t * node,const char * pgname,const char * pname,nvlist_t * pargs,int * err)179 prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs,
180 int *err)
181 {
182 topo_propval_t *pv = NULL;
183
184 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
185 *err = ETOPO_PROP_NOENT;
186 return (NULL);
187 }
188
189 if (pv->tp_flag & TOPO_PROP_NONVOLATILE && pv->tp_val != NULL)
190 return (pv);
191
192 if (pv->tp_method != NULL) {
193 if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0)
194 return (NULL);
195 }
196
197 return (pv);
198 }
199
200 static int
get_properror(tnode_t * node,int * errp,int err)201 get_properror(tnode_t *node, int *errp, int err)
202 {
203 topo_node_unlock(node);
204 *errp = err;
205 return (-1);
206 }
207
208 static int
prop_getval(tnode_t * node,const char * pgname,const char * pname,void * val,topo_type_t type,uint_t * nelems,int * err)209 prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val,
210 topo_type_t type, uint_t *nelems, int *err)
211 {
212 int i, j, ret = 0;
213 topo_hdl_t *thp = node->tn_hdl;
214 topo_propval_t *pv;
215
216 topo_node_lock(node);
217 if ((pv = prop_get(node, pgname, pname, NULL, err))
218 == NULL)
219 return (get_properror(node, err, *err));
220
221 if (pv->tp_type != type)
222 return (get_properror(node, err, ETOPO_PROP_TYPE));
223
224 switch (type) {
225 case TOPO_TYPE_INT32:
226 ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL,
227 (int32_t *)val);
228 break;
229 case TOPO_TYPE_UINT32:
230 ret = nvlist_lookup_uint32(pv->tp_val,
231 TOPO_PROP_VAL_VAL, (uint32_t *)val);
232 break;
233 case TOPO_TYPE_INT64:
234 ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL,
235 (int64_t *)val);
236 break;
237 case TOPO_TYPE_UINT64:
238 ret = nvlist_lookup_uint64(pv->tp_val,
239 TOPO_PROP_VAL_VAL, (uint64_t *)val);
240 break;
241 case TOPO_TYPE_DOUBLE:
242 ret = nvlist_lookup_double(pv->tp_val,
243 TOPO_PROP_VAL_VAL, (double *)val);
244 break;
245 case TOPO_TYPE_STRING: {
246 char *str;
247
248 ret = nvlist_lookup_string(pv->tp_val,
249 TOPO_PROP_VAL_VAL, &str);
250 if (ret == 0) {
251 char *s2;
252 if ((s2 = topo_hdl_strdup(thp, str)) == NULL)
253 ret = -1;
254 else
255 *(char **)val = s2;
256 }
257 break;
258 }
259 case TOPO_TYPE_FMRI: {
260 nvlist_t *nvl;
261
262 ret = nvlist_lookup_nvlist(pv->tp_val,
263 TOPO_PROP_VAL_VAL, &nvl);
264 if (ret == 0)
265 ret = topo_hdl_nvdup(thp, nvl,
266 (nvlist_t **)val);
267 break;
268 }
269 case TOPO_TYPE_INT32_ARRAY: {
270 int32_t *a1, *a2;
271
272 if ((ret = nvlist_lookup_int32_array(pv->tp_val,
273 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
274 break;
275 if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) *
276 *nelems)) == NULL) {
277 ret = ETOPO_NOMEM;
278 break;
279 }
280 for (i = 0; i < *nelems; ++i)
281 a1[i] = a2[i];
282 *(int32_t **)val = a1;
283 break;
284 }
285 case TOPO_TYPE_UINT32_ARRAY: {
286 uint32_t *a1, *a2;
287
288 if ((ret = nvlist_lookup_uint32_array(pv->tp_val,
289 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
290 break;
291 if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) *
292 *nelems)) == NULL) {
293 ret = ETOPO_NOMEM;
294 break;
295 }
296 for (i = 0; i < *nelems; ++i)
297 a1[i] = a2[i];
298 *(uint32_t **)val = a1;
299 break;
300 }
301 case TOPO_TYPE_INT64_ARRAY: {
302 int64_t *a1, *a2;
303
304 if ((ret = nvlist_lookup_int64_array(pv->tp_val,
305 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
306 break;
307 if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) *
308 *nelems)) == NULL) {
309 ret = ETOPO_NOMEM;
310 break;
311 }
312 for (i = 0; i < *nelems; ++i)
313 a1[i] = a2[i];
314 *(int64_t **)val = a1;
315 break;
316 }
317 case TOPO_TYPE_UINT64_ARRAY: {
318 uint64_t *a1, *a2;
319
320 if ((ret = nvlist_lookup_uint64_array(pv->tp_val,
321 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
322 break;
323 if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) *
324 *nelems)) == NULL) {
325 ret = ETOPO_NOMEM;
326 break;
327 }
328 for (i = 0; i < *nelems; ++i)
329 a1[i] = a2[i];
330 *(uint64_t **)val = a1;
331 break;
332 }
333 case TOPO_TYPE_STRING_ARRAY: {
334 char **a1, **a2;
335
336 if ((ret = nvlist_lookup_string_array(pv->tp_val,
337 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
338 break;
339 if ((a1 = topo_hdl_alloc(thp, sizeof (char *) *
340 *nelems)) == NULL) {
341 ret = ETOPO_NOMEM;
342 break;
343 }
344 for (i = 0; i < *nelems; ++i) {
345 if ((a1[i] = topo_hdl_strdup(thp, a2[i]))
346 == NULL) {
347 for (j = 0; j < i; ++j)
348 topo_hdl_free(thp, a1[j],
349 sizeof (char *));
350 topo_hdl_free(thp, a1,
351 sizeof (char *) * *nelems);
352 break;
353 }
354 }
355 *(char ***)val = a1;
356 break;
357 }
358 case TOPO_TYPE_FMRI_ARRAY: {
359 nvlist_t **a1, **a2;
360
361 if ((ret = nvlist_lookup_nvlist_array(pv->tp_val,
362 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0)
363 break;
364 if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) *
365 *nelems)) == NULL) {
366 ret = ETOPO_NOMEM;
367 break;
368 }
369 for (i = 0; i < *nelems; ++i) {
370 if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) {
371 for (j = 0; j < i; ++j)
372 nvlist_free(a1[j]);
373 topo_hdl_free(thp, a1,
374 sizeof (nvlist_t *) * *nelems);
375 break;
376 }
377 }
378 *(nvlist_t ***)val = a1;
379 break;
380 }
381 default:
382 ret = ETOPO_PROP_NOENT;
383 }
384
385 if (ret != 0) {
386 if (ret == ENOENT)
387 return (get_properror(node, err, ETOPO_PROP_NOENT));
388 else if (ret < ETOPO_UNKNOWN)
389 return (get_properror(node, err, ETOPO_PROP_NVL));
390 else
391 return (get_properror(node, err, ret));
392 }
393
394 topo_node_unlock(node);
395 return (0);
396 }
397
398 int
topo_prop_get_int32(tnode_t * node,const char * pgname,const char * pname,int32_t * val,int * err)399 topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname,
400 int32_t *val, int *err)
401 {
402 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32,
403 NULL, err));
404 }
405
406 int
topo_prop_get_uint32(tnode_t * node,const char * pgname,const char * pname,uint32_t * val,int * err)407 topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname,
408 uint32_t *val, int *err)
409 {
410 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32,
411 NULL, err));
412 }
413
414 int
topo_prop_get_int64(tnode_t * node,const char * pgname,const char * pname,int64_t * val,int * err)415 topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname,
416 int64_t *val, int *err)
417 {
418 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64,
419 NULL, err));
420 }
421
422 int
topo_prop_get_uint64(tnode_t * node,const char * pgname,const char * pname,uint64_t * val,int * err)423 topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname,
424 uint64_t *val, int *err)
425 {
426 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64,
427 NULL, err));
428 }
429
430 int
topo_prop_get_double(tnode_t * node,const char * pgname,const char * pname,double * val,int * err)431 topo_prop_get_double(tnode_t *node, const char *pgname, const char *pname,
432 double *val, int *err)
433 {
434 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_DOUBLE,
435 NULL, err));
436 }
437
438 int
topo_prop_get_string(tnode_t * node,const char * pgname,const char * pname,char ** val,int * err)439 topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname,
440 char **val, int *err)
441 {
442 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING,
443 NULL, err));
444 }
445
446 int
topo_prop_get_fmri(tnode_t * node,const char * pgname,const char * pname,nvlist_t ** val,int * err)447 topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname,
448 nvlist_t **val, int *err)
449 {
450 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI,
451 NULL, err));
452 }
453
454 int
topo_prop_get_int32_array(tnode_t * node,const char * pgname,const char * pname,int32_t ** val,uint_t * nelem,int * err)455 topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname,
456 int32_t **val, uint_t *nelem, int *err)
457 {
458 return (prop_getval(node, pgname, pname, (void *)val,
459 TOPO_TYPE_INT32_ARRAY, nelem, err));
460 }
461
462 int
topo_prop_get_uint32_array(tnode_t * node,const char * pgname,const char * pname,uint32_t ** val,uint_t * nelem,int * err)463 topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname,
464 uint32_t **val, uint_t *nelem, int *err)
465 {
466 return (prop_getval(node, pgname, pname, (void *)val,
467 TOPO_TYPE_UINT32_ARRAY, nelem, err));
468 }
469
470 int
topo_prop_get_int64_array(tnode_t * node,const char * pgname,const char * pname,int64_t ** val,uint_t * nelem,int * err)471 topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname,
472 int64_t **val, uint_t *nelem, int *err)
473 {
474 return (prop_getval(node, pgname, pname, (void *)val,
475 TOPO_TYPE_INT64_ARRAY, nelem, err));
476 }
477
478 int
topo_prop_get_uint64_array(tnode_t * node,const char * pgname,const char * pname,uint64_t ** val,uint_t * nelem,int * err)479 topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname,
480 uint64_t **val, uint_t *nelem, int *err)
481 {
482 return (prop_getval(node, pgname, pname, (void *)val,
483 TOPO_TYPE_UINT64_ARRAY, nelem, err));
484 }
485
486 int
topo_prop_get_string_array(tnode_t * node,const char * pgname,const char * pname,char *** val,uint_t * nelem,int * err)487 topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname,
488 char ***val, uint_t *nelem, int *err)
489 {
490 return (prop_getval(node, pgname, pname, (void *)val,
491 TOPO_TYPE_STRING_ARRAY, nelem, err));
492 }
493
494 int
topo_prop_get_fmri_array(tnode_t * node,const char * pgname,const char * pname,nvlist_t *** val,uint_t * nelem,int * err)495 topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname,
496 nvlist_t ***val, uint_t *nelem, int *err)
497 {
498 return (prop_getval(node, pgname, pname, (void *)val,
499 TOPO_TYPE_FMRI_ARRAY, nelem, err));
500 }
501
502 static topo_propval_t *
set_seterror(tnode_t * node,topo_proplist_t * pvl,int * errp,int err)503 set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err)
504 {
505 topo_hdl_t *thp = node->tn_hdl;
506 topo_propval_t *pv;
507
508 if (pvl != NULL) {
509 pv = pvl->tp_pval;
510 topo_propval_destroy(pv);
511 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
512 }
513
514 topo_node_unlock(node);
515 *errp = err;
516
517 return (NULL);
518 }
519
520 static topo_propval_t *
prop_create(tnode_t * node,const char * pgname,const char * pname,topo_type_t type,int flag,int * err)521 prop_create(tnode_t *node, const char *pgname, const char *pname,
522 topo_type_t type, int flag, int *err)
523 {
524 topo_hdl_t *thp = node->tn_hdl;
525 topo_pgroup_t *pg;
526 topo_propval_t *pv;
527 topo_proplist_t *pvl;
528
529 /*
530 * Replace existing prop value with new one
531 */
532 if ((pg = pgroup_get(node, pgname)) == NULL) {
533 topo_node_unlock(node);
534 *err = ETOPO_PROP_NOENT;
535 return (NULL);
536 }
537
538 if ((pv = propval_get(pg, pname)) != NULL) {
539 if (pv->tp_type != type)
540 return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE));
541 else if (! (pv->tp_flag & TOPO_PROP_MUTABLE))
542 return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD));
543
544 nvlist_free(pv->tp_val);
545 pv->tp_val = NULL;
546 } else {
547 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
548 == NULL)
549 return (set_seterror(node, NULL, err, ETOPO_NOMEM));
550
551 if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t)))
552 == NULL)
553 return (set_seterror(node, pvl, err, ETOPO_NOMEM));
554
555 pv->tp_hdl = thp;
556 pvl->tp_pval = pv;
557
558 if ((pv->tp_name = topo_hdl_strdup(thp, pname))
559 == NULL)
560 return (set_seterror(node, pvl, err, ETOPO_NOMEM));
561 pv->tp_flag = flag;
562 pv->tp_type = type;
563 topo_prop_hold(pv);
564 topo_list_append(&pg->tpg_pvals, pvl);
565 }
566
567 return (pv);
568 }
569
570 static int
topo_prop_set(tnode_t * node,const char * pgname,const char * pname,topo_type_t type,int flag,void * val,int nelems,int * err)571 topo_prop_set(tnode_t *node, const char *pgname, const char *pname,
572 topo_type_t type, int flag, void *val, int nelems, int *err)
573 {
574 int ret;
575 topo_hdl_t *thp = node->tn_hdl;
576 nvlist_t *nvl;
577
578 if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) {
579 *err = ETOPO_PROP_NVL;
580 return (-1);
581 }
582
583 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname);
584 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type);
585 switch (type) {
586 case TOPO_TYPE_INT32:
587 ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL,
588 *(int32_t *)val);
589 break;
590 case TOPO_TYPE_UINT32:
591 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL,
592 *(uint32_t *)val);
593 break;
594 case TOPO_TYPE_INT64:
595 ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL,
596 *(int64_t *)val);
597 break;
598 case TOPO_TYPE_UINT64:
599 ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL,
600 *(uint64_t *)val);
601 break;
602 case TOPO_TYPE_DOUBLE:
603 ret |= nvlist_add_double(nvl, TOPO_PROP_VAL_VAL,
604 *(double *)val);
605 break;
606 case TOPO_TYPE_STRING:
607 ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL,
608 (char *)val);
609 break;
610 case TOPO_TYPE_FMRI:
611 ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL,
612 (nvlist_t *)val);
613 break;
614 case TOPO_TYPE_INT32_ARRAY:
615 ret |= nvlist_add_int32_array(nvl,
616 TOPO_PROP_VAL_VAL, (int32_t *)val, nelems);
617 break;
618 case TOPO_TYPE_UINT32_ARRAY:
619 ret |= nvlist_add_uint32_array(nvl,
620 TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems);
621 break;
622 case TOPO_TYPE_INT64_ARRAY:
623 ret |= nvlist_add_int64_array(nvl,
624 TOPO_PROP_VAL_VAL, (int64_t *)val, nelems);
625 break;
626 case TOPO_TYPE_UINT64_ARRAY:
627 ret |= nvlist_add_uint64_array(nvl,
628 TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems);
629 break;
630 case TOPO_TYPE_STRING_ARRAY:
631 ret |= nvlist_add_string_array(nvl,
632 TOPO_PROP_VAL_VAL, (char **)val, nelems);
633 break;
634 case TOPO_TYPE_FMRI_ARRAY:
635 ret |= nvlist_add_nvlist_array(nvl,
636 TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems);
637 break;
638 default:
639 *err = ETOPO_PROP_TYPE;
640 return (-1);
641 }
642
643 if (ret != 0) {
644 nvlist_free(nvl);
645 if (ret == ENOMEM) {
646 *err = ETOPO_PROP_NOMEM;
647 return (-1);
648 } else {
649 *err = ETOPO_PROP_NVL;
650 return (-1);
651 }
652 }
653
654 if (topo_prop_setprop(node, pgname, nvl, flag, nvl, err) != 0) {
655 nvlist_free(nvl);
656 return (-1); /* err set */
657 }
658 nvlist_free(nvl);
659 return (ret);
660 }
661
662 int
topo_prop_set_int32(tnode_t * node,const char * pgname,const char * pname,int flag,int32_t val,int * err)663 topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname,
664 int flag, int32_t val, int *err)
665 {
666 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag,
667 &val, 1, err));
668 }
669
670 int
topo_prop_set_uint32(tnode_t * node,const char * pgname,const char * pname,int flag,uint32_t val,int * err)671 topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname,
672 int flag, uint32_t val, int *err)
673 {
674 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag,
675 &val, 1, err));
676 }
677
678 int
topo_prop_set_int64(tnode_t * node,const char * pgname,const char * pname,int flag,int64_t val,int * err)679 topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname,
680 int flag, int64_t val, int *err)
681 {
682 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag,
683 &val, 1, err));
684 }
685
686 int
topo_prop_set_uint64(tnode_t * node,const char * pgname,const char * pname,int flag,uint64_t val,int * err)687 topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname,
688 int flag, uint64_t val, int *err)
689 {
690 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag,
691 &val, 1, err));
692 }
693
694 int
topo_prop_set_double(tnode_t * node,const char * pgname,const char * pname,int flag,double val,int * err)695 topo_prop_set_double(tnode_t *node, const char *pgname, const char *pname,
696 int flag, double val, int *err)
697 {
698 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_DOUBLE, flag,
699 &val, 1, err));
700 }
701
702 int
topo_prop_set_string(tnode_t * node,const char * pgname,const char * pname,int flag,const char * val,int * err)703 topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname,
704 int flag, const char *val, int *err)
705 {
706 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag,
707 (void *)val, 1, err));
708 }
709
710 int
topo_prop_set_fmri(tnode_t * node,const char * pgname,const char * pname,int flag,const nvlist_t * fmri,int * err)711 topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname,
712 int flag, const nvlist_t *fmri, int *err)
713 {
714 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag,
715 (void *)fmri, 1, err));
716 }
717
718 int
topo_prop_set_int32_array(tnode_t * node,const char * pgname,const char * pname,int flag,int32_t * val,uint_t nelems,int * err)719 topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname,
720 int flag, int32_t *val, uint_t nelems, int *err)
721 {
722 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag,
723 val, nelems, err));
724 }
725
726 int
topo_prop_set_uint32_array(tnode_t * node,const char * pgname,const char * pname,int flag,uint32_t * val,uint_t nelems,int * err)727 topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname,
728 int flag, uint32_t *val, uint_t nelems, int *err)
729 {
730 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag,
731 val, nelems, err));
732 }
733
734 int
topo_prop_set_int64_array(tnode_t * node,const char * pgname,const char * pname,int flag,int64_t * val,uint_t nelems,int * err)735 topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname,
736 int flag, int64_t *val, uint_t nelems, int *err)
737 {
738 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag,
739 val, nelems, err));
740 }
741
742 int
topo_prop_set_uint64_array(tnode_t * node,const char * pgname,const char * pname,int flag,uint64_t * val,uint_t nelems,int * err)743 topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname,
744 int flag, uint64_t *val, uint_t nelems, int *err)
745 {
746 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag,
747 val, nelems, err));
748 }
749
750 int
topo_prop_set_string_array(tnode_t * node,const char * pgname,const char * pname,int flag,const char ** val,uint_t nelems,int * err)751 topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname,
752 int flag, const char **val, uint_t nelems, int *err)
753 {
754 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag,
755 (void *)val, nelems, err));
756 }
757
758 int
topo_prop_set_fmri_array(tnode_t * node,const char * pgname,const char * pname,int flag,const nvlist_t ** fmri,uint_t nelems,int * err)759 topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname,
760 int flag, const nvlist_t **fmri, uint_t nelems, int *err)
761 {
762 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag,
763 (void *)fmri, nelems, err));
764 }
765
766 /*
767 * topo_prop_setprop() is a private project function for fmtopo
768 */
769 int
topo_prop_setprop(tnode_t * node,const char * pgname,nvlist_t * prop,int flag,nvlist_t * pargs,int * err)770 topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop,
771 int flag, nvlist_t *pargs, int *err)
772 {
773 int ret;
774 topo_hdl_t *thp = node->tn_hdl;
775 topo_propval_t *pv;
776 nvlist_t *nvl, *args;
777 char *name;
778 topo_type_t type;
779
780 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) {
781 *err = ETOPO_PROP_NAME;
782 return (-1);
783 }
784 if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type)
785 != 0) {
786 *err = ETOPO_PROP_TYPE;
787 return (-1);
788 }
789
790 topo_node_lock(node);
791 if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL)
792 return (-1); /* unlocked and err set */
793
794 /*
795 * Set by method or set to new prop value. If we fail, leave
796 * property in list with old value.
797 */
798 if (pv->tp_method != NULL) {
799 topo_propmethod_t *pm = pv->tp_method;
800
801 if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) {
802 topo_node_unlock(node);
803 *err = ETOPO_PROP_NOMEM;
804 return (-1);
805 }
806 ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args);
807 if (pargs != NULL)
808 ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs);
809
810 if (ret != 0) {
811 topo_node_unlock(node);
812 nvlist_free(args);
813 *err = ETOPO_PROP_NVL;
814 return (-1);
815 }
816
817 /*
818 *
819 * Grab a reference to the property and then unlock the node.
820 * This will allow property methods to safely re-enter the
821 * prop_get codepath, making it possible for property methods
822 * to access other property values on the same node w\o causing
823 * a deadlock.
824 *
825 * We don't technically need this now, since this interface is
826 * currently only used by fmtopo (which is single-threaded), but
827 * we may make this interface available to other parts of
828 * libtopo in the future, so best to make it MT-safe now.
829 */
830 topo_prop_hold(pv);
831 topo_node_unlock(node);
832 ret = topo_method_call(node, pm->tpm_name, pm->tpm_version,
833 args, &nvl, err);
834 topo_node_lock(node);
835 topo_prop_rele(pv);
836
837 nvlist_free(args);
838 } else {
839 if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0)
840 *err = ETOPO_PROP_NOMEM;
841 }
842
843 if (ret != 0) {
844 topo_node_unlock(node);
845 return (-1);
846 }
847
848 pv->tp_val = nvl;
849 topo_node_unlock(node);
850 return (0);
851 }
852
853 static int
register_methoderror(tnode_t * node,topo_propmethod_t * pm,int * errp,int l,int err)854 register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l,
855 int err)
856 {
857 topo_hdl_t *thp = node->tn_hdl;
858
859 if (pm != NULL) {
860 if (pm->tpm_name != NULL)
861 topo_hdl_strfree(thp, pm->tpm_name);
862 nvlist_free(pm->tpm_args);
863 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
864 }
865
866 *errp = err;
867
868 if (l != 0)
869 topo_node_unlock(node);
870
871 return (-1);
872 }
873
874 int
prop_method_register(tnode_t * node,const char * pgname,const char * pname,topo_type_t ptype,const char * mname,topo_version_t version,const nvlist_t * args,int * err)875 prop_method_register(tnode_t *node, const char *pgname, const char *pname,
876 topo_type_t ptype, const char *mname, topo_version_t version,
877 const nvlist_t *args, int *err)
878 {
879 topo_hdl_t *thp = node->tn_hdl;
880 topo_propmethod_t *pm = NULL;
881 topo_propval_t *pv = NULL;
882
883 if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL)
884 return (register_methoderror(node, pm, err, 1,
885 ETOPO_PROP_NOMEM));
886
887 if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL)
888 return (register_methoderror(node, pm, err, 1,
889 ETOPO_PROP_NOMEM));
890
891 pm->tpm_version = version;
892
893 if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0)
894 return (register_methoderror(node, pm, err, 1,
895 ETOPO_PROP_NOMEM));
896
897 /*
898 * It's possible the property may already exist. However we still want
899 * to allow the method to be registered. This is to handle the case
900 * where we specify a prop method in an xml map to override the value
901 * that was set by the enumerator.
902 *
903 * By default, propmethod-backed properties are not MUTABLE. This is
904 * done to simplify the programming model for modules that implement
905 * property methods as most propmethods tend to only support get
906 * operations. Enumerator modules can override this by calling
907 * topo_prop_setmutable(). Propmethods that are registered via XML can
908 * be set as mutable via the optional "mutable" attribute, which will
909 * result in the xml parser calling topo_prop_setflags() after
910 * registering the propmethod.
911 */
912 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL)
913 if ((pv = prop_create(node, pgname, pname, ptype,
914 TOPO_PROP_IMMUTABLE, err)) == NULL) {
915 /* node unlocked */
916 return (register_methoderror(node, pm, err, 0, *err));
917 }
918
919 if (pv->tp_method != NULL)
920 return (register_methoderror(node, pm, err, 1,
921 ETOPO_METHOD_DEFD));
922
923 if (pv->tp_val != NULL) {
924 nvlist_free(pv->tp_val);
925 pv->tp_val = NULL;
926 }
927 pv->tp_method = pm;
928
929 topo_node_unlock(node);
930
931 return (0);
932 }
933
934 int
topo_prop_method_register(tnode_t * node,const char * pgname,const char * pname,topo_type_t ptype,const char * mname,const nvlist_t * args,int * err)935 topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname,
936 topo_type_t ptype, const char *mname, const nvlist_t *args, int *err)
937 {
938 topo_imethod_t *mp;
939
940 topo_node_lock(node);
941
942 if ((mp = topo_method_lookup(node, mname)) == NULL)
943 return (register_methoderror(node, NULL, err, 1,
944 ETOPO_METHOD_NOTSUP)); /* node unlocked */
945
946 topo_node_lock(node);
947
948 return (prop_method_register(node, pgname, pname, ptype, mname,
949 mp->tim_version, args, err)); /* err set and node unlocked */
950 }
951
952 int
topo_prop_method_version_register(tnode_t * node,const char * pgname,const char * pname,topo_type_t ptype,const char * mname,topo_version_t version,const nvlist_t * args,int * err)953 topo_prop_method_version_register(tnode_t *node, const char *pgname,
954 const char *pname, topo_type_t ptype, const char *mname,
955 topo_version_t version, const nvlist_t *args, int *err)
956 {
957 topo_imethod_t *mp;
958
959 topo_node_lock(node);
960
961 if ((mp = topo_method_lookup(node, mname)) == NULL)
962 return (register_methoderror(node, NULL, err, 1,
963 ETOPO_METHOD_NOTSUP)); /* node unlocked */
964
965 topo_node_lock(node);
966
967 if (version < mp->tim_version)
968 return (register_methoderror(node, NULL, err, 1,
969 ETOPO_METHOD_VEROLD));
970 if (version > mp->tim_version)
971 return (register_methoderror(node, NULL, err, 1,
972 ETOPO_METHOD_VERNEW));
973
974 return (prop_method_register(node, pgname, pname, ptype, mname,
975 version, args, err)); /* err set and node unlocked */
976 }
977
978 void
topo_prop_method_unregister(tnode_t * node,const char * pgname,const char * pname)979 topo_prop_method_unregister(tnode_t *node, const char *pgname,
980 const char *pname)
981 {
982 topo_propval_t *pv;
983 topo_pgroup_t *pg;
984 topo_proplist_t *pvl;
985 topo_hdl_t *thp = node->tn_hdl;
986
987 topo_node_lock(node);
988
989 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
990 pg = topo_list_next(pg)) {
991 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) {
992 break;
993 }
994 }
995
996 if (pg == NULL) {
997 topo_node_unlock(node);
998 return;
999 }
1000
1001 for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL;
1002 pvl = topo_list_next(pvl)) {
1003 pv = pvl->tp_pval;
1004 if (strcmp(pv->tp_name, pname) == 0) {
1005 topo_list_delete(&pg->tpg_pvals, pvl);
1006 assert(pv->tp_refs == 1);
1007 topo_prop_rele(pv);
1008 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1009 break;
1010 }
1011 }
1012
1013 topo_node_unlock(node);
1014 }
1015
1016 int
topo_prop_setmutable(tnode_t * node,const char * pgname,const char * pname,int * err)1017 topo_prop_setmutable(tnode_t *node, const char *pgname, const char *pname,
1018 int *err)
1019 {
1020 topo_propval_t *pv = NULL;
1021
1022 topo_node_lock(node);
1023 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1024 topo_node_unlock(node);
1025 *err = ETOPO_PROP_NOENT;
1026 return (-1);
1027 }
1028
1029 /*
1030 * If the property is being inherited then we don't want to allow a
1031 * change from IMMUTABLE to MUTABLE.
1032 */
1033 if (pv->tp_refs > 1) {
1034 topo_node_unlock(node);
1035 *err = ETOPO_PROP_DEFD;
1036 return (-1);
1037 }
1038 pv->tp_flag |= TOPO_PROP_MUTABLE;
1039
1040 topo_node_unlock(node);
1041
1042 return (0);
1043 }
1044 int
topo_prop_setnonvolatile(tnode_t * node,const char * pgname,const char * pname,int * err)1045 topo_prop_setnonvolatile(tnode_t *node, const char *pgname, const char *pname,
1046 int *err)
1047 {
1048 topo_propval_t *pv = NULL;
1049
1050 topo_node_lock(node);
1051 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) {
1052 topo_node_unlock(node);
1053 *err = ETOPO_PROP_NOENT;
1054 return (-1);
1055 }
1056
1057 pv->tp_flag |= TOPO_PROP_NONVOLATILE;
1058
1059 topo_node_unlock(node);
1060
1061 return (0);
1062 }
1063
1064 static int
inherit_seterror(tnode_t * node,int * errp,int err)1065 inherit_seterror(tnode_t *node, int *errp, int err)
1066 {
1067 topo_node_unlock(node);
1068 topo_node_unlock(node->tn_parent);
1069
1070 *errp = err;
1071
1072 return (-1);
1073 }
1074
1075 int
topo_prop_inherit(tnode_t * node,const char * pgname,const char * name,int * err)1076 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
1077 {
1078 topo_hdl_t *thp = node->tn_hdl;
1079 tnode_t *pnode = node->tn_parent;
1080 topo_pgroup_t *pg;
1081 topo_propval_t *pv;
1082 topo_proplist_t *pvl;
1083
1084 topo_node_lock(pnode);
1085 topo_node_lock(node);
1086
1087 /*
1088 * Check if the requested property group and prop val are already set
1089 * on the node.
1090 */
1091 if (propval_get(pgroup_get(node, pgname), name) != NULL)
1092 return (inherit_seterror(node, err, ETOPO_PROP_DEFD));
1093
1094 /*
1095 * Check if the requested property group and prop val exists on the
1096 * parent node
1097 */
1098 if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
1099 return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
1100
1101 /*
1102 * Can this propval be inherited?
1103 */
1104 if (pv->tp_flag & TOPO_PROP_MUTABLE)
1105 return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT));
1106
1107 /*
1108 * Property group should already exist: bump the ref count for this
1109 * propval and add it to the node's property group
1110 */
1111 if ((pg = pgroup_get(node, pgname)) == NULL)
1112 return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
1113
1114 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t)))
1115 == NULL)
1116 return (inherit_seterror(node, err, ETOPO_NOMEM));
1117
1118 topo_prop_hold(pv);
1119 pvl->tp_pval = pv;
1120 topo_list_append(&pg->tpg_pvals, pvl);
1121
1122 topo_node_unlock(node);
1123 topo_node_unlock(pnode);
1124
1125 return (0);
1126 }
1127
1128 topo_pgroup_info_t *
topo_pgroup_info(tnode_t * node,const char * pgname,int * err)1129 topo_pgroup_info(tnode_t *node, const char *pgname, int *err)
1130 {
1131 topo_hdl_t *thp = node->tn_hdl;
1132 topo_pgroup_t *pg;
1133 topo_ipgroup_info_t *pip;
1134 topo_pgroup_info_t *info;
1135
1136 topo_node_lock(node);
1137 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1138 pg = topo_list_next(pg)) {
1139 if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) {
1140 if ((info = topo_hdl_alloc(thp,
1141 sizeof (topo_pgroup_info_t))) == NULL)
1142 return (NULL);
1143
1144 pip = pg->tpg_info;
1145 if ((info->tpi_name =
1146 topo_hdl_strdup(thp, pip->tpi_name)) == NULL) {
1147 *err = ETOPO_PROP_NOMEM;
1148 topo_hdl_free(thp, info,
1149 sizeof (topo_pgroup_info_t));
1150 topo_node_unlock(node);
1151 return (NULL);
1152 }
1153 info->tpi_namestab = pip->tpi_namestab;
1154 info->tpi_datastab = pip->tpi_datastab;
1155 info->tpi_version = pip->tpi_version;
1156 topo_node_unlock(node);
1157 return (info);
1158 }
1159 }
1160
1161 *err = ETOPO_PROP_NOENT;
1162 topo_node_unlock(node);
1163 return (NULL);
1164 }
1165
1166 static int
pgroup_seterr(tnode_t * node,topo_pgroup_t * pg,topo_ipgroup_info_t * pip,int * err)1167 pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip,
1168 int *err)
1169 {
1170 topo_hdl_t *thp = node->tn_hdl;
1171
1172 if (pip != NULL) {
1173 if (pip->tpi_name != NULL)
1174 topo_hdl_strfree(thp, (char *)pip->tpi_name);
1175 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
1176 }
1177
1178 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1179 *err = ETOPO_NOMEM;
1180
1181 topo_node_unlock(node);
1182
1183 return (-1);
1184 }
1185
1186 int
topo_pgroup_create(tnode_t * node,const topo_pgroup_info_t * pinfo,int * err)1187 topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err)
1188 {
1189 topo_pgroup_t *pg;
1190 topo_ipgroup_info_t *pip;
1191 topo_hdl_t *thp = node->tn_hdl;
1192
1193 *err = 0;
1194
1195 topo_node_lock(node);
1196 /*
1197 * Check for an existing pgroup
1198 */
1199 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1200 pg = topo_list_next(pg)) {
1201 if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) {
1202 *err = ETOPO_PROP_DEFD;
1203 topo_node_unlock(node);
1204 return (-1);
1205 }
1206 }
1207
1208 if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) {
1209 *err = ETOPO_NOMEM;
1210 topo_node_unlock(node);
1211 return (-1);
1212 }
1213
1214 if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t)))
1215 == NULL)
1216 return (pgroup_seterr(node, pg, pip, err));
1217
1218 if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name))
1219 == NULL)
1220 return (pgroup_seterr(node, pg, pip, err));
1221
1222 pip->tpi_namestab = pinfo->tpi_namestab;
1223 pip->tpi_datastab = pinfo->tpi_datastab;
1224 pip->tpi_version = pinfo->tpi_version;
1225
1226 pg->tpg_info = pip;
1227
1228 topo_list_append(&node->tn_pgroups, pg);
1229 topo_node_unlock(node);
1230
1231 return (0);
1232 }
1233
1234 void
topo_pgroup_destroy(tnode_t * node,const char * pname)1235 topo_pgroup_destroy(tnode_t *node, const char *pname)
1236 {
1237 topo_hdl_t *thp = node->tn_hdl;
1238 topo_pgroup_t *pg;
1239 topo_proplist_t *pvl;
1240 topo_ipgroup_info_t *pip;
1241
1242 topo_node_lock(node);
1243 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1244 pg = topo_list_next(pg)) {
1245 if (strcmp(pg->tpg_info->tpi_name, pname) == 0) {
1246 break;
1247 }
1248 }
1249
1250 if (pg == NULL) {
1251 topo_node_unlock(node);
1252 return;
1253 }
1254
1255 while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) {
1256 topo_list_delete(&pg->tpg_pvals, pvl);
1257 topo_prop_rele(pvl->tp_pval);
1258 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1259 }
1260
1261 topo_list_delete(&node->tn_pgroups, pg);
1262 topo_node_unlock(node);
1263
1264 pip = pg->tpg_info;
1265 if (pip != NULL) {
1266 if (pip->tpi_name != NULL)
1267 topo_hdl_strfree(thp, (char *)pip->tpi_name);
1268 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t));
1269 }
1270
1271 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1272 }
1273
1274 void
topo_pgroup_destroy_all(tnode_t * node)1275 topo_pgroup_destroy_all(tnode_t *node)
1276 {
1277 topo_hdl_t *thp = node->tn_hdl;
1278 topo_pgroup_t *pg;
1279 topo_proplist_t *pvl;
1280 topo_ipgroup_info_t *pip;
1281
1282 topo_node_lock(node);
1283 while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) {
1284 while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) {
1285 topo_list_delete(&pg->tpg_pvals, pvl);
1286 topo_prop_rele(pvl->tp_pval);
1287 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t));
1288 }
1289
1290 topo_list_delete(&node->tn_pgroups, pg);
1291
1292 pip = pg->tpg_info;
1293 if (pip != NULL) {
1294 if (pip->tpi_name != NULL)
1295 topo_hdl_strfree(thp, (char *)pip->tpi_name);
1296 topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t));
1297 }
1298
1299 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t));
1300 }
1301 topo_node_unlock(node);
1302 }
1303
1304 static void
propmethod_destroy(topo_hdl_t * thp,topo_propval_t * pv)1305 propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv)
1306 {
1307 topo_propmethod_t *pm;
1308
1309 pm = pv->tp_method;
1310 if (pm != NULL) {
1311 if (pm->tpm_name != NULL)
1312 topo_hdl_strfree(thp, pm->tpm_name);
1313 nvlist_free(pm->tpm_args);
1314 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t));
1315 pv->tp_method = NULL;
1316 }
1317 }
1318
1319 static void
topo_propval_destroy(topo_propval_t * pv)1320 topo_propval_destroy(topo_propval_t *pv)
1321 {
1322 topo_hdl_t *thp;
1323
1324 if (pv == NULL)
1325 return;
1326
1327 thp = pv->tp_hdl;
1328
1329 if (pv->tp_name != NULL)
1330 topo_hdl_strfree(thp, pv->tp_name);
1331
1332 nvlist_free(pv->tp_val);
1333
1334 propmethod_destroy(thp, pv);
1335
1336 topo_hdl_free(thp, pv, sizeof (topo_propval_t));
1337 }
1338
1339 void
topo_prop_hold(topo_propval_t * pv)1340 topo_prop_hold(topo_propval_t *pv)
1341 {
1342 pv->tp_refs++;
1343 }
1344
1345 void
topo_prop_rele(topo_propval_t * pv)1346 topo_prop_rele(topo_propval_t *pv)
1347 {
1348 pv->tp_refs--;
1349
1350 assert(pv->tp_refs >= 0);
1351
1352 if (pv->tp_refs == 0)
1353 topo_propval_destroy(pv);
1354 }
1355
1356 /*
1357 * topo_prop_getprop() and topo_prop_getprops() are private project functions
1358 * for fmtopo
1359 */
1360 int
topo_prop_getprop(tnode_t * node,const char * pgname,const char * pname,nvlist_t * args,nvlist_t ** prop,int * err)1361 topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname,
1362 nvlist_t *args, nvlist_t **prop, int *err)
1363 {
1364 topo_hdl_t *thp = node->tn_hdl;
1365 topo_propval_t *pv;
1366
1367 topo_node_lock(node);
1368 if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) {
1369 (void) get_properror(node, err, *err);
1370 return (-1);
1371 }
1372
1373 if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) {
1374 (void) get_properror(node, err, ETOPO_NOMEM);
1375 return (-1);
1376 }
1377 topo_node_unlock(node);
1378
1379 return (0);
1380 }
1381
1382 static int
prop_val_add(tnode_t * node,nvlist_t ** nvl,topo_propval_t * pv,int * err)1383 prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err)
1384 {
1385 if (pv->tp_method != NULL)
1386 if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0)
1387 return (-1);
1388
1389 if (pv->tp_val == NULL) {
1390 *err = ETOPO_PROP_NOENT;
1391 return (-1);
1392 }
1393
1394 if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) {
1395 *err = ETOPO_PROP_NOMEM;
1396 return (-1);
1397 }
1398
1399 return (0);
1400 }
1401
1402 static int
get_pgrp_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)1403 get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1404 {
1405 topo_node_unlock(node);
1406
1407 nvlist_free(nvl);
1408
1409 *errp = err;
1410
1411 return (-1);
1412 }
1413
1414 int
topo_prop_getpgrp(tnode_t * node,const char * pgname,nvlist_t ** pgrp,int * err)1415 topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp,
1416 int *err)
1417 {
1418 int ret;
1419 topo_hdl_t *thp = node->tn_hdl;
1420 nvlist_t *nvl, *pvnvl;
1421 topo_pgroup_t *pg;
1422 topo_propval_t *pv;
1423 topo_proplist_t *pvl;
1424
1425 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1426 *err = ETOPO_NOMEM;
1427 return (-1);
1428 }
1429
1430 topo_node_lock(node);
1431 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1432 pg = topo_list_next(pg)) {
1433
1434 if (strcmp(pgname, pg->tpg_info->tpi_name) != 0)
1435 continue;
1436
1437 if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME,
1438 pg->tpg_info->tpi_name) != 0 ||
1439 nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB,
1440 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1441 nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB,
1442 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1443 nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION,
1444 pg->tpg_info->tpi_version) != 0)
1445 return (get_pgrp_seterror(node, nvl, err,
1446 ETOPO_PROP_NVL));
1447
1448 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1449 pvl = topo_list_next(pvl)) {
1450
1451 pv = pvl->tp_pval;
1452 if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1453 return (get_pgrp_seterror(node, nvl, err,
1454 *err));
1455 }
1456 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL,
1457 pvnvl)) != 0) {
1458 nvlist_free(pvnvl);
1459 return (get_pgrp_seterror(node, nvl, err, ret));
1460 }
1461
1462 nvlist_free(pvnvl);
1463 }
1464 topo_node_unlock(node);
1465 *pgrp = nvl;
1466 return (0);
1467 }
1468
1469 topo_node_unlock(node);
1470 *err = ETOPO_PROP_NOENT;
1471 return (-1);
1472 }
1473
1474 static nvlist_t *
get_all_seterror(tnode_t * node,nvlist_t * nvl,int * errp,int err)1475 get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err)
1476 {
1477 topo_node_unlock(node);
1478
1479 nvlist_free(nvl);
1480
1481 *errp = err;
1482
1483 return (NULL);
1484 }
1485
1486 nvlist_t *
topo_prop_getprops(tnode_t * node,int * err)1487 topo_prop_getprops(tnode_t *node, int *err)
1488 {
1489 int ret;
1490 topo_hdl_t *thp = node->tn_hdl;
1491 nvlist_t *nvl, *pgnvl, *pvnvl;
1492 topo_pgroup_t *pg;
1493 topo_propval_t *pv;
1494 topo_proplist_t *pvl;
1495
1496 topo_node_lock(node);
1497 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) {
1498 return (get_all_seterror(node, NULL, err, ETOPO_NOMEM));
1499 }
1500
1501 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL;
1502 pg = topo_list_next(pg)) {
1503 if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0)
1504 return (get_all_seterror(node, nvl, err, ETOPO_NOMEM));
1505
1506 if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME,
1507 pg->tpg_info->tpi_name) != 0 ||
1508 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB,
1509 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 ||
1510 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB,
1511 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 ||
1512 nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION,
1513 pg->tpg_info->tpi_version) != 0)
1514 return (get_all_seterror(node, nvl, err,
1515 ETOPO_PROP_NVL));
1516
1517 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL;
1518 pvl = topo_list_next(pvl)) {
1519
1520 pv = pvl->tp_pval;
1521 if (prop_val_add(node, &pvnvl, pv, err) < 0) {
1522 nvlist_free(pgnvl);
1523 return (get_all_seterror(node, nvl, err, *err));
1524 }
1525 if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL,
1526 pvnvl)) != 0) {
1527 nvlist_free(pgnvl);
1528 nvlist_free(pvnvl);
1529 return (get_all_seterror(node, nvl, err, ret));
1530 }
1531
1532 nvlist_free(pvnvl);
1533 }
1534 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl))
1535 != 0) {
1536 nvlist_free(pgnvl);
1537 return (get_all_seterror(node, nvl, err, ret));
1538 }
1539
1540 nvlist_free(pgnvl);
1541 }
1542
1543 topo_node_unlock(node);
1544
1545 return (nvl);
1546 }
1547
1548 /*
1549 * This is a convenience function for modules in the spirit of
1550 * nvlist_get_pairs(). Most modules want to create a property group (which may
1551 * already exist) and then set a number of properties. If setting any one
1552 * property fails then the operation will fail and they are responsible for
1553 * tearing down the node or failing the operation.
1554 */
1555 int
topo_create_props(topo_mod_t * mod,tnode_t * tn,int prop_flags,const topo_pgroup_info_t * grp,...)1556 topo_create_props(topo_mod_t *mod, tnode_t *tn, int prop_flags,
1557 const topo_pgroup_info_t *grp, ...)
1558 {
1559 va_list ap;
1560 const char *prop;
1561 int ret = 0, err;
1562
1563 if (topo_pgroup_create(tn, grp, &err) != 0 && err != ETOPO_PROP_DEFD) {
1564 topo_mod_dprintf(mod, "failed to create property group %s: %s",
1565 grp->tpi_name, topo_strerror(err));
1566 return (topo_mod_seterrno(mod, err));
1567 }
1568
1569 va_start(ap, grp);
1570 while ((prop = va_arg(ap, const char *)) != NULL) {
1571 topo_type_t type = va_arg(ap, topo_type_t);
1572
1573 switch (type) {
1574 case TOPO_TYPE_INT32: {
1575 int32_t val = va_arg(ap, int32_t);
1576 ret = topo_prop_set_int32(tn, grp->tpi_name, prop,
1577 prop_flags, val, &err);
1578 break;
1579 }
1580 case TOPO_TYPE_UINT32: {
1581 uint32_t val = va_arg(ap, uint32_t);
1582 ret = topo_prop_set_uint32(tn, grp->tpi_name, prop,
1583 prop_flags, val, &err);
1584 break;
1585 }
1586 case TOPO_TYPE_INT64: {
1587 int64_t val = va_arg(ap, int64_t);
1588 ret = topo_prop_set_int64(tn, grp->tpi_name, prop,
1589 prop_flags, val, &err);
1590 break;
1591 }
1592 case TOPO_TYPE_UINT64: {
1593 uint64_t val = va_arg(ap, uint64_t);
1594 ret = topo_prop_set_uint64(tn, grp->tpi_name, prop,
1595 prop_flags, val, &err);
1596 break;
1597 }
1598 case TOPO_TYPE_STRING: {
1599 const char *val = va_arg(ap, const char *);
1600 ret = topo_prop_set_string(tn, grp->tpi_name, prop,
1601 prop_flags, val, &err);
1602 break;
1603 }
1604 case TOPO_TYPE_FMRI: {
1605 const nvlist_t *val = va_arg(ap, const nvlist_t *);
1606 ret = topo_prop_set_fmri(tn, grp->tpi_name, prop,
1607 prop_flags, val, &err);
1608 break;
1609 }
1610 case TOPO_TYPE_INT32_ARRAY: {
1611 int32_t *vals = va_arg(ap, int32_t *);
1612 uint_t count = va_arg(ap, uint_t);
1613 ret = topo_prop_set_int32_array(tn, grp->tpi_name,
1614 prop, prop_flags, vals, count, &err);
1615 break;
1616 }
1617 case TOPO_TYPE_UINT32_ARRAY: {
1618 uint32_t *vals = va_arg(ap, uint32_t *);
1619 uint_t count = va_arg(ap, uint_t);
1620 ret = topo_prop_set_uint32_array(tn, grp->tpi_name,
1621 prop, prop_flags, vals, count, &err);
1622 break;
1623 }
1624 case TOPO_TYPE_INT64_ARRAY: {
1625 int64_t *vals = va_arg(ap, int64_t *);
1626 uint_t count = va_arg(ap, uint_t);
1627 ret = topo_prop_set_int64_array(tn, grp->tpi_name,
1628 prop, prop_flags, vals, count, &err);
1629 break;
1630 }
1631 case TOPO_TYPE_UINT64_ARRAY: {
1632 uint64_t *vals = va_arg(ap, uint64_t *);
1633 uint_t count = va_arg(ap, uint_t);
1634 ret = topo_prop_set_uint64_array(tn, grp->tpi_name,
1635 prop, prop_flags, vals, count, &err);
1636 break;
1637 }
1638 case TOPO_TYPE_STRING_ARRAY: {
1639 const char **vals = va_arg(ap, const char **);
1640 uint_t count = va_arg(ap, uint_t);
1641 ret = topo_prop_set_string_array(tn, grp->tpi_name,
1642 prop, prop_flags, vals, count, &err);
1643 break;
1644 }
1645 case TOPO_TYPE_FMRI_ARRAY: {
1646 const nvlist_t **vals = va_arg(ap, const nvlist_t **);
1647 uint_t count = va_arg(ap, uint_t);
1648 ret = topo_prop_set_fmri_array(tn, grp->tpi_name,
1649 prop, prop_flags, vals, count, &err);
1650 break;
1651 }
1652 case TOPO_TYPE_DOUBLE: {
1653 double val = va_arg(ap, double);
1654 ret = topo_prop_set_double(tn, grp->tpi_name, prop,
1655 prop_flags, val, &err);
1656 break;
1657 }
1658 default:
1659 topo_mod_dprintf(mod, "cannot set property %s with "
1660 "unsupported and unknown type 0x%x\n", prop,
1661 type);
1662 va_end(ap);
1663 return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM));
1664 }
1665
1666 if (ret != 0) {
1667 topo_mod_dprintf(mod, "failed to create %s property "
1668 "%s: %s\n", grp->tpi_name, prop,
1669 topo_strerror(err));
1670 va_end(ap);
1671 return (topo_mod_seterrno(mod, err));
1672 }
1673 }
1674
1675 va_end(ap);
1676 return (0);
1677 }
1678