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 * 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 * 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 1340 topo_prop_hold(topo_propval_t *pv) 1341 { 1342 pv->tp_refs++; 1343 } 1344 1345 void 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 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 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 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 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 * 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 * 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 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