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