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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * Subroutines used by various components of the Sun4v PI enumerator 30 */ 31 32 #include <sys/types.h> 33 #include <sys/systeminfo.h> 34 #include <sys/utsname.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <sys/fm/protocol.h> 38 #include <fm/topo_mod.h> 39 #include <fm/topo_hc.h> 40 #include <sys/mdesc.h> 41 #include <libnvpair.h> 42 43 #include "pi_impl.h" 44 45 #define MAX_PATH_DEPTH (MAXPATHLEN / 256) /* max pci path = 256 */ 46 47 static const topo_pgroup_info_t sys_pgroup = { 48 TOPO_PGROUP_SYSTEM, 49 TOPO_STABILITY_PRIVATE, 50 TOPO_STABILITY_PRIVATE, 51 1 52 }; 53 54 static const topo_pgroup_info_t auth_pgroup = { 55 FM_FMRI_AUTHORITY, 56 TOPO_STABILITY_PRIVATE, 57 TOPO_STABILITY_PRIVATE, 58 1 59 }; 60 61 62 /* 63 * Search the PRI for MDE nodes using md_scan_dag. Using this routine 64 * consolodates similar searches used in a few places within the sun4vpi 65 * enumerator. 66 * 67 * The routine returns the number of nodes found, or -1. If the node array 68 * is non-NULL on return, then it must be freed: 69 * topo_mod_free(mod, nodes, nsize); 70 * 71 */ 72 int 73 pi_find_mdenodes(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_start, 74 char *type_str, char *arc_str, mde_cookie_t **nodes, size_t *nsize) 75 { 76 int result; 77 int total_mdenodes; 78 79 mde_str_cookie_t start_cookie; 80 mde_str_cookie_t arc_cookie; 81 82 /* Prepare to scan the PRI using the start string and given arc */ 83 total_mdenodes = md_node_count(mdp); 84 start_cookie = md_find_name(mdp, type_str); 85 arc_cookie = md_find_name(mdp, arc_str); 86 87 /* Allocate an array to hold the results of the scan */ 88 *nsize = sizeof (mde_cookie_t) * total_mdenodes; 89 *nodes = topo_mod_zalloc(mod, *nsize); 90 if (*nodes == NULL) { 91 /* We have no memory. Set an error code and return failure */ 92 *nsize = 0; 93 topo_mod_seterrno(mod, EMOD_NOMEM); 94 return (-1); 95 } 96 97 result = md_scan_dag(mdp, mde_start, start_cookie, arc_cookie, *nodes); 98 if (result <= 0) { 99 /* No nodes found. Free the node array before returning */ 100 topo_mod_free(mod, *nodes, *nsize); 101 *nodes = NULL; 102 *nsize = 0; 103 } 104 105 return (result); 106 } 107 108 109 /* 110 * Determine if this node should be skipped by finding the topo-skip property. 111 */ 112 int 113 pi_skip_node(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 114 { 115 int result; 116 uint64_t skip; 117 118 if (mod == NULL || mdp == NULL) { 119 /* 120 * These parameters are required. Tell the caller to skip 121 * all nodes. 122 */ 123 return (1); 124 } 125 126 skip = 0; /* do not skip by default */ 127 result = md_get_prop_val(mdp, mde_node, MD_STR_TOPO_SKIP, &skip); 128 if (result != 0) { 129 /* 130 * There is no topo-skip property. Assume we are not skipping 131 * the mde node. 132 */ 133 skip = 0; 134 } 135 136 /* 137 * If skip is present and non-zero we want to skip this node. We 138 * return 1 to indicate this. 139 */ 140 if (skip != 0) { 141 return (1); 142 } 143 return (0); 144 } 145 146 /* 147 * Get the product serial number (the ID as far as the topo authority is 148 * concerned) either from the current node, if it is of type 'product', or 149 * search for a product node in the PRI. 150 * 151 * The string must be freed with topo_mod_strfree() 152 */ 153 char * 154 pi_get_productsn(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 155 { 156 int result; 157 int idx; 158 int num_nodes; 159 char *id = NULL; 160 char *type; 161 size_t size; 162 mde_cookie_t *nodes = NULL; 163 164 topo_mod_dprintf(mod, "pi_get_productsn: enter\n"); 165 166 result = md_get_prop_str(mdp, mde_node, MD_STR_TYPE, &type); 167 if (result == 0 && strcmp(type, MD_STR_PRODUCT) == 0) { 168 /* 169 * This is a product node. We need only search for the serial 170 * number property on this node to return the ID. 171 */ 172 result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER, 173 &id); 174 if (result != 0 || id == NULL || strlen(id) == 0) 175 return (NULL); 176 177 topo_mod_dprintf(mod, "pi_get_productsn: product-sn = %s\n", 178 id); 179 return (topo_mod_strdup(mod, id)); 180 } 181 182 /* 183 * Search the PRI for nodes of type MD_STR_COMPONENT and find the 184 * first element with type of MD_STR_PRODUCT. This node 185 * will contain the MD_STR_SERIAL_NUMBER property to use as the 186 * product-sn. 187 */ 188 num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE, 189 MD_STR_COMPONENT, MD_STR_FWD, &nodes, &size); 190 if (num_nodes <= 0 || nodes == NULL) { 191 /* We did not find any component nodes */ 192 return (NULL); 193 } 194 topo_mod_dprintf(mod, "pi_get_productsn: found %d %s nodes\n", 195 num_nodes, MD_STR_COMPONENT); 196 197 idx = 0; 198 while (id == NULL && idx < num_nodes) { 199 result = md_get_prop_str(mdp, nodes[idx], MD_STR_TYPE, &type); 200 if (result == 0 && strcmp(type, MD_STR_PRODUCT) == 0) { 201 /* 202 * This is a product node. Get the serial number 203 * property from the node. 204 */ 205 result = md_get_prop_str(mdp, nodes[idx], 206 MD_STR_SERIAL_NUMBER, &id); 207 if (result != 0) 208 topo_mod_dprintf(mod, "pi_get_productsn: " 209 "failed to read %s from node_0x%llx\n", 210 MD_STR_SERIAL_NUMBER, 211 (uint64_t)nodes[idx]); 212 } 213 /* Search the next node, if necessary */ 214 idx++; 215 } 216 topo_mod_free(mod, nodes, size); 217 218 /* Everything is freed up and it's time to return the product-sn */ 219 if (result != 0 || id == NULL || strlen(id) == 0) { 220 return (NULL); 221 } 222 topo_mod_dprintf(mod, "pi_get_productsn: product-sn %s\n", id); 223 224 return (topo_mod_strdup(mod, id)); 225 } 226 227 228 /* 229 * Get the chassis serial number (the ID as far as the topo authority is 230 * concerned) either from the current node, if it is of type 'chassis', or 231 * search for a chassis node in the PRI. 232 * 233 * The string must be freed with topo_mod_strfree() 234 */ 235 char * 236 pi_get_chassisid(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 237 { 238 int result; 239 int idx; 240 int num_nodes; 241 char *id = NULL; 242 char *hc_name = NULL; 243 size_t chassis_size; 244 mde_cookie_t *chassis_nodes = NULL; 245 246 topo_mod_dprintf(mod, "pi_get_chassis: enter\n"); 247 248 hc_name = pi_get_topo_hc_name(mod, mdp, mde_node); 249 if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) { 250 topo_mod_strfree(mod, hc_name); 251 252 /* 253 * This is a chassis node. We need only search for the serial 254 * number property on this node to return the ID. 255 */ 256 result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER, 257 &id); 258 if (result != 0 || id == NULL || strlen(id) == 0) { 259 return (NULL); 260 } 261 topo_mod_dprintf(mod, "pi_get_chassis: chassis-id = %s\n", id); 262 return (topo_mod_strdup(mod, id)); 263 } 264 if (hc_name != NULL) { 265 topo_mod_strfree(mod, hc_name); 266 } 267 268 /* 269 * Search the PRI for nodes of type MD_STR_COMPONENT and find the 270 * first element with topo-hc-type of MD_STR_CHASSIS. This node 271 * will contain the MD_STR_SERIAL_NUMBER property to use as the 272 * chassis-id. 273 */ 274 num_nodes = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE, 275 MD_STR_COMPONENT, MD_STR_FWD, &chassis_nodes, &chassis_size); 276 if (num_nodes <= 0 || chassis_nodes == NULL) { 277 /* We did not find any chassis nodes */ 278 return (NULL); 279 } 280 topo_mod_dprintf(mod, "pi_get_chassisid: found %d %s nodes\n", 281 num_nodes, MD_STR_COMPONENT); 282 283 idx = 0; 284 while (id == NULL && idx < num_nodes) { 285 hc_name = pi_get_topo_hc_name(mod, mdp, chassis_nodes[idx]); 286 if (hc_name != NULL && strcmp(hc_name, MD_STR_CHASSIS) == 0) { 287 /* 288 * This is a chassis node. Get the serial number 289 * property from the node. 290 */ 291 result = md_get_prop_str(mdp, chassis_nodes[idx], 292 MD_STR_SERIAL_NUMBER, &id); 293 if (result != 0) { 294 topo_mod_dprintf(mod, "pi_get_chassisid: " 295 "failed to read %s from node_0x%llx\n", 296 MD_STR_SERIAL_NUMBER, 297 (uint64_t)chassis_nodes[idx]); 298 } 299 } 300 topo_mod_strfree(mod, hc_name); 301 302 /* Search the next node, if necessary */ 303 idx++; 304 } 305 topo_mod_free(mod, chassis_nodes, chassis_size); 306 307 /* Everything is freed up and it's time to return the platform-id */ 308 if (result != 0 || id == NULL || strlen(id) == 0) { 309 return (NULL); 310 } 311 topo_mod_dprintf(mod, "pi_get_chassis: chassis-id %s\n", id); 312 313 return (topo_mod_strdup(mod, id)); 314 } 315 316 317 /* 318 * Determine if the node is a FRU by checking for the existance and non-zero 319 * value of the 'fru' property on the mde node. 320 */ 321 int 322 pi_get_fru(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, int *is_fru) 323 { 324 int result; 325 uint64_t fru; 326 327 if (mod == NULL || mdp == NULL || is_fru == NULL) { 328 return (-1); 329 } 330 fru = 0; 331 *is_fru = 0; 332 333 result = md_get_prop_val(mdp, mde_node, MD_STR_FRU, &fru); 334 if (result != 0) { 335 /* The node is not a FRU. */ 336 return (-1); 337 } 338 if (fru != 0) { 339 *is_fru = 1; 340 } 341 return (0); 342 } 343 344 345 /* 346 * Get the id property value from the given PRI node 347 */ 348 int 349 pi_get_instance(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, 350 topo_instance_t *ip) 351 { 352 int result; 353 uint64_t id; 354 355 id = 0; 356 result = md_get_prop_val(mdp, mde_node, MD_STR_ID, &id); 357 if (result != 0) { 358 /* 359 * There is no id property. 360 */ 361 topo_mod_dprintf(mod, "node_0x%llx has no id property\n", 362 (uint64_t)mde_node); 363 return (-1); 364 } 365 *ip = id; 366 367 return (0); 368 } 369 370 371 /* 372 * If the given MDE node is a FRU return the 'nac' property, if it exists, 373 * to use as the label. 374 * 375 * The string must be freed with topo_mod_strfree() 376 */ 377 char * 378 pi_get_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 379 { 380 int result; 381 int is_fru; 382 char *lp = NULL; 383 384 result = pi_get_fru(mod, mdp, mde_node, &is_fru); 385 if (result != 0 || is_fru == 0) { 386 /* This node is not a FRU. It has no label */ 387 return (NULL); 388 } 389 390 /* 391 * The node is a FRU. Get the NAC name to use as a label. 392 */ 393 result = md_get_prop_str(mdp, mde_node, MD_STR_NAC, &lp); 394 if (result != 0 || lp == NULL || strlen(lp) == 0) { 395 /* No NAC label. Return NULL */ 396 return (NULL); 397 } 398 399 /* Return a copy of the label */ 400 return (topo_mod_strdup(mod, lp)); 401 } 402 403 404 /* 405 * Return the complete part number string to the caller. The complete part 406 * number is made up of the part number attribute concatenated with the dash 407 * number attribute of the mde node. 408 * 409 * The string must be freed with topo_mod_strfree() 410 */ 411 char * 412 pi_get_part(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 413 { 414 int result; 415 size_t bufsize; 416 char *buf = NULL; 417 char *part = NULL; 418 char *dash = NULL; 419 420 result = md_get_prop_str(mdp, mde_node, MD_STR_PART_NUMBER, &part); 421 if (result != 0) { 422 part = NULL; 423 } 424 result = md_get_prop_str(mdp, mde_node, MD_STR_DASH_NUMBER, &dash); 425 if (result != 0) { 426 dash = NULL; 427 } 428 bufsize = 1 + (part ? strlen(part) : 0) + (dash ? strlen(dash) : 0); 429 if (bufsize == 1) { 430 return (NULL); 431 } 432 433 /* Construct the part number from the part and dash values */ 434 buf = topo_mod_alloc(mod, bufsize); 435 if (buf != NULL) { 436 (void) snprintf(buf, bufsize, "%s%s", (part ? part : ""), 437 (dash ? dash : "")); 438 } 439 440 return (buf); 441 } 442 443 444 /* 445 * Return the path string to the caller. 446 * 447 * The string must be freed with topo_mod_strfree() 448 */ 449 char * 450 pi_get_path(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 451 { 452 int result; 453 int i = 0; 454 size_t max_addrs; 455 size_t path_len = 0; 456 size_t buf_len; 457 char *propbuf = NULL; 458 char *buf = NULL; 459 char *buffree; 460 char *path = NULL; 461 char *token; 462 char *dev_addr[MAX_PATH_DEPTH] = { NULL }; 463 char *dev_path[MAX_PATH_DEPTH] = { NULL }; 464 char *lastp; 465 466 /* 467 * Get the path property from PRI; should look something 468 * like "/@600/@0". 469 */ 470 result = md_get_prop_str(mdp, mde_node, MD_STR_PATH, &propbuf); 471 if (result != 0 || propbuf == NULL || strlen(propbuf) == 0) { 472 topo_mod_dprintf(mod, "pi_get_path: failed to get path\n"); 473 return (NULL); 474 } 475 buf_len = strlen(propbuf) + 1; 476 buf = topo_mod_alloc(mod, buf_len); 477 if (buf == NULL) { 478 topo_mod_dprintf(mod, "pi_get_path: no memory\n"); 479 return (NULL); 480 } 481 buffree = buf; /* strtok_r is destructive */ 482 (void) strcpy(buf, propbuf); 483 484 /* 485 * Grab the address(es) from the path property. 486 */ 487 if ((token = strtok_r(buf, "/@", &lastp)) != NULL) { 488 dev_addr[i] = topo_mod_strdup(mod, token); 489 while ((token = strtok_r(NULL, "/@", &lastp)) != NULL) { 490 if (++i < MAX_PATH_DEPTH) { 491 dev_addr[i] = topo_mod_strdup(mod, token); 492 } else { 493 topo_mod_dprintf(mod, "pi_get_path: path " 494 "too long (%d)\n", i); 495 topo_mod_free(mod, buffree, buf_len); 496 return (NULL); 497 } 498 } 499 } else { 500 topo_mod_dprintf(mod, "pi_get_path: path wrong\n"); 501 topo_mod_free(mod, buffree, buf_len); 502 return (NULL); 503 } 504 max_addrs = ++i; 505 topo_mod_free(mod, buffree, buf_len); 506 507 /* 508 * Construct the path to look something like "/pci@600/pci@0". 509 */ 510 for (i = 0; i < max_addrs; i++) { 511 int len = strlen(dev_addr[i]) + strlen("/pci@") + 1; 512 path_len += len; 513 dev_path[i] = (char *)topo_mod_alloc(mod, len); 514 result = snprintf(dev_path[i], len, "/pci@%s", dev_addr[i]); 515 if (result < 0) { 516 return (NULL); 517 } 518 } 519 520 path_len -= (i - 1); /* leave room for one null char */ 521 path = (char *)topo_mod_alloc(mod, path_len); 522 path = strcpy(path, dev_path[0]); 523 524 /* put the parts together */ 525 for (i = 1; i < max_addrs; i++) { 526 path = strncat(path, dev_path[i], strlen(dev_path[i]) + 1); 527 } 528 529 /* 530 * Cleanup 531 */ 532 for (i = 0; i < max_addrs; i++) { 533 if (dev_addr[i] != NULL) { 534 topo_mod_free(mod, dev_addr[i], 535 strlen(dev_addr[i]) + 1); 536 } 537 if (dev_path[i] != NULL) { 538 topo_mod_free(mod, dev_path[i], 539 strlen(dev_path[i]) + 1); 540 } 541 } 542 543 topo_mod_dprintf(mod, "pi_get_path: path = (%s)\n", path); 544 return (path); 545 } 546 547 548 /* 549 * Get the product ID from the 'platform' node in the PRI 550 * 551 * The string must be freed with topo_mod_strfree() 552 */ 553 char * 554 pi_get_productid(topo_mod_t *mod, md_t *mdp) 555 { 556 int result; 557 char *id = NULL; 558 size_t platform_size; 559 mde_cookie_t *platform_nodes = NULL; 560 561 topo_mod_dprintf(mod, "pi_get_product: enter\n"); 562 563 /* 564 * Search the PRI for nodes of type MD_STR_PLATFORM, which contains 565 * the product-id in it's MD_STR_NAME property. 566 */ 567 result = pi_find_mdenodes(mod, mdp, MDE_INVAL_ELEM_COOKIE, 568 MD_STR_PLATFORM, MD_STR_FWD, &platform_nodes, &platform_size); 569 if (result <= 0 || platform_nodes == NULL) { 570 /* We did not find any platform nodes */ 571 return (NULL); 572 } 573 topo_mod_dprintf(mod, "pi_get_productid: found %d platform nodes\n", 574 result); 575 576 /* 577 * There should only be 1 platform node, so we will always 578 * use the first if we find any at all. 579 */ 580 result = md_get_prop_str(mdp, platform_nodes[0], MD_STR_NAME, &id); 581 topo_mod_free(mod, platform_nodes, platform_size); 582 583 /* Everything is freed up and it's time to return the platform-id */ 584 if (result != 0 || id == NULL || strlen(id) == 0) { 585 return (NULL); 586 } 587 topo_mod_dprintf(mod, "pi_get_product: returning %s\n", id); 588 589 return (topo_mod_strdup(mod, id)); 590 } 591 592 593 /* 594 * Return the revision string to the caller. 595 * 596 * The string must be freed with topo_mod_strfree() 597 */ 598 char * 599 pi_get_revision(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 600 { 601 int result; 602 char *rp = NULL; 603 604 result = md_get_prop_str(mdp, mde_node, MD_STR_REVISION_NUMBER, &rp); 605 if (result != 0 || rp == NULL || strlen(rp) == 0) { 606 return (NULL); 607 } 608 609 return (topo_mod_strdup(mod, rp)); 610 } 611 612 613 /* 614 * Return the serial number string to the caller. 615 * 616 * The string must be freed with topo_mod_strfree() 617 */ 618 char * 619 pi_get_serial(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 620 { 621 int result; 622 uint64_t sn; 623 char *sp = NULL; 624 char buf[MAXNAMELEN]; 625 626 result = md_get_prop_str(mdp, mde_node, MD_STR_SERIAL_NUMBER, &sp); 627 if (result != 0 || sp == NULL || strlen(sp) == 0) { 628 /* Is this a uint64_t type serial number? */ 629 result = md_get_prop_val(mdp, mde_node, MD_STR_SERIAL_NUMBER, 630 &sn); 631 if (result != 0) { 632 /* No. We have failed to find a serial number */ 633 return (NULL); 634 } 635 topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx numeric " 636 "serial number %llx\n", (uint64_t)mde_node, sn); 637 638 /* Convert the acquired value to a string */ 639 result = snprintf(buf, sizeof (buf), "%llu", sn); 640 if (result < 0) { 641 return (NULL); 642 } 643 sp = buf; 644 } 645 topo_mod_dprintf(mod, "pi_get_serial: node_0x%llx = %s\n", 646 (uint64_t)mde_node, (sp == NULL ? "NULL" : sp)); 647 648 return (topo_mod_strdup(mod, sp)); 649 } 650 651 652 /* 653 * Get the server hostname (the ID as far as the topo authority is 654 * concerned) from sysinfo and return a copy to the caller. 655 * 656 * The string must be freed with topo_mod_strfree() 657 */ 658 char * 659 pi_get_serverid(topo_mod_t *mod) 660 { 661 int result; 662 char hostname[MAXNAMELEN]; 663 664 topo_mod_dprintf(mod, "pi_get_serverid: enter\n"); 665 666 result = sysinfo(SI_HOSTNAME, hostname, sizeof (hostname)); 667 /* Everything is freed up and it's time to return the platform-id */ 668 if (result == -1) { 669 return (NULL); 670 } 671 topo_mod_dprintf(mod, "pi_get_serverid: hostname = %s\n", hostname); 672 673 return (topo_mod_strdup(mod, hostname)); 674 } 675 676 677 /* 678 * Get the hc scheme name for the given node 679 */ 680 char * 681 pi_get_topo_hc_name(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node) 682 { 683 int result; 684 char *hc_name; 685 686 /* 687 * Request the hc name from the node. 688 */ 689 hc_name = NULL; 690 result = md_get_prop_str(mdp, mde_node, MD_STR_TOPO_HC_NAME, &hc_name); 691 if (result != 0 || hc_name == NULL) { 692 topo_mod_dprintf(mod, 693 "failed to get property %s from node_0x%llx\n", 694 MD_STR_TOPO_HC_NAME, (uint64_t)mde_node); 695 return (NULL); 696 } 697 698 /* Return a copy of the type string */ 699 return (topo_mod_strdup(mod, hc_name)); 700 } 701 702 703 /* 704 * Calculate the authority information for a node. Inherit the data if 705 * possible, but always create an appropriate property group. 706 */ 707 int 708 pi_set_auth(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, 709 tnode_t *t_parent, tnode_t *t_node) 710 { 711 int result; 712 int err; 713 nvlist_t *auth; 714 char *val = NULL; 715 char *prod = NULL; 716 char *psn = NULL; 717 char *csn = NULL; 718 char *server = NULL; 719 720 if (mod == NULL || mdp == NULL || t_parent == NULL || t_node == NULL) { 721 return (-1); 722 } 723 724 result = topo_pgroup_create(t_node, &auth_pgroup, &err); 725 if (result != 0 && err != ETOPO_PROP_DEFD) { 726 /* 727 * We failed to create the property group and it was not 728 * already defined. Set the err code and return failure. 729 */ 730 topo_mod_seterrno(mod, err); 731 return (-1); 732 } 733 734 /* Get the authority information already available from the parent */ 735 auth = topo_mod_auth(mod, t_parent); 736 737 /* 738 * Set the authority data, inheriting it if possible, but creating it 739 * if necessary. 740 */ 741 742 /* product-id */ 743 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 744 FM_FMRI_AUTH_PRODUCT, &err); 745 if (result != 0 && err != ETOPO_PROP_DEFD) { 746 val = NULL; 747 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, 748 &val); 749 if (result != 0 || val == NULL) { 750 /* 751 * No product information in the parent node or auth 752 * list. Find the product information in the PRI. 753 */ 754 prod = pi_get_productid(mod, mdp); 755 if (prod == NULL) { 756 topo_mod_dprintf(mod, "pi_set_auth: product " 757 "name not found for node_0x%llx\n", 758 (uint64_t)mde_node); 759 } 760 } else { 761 /* 762 * Dup the string. If we cannot find it in the auth 763 * nvlist we will need to free it, so this lets us 764 * have a single code path. 765 */ 766 prod = topo_mod_strdup(mod, val); 767 } 768 769 /* 770 * We continue even if the product information is not available 771 * to enumerate as much as possible. 772 */ 773 if (prod != NULL) { 774 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 775 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 776 &err); 777 if (result != 0) { 778 /* Preserve the error and continue */ 779 topo_mod_seterrno(mod, err); 780 topo_mod_dprintf(mod, "pi_set_auth: failed to " 781 "set property %s (%d) : %s\n", 782 FM_FMRI_AUTH_CHASSIS, err, 783 topo_strerror(err)); 784 } 785 topo_mod_strfree(mod, prod); 786 } 787 } 788 789 /* product-sn */ 790 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 791 FM_FMRI_AUTH_PRODUCT_SN, &err); 792 if (result != 0 && err != ETOPO_PROP_DEFD) { 793 val = NULL; 794 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, 795 &val); 796 if (result != 0 || val == NULL) { 797 /* 798 * No product-sn information in the parent node or auth 799 * list. Find the product-sn information in the PRI. 800 */ 801 psn = pi_get_productsn(mod, mdp, mde_node); 802 if (psn == NULL) { 803 topo_mod_dprintf(mod, "pi_set_auth: psn " 804 "name not found for node_0x%llx\n", 805 (uint64_t)mde_node); 806 } 807 } else { 808 /* 809 * Dup the string. If we cannot find it in the auth 810 * nvlist we will need to free it, so this lets us 811 * have a single code path. 812 */ 813 psn = topo_mod_strdup(mod, val); 814 } 815 816 /* 817 * We continue even if the product information is not available 818 * to enumerate as much as possible. 819 */ 820 if (psn != NULL) { 821 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 822 FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn, 823 &err); 824 if (result != 0) { 825 /* Preserve the error and continue */ 826 topo_mod_seterrno(mod, err); 827 topo_mod_dprintf(mod, "pi_set_auth: failed to " 828 "set property %s (%d) : %s\n", 829 FM_FMRI_AUTH_PRODUCT_SN, err, 830 topo_strerror(err)); 831 } 832 topo_mod_strfree(mod, psn); 833 } 834 } 835 836 /* chassis-id */ 837 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 838 FM_FMRI_AUTH_CHASSIS, &err); 839 if (result != 0 && err != ETOPO_PROP_DEFD) { 840 val = NULL; 841 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, 842 &val); 843 if (result != 0 || val == NULL) { 844 /* 845 * No product information in the parent node or auth 846 * list. Find the product information in the PRI. 847 */ 848 csn = pi_get_chassisid(mod, mdp, mde_node); 849 if (csn == NULL) { 850 topo_mod_dprintf(mod, "pi_set_auth: csn " 851 "name not found for node_0x%llx\n", 852 (uint64_t)mde_node); 853 } 854 } else { 855 /* 856 * Dup the string. If we cannot find it in the auth 857 * nvlist we will need to free it, so this lets us 858 * have a single code path. 859 */ 860 csn = topo_mod_strdup(mod, val); 861 } 862 863 /* 864 * We continue even if the product information is not available 865 * to enumerate as much as possible. 866 */ 867 if (csn != NULL) { 868 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 869 FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn, 870 &err); 871 if (result != 0) { 872 /* Preserve the error and continue */ 873 topo_mod_seterrno(mod, err); 874 topo_mod_dprintf(mod, "pi_set_auth: failed to " 875 "set property %s (%d) : %s\n", 876 FM_FMRI_AUTH_CHASSIS, err, 877 topo_strerror(err)); 878 } 879 topo_mod_strfree(mod, csn); 880 } 881 } 882 883 /* server-id */ 884 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 885 FM_FMRI_AUTH_SERVER, &err); 886 if (result != 0 && err != ETOPO_PROP_DEFD) { 887 val = NULL; 888 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, 889 &val); 890 if (result != 0 || val == NULL) { 891 /* 892 * No product information in the parent node or auth 893 * list. Find the product information in the PRI. 894 */ 895 server = pi_get_serverid(mod); 896 if (server == NULL) { 897 topo_mod_dprintf(mod, "pi_set_auth: server " 898 "name not found for node_0x%llx\n", 899 (uint64_t)mde_node); 900 } 901 } else { 902 /* 903 * Dup the string. If we cannot find it in the auth 904 * nvlist we will need to free it, so this lets us 905 * have a single code path. 906 */ 907 server = topo_mod_strdup(mod, val); 908 } 909 910 /* 911 * We continue even if the product information is not available 912 * to enumerate as much as possible. 913 */ 914 if (server != NULL) { 915 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 916 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 917 &err); 918 if (result != 0) { 919 /* Preserve the error and continue */ 920 topo_mod_seterrno(mod, err); 921 topo_mod_dprintf(mod, "pi_set_auth: failed to " 922 "set property %s (%d) : %s\n", 923 FM_FMRI_AUTH_SERVER, err, 924 topo_strerror(err)); 925 } 926 topo_mod_strfree(mod, server); 927 } 928 } 929 930 nvlist_free(auth); 931 932 return (0); 933 } 934 935 936 /* 937 * Calculate a generic FRU for the given node. If the node is not a FRU, 938 * then inherit the FRU data from the nodes parent. 939 */ 940 int 941 pi_set_frufmri(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, 942 const char *name, topo_instance_t inst, tnode_t *t_parent, tnode_t *t_node) 943 { 944 int result; 945 int err; 946 int is_fru; 947 char *part; 948 char *rev; 949 char *serial; 950 nvlist_t *auth = NULL; 951 nvlist_t *frufmri = NULL; 952 953 if (t_node == NULL || mod == NULL || mdp == NULL) { 954 return (-1); 955 } 956 957 /* 958 * Determine if this node is a FRU 959 */ 960 result = pi_get_fru(mod, mdp, mde_node, &is_fru); 961 if (result != 0 || is_fru == 0) { 962 /* This node is not a FRU. Inherit from parent and return */ 963 topo_node_fru_set(t_node, NULL, 0, &result); 964 return (0); 965 } 966 967 /* 968 * This node is a FRU. Create an FMRI. 969 */ 970 part = pi_get_part(mod, mdp, mde_node); 971 rev = pi_get_revision(mod, mdp, mde_node); 972 serial = pi_get_serial(mod, mdp, mde_node); 973 auth = topo_mod_auth(mod, t_parent); 974 frufmri = topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION, name, 975 inst, NULL, auth, part, rev, serial); 976 if (frufmri == NULL) { 977 topo_mod_dprintf(mod, "failed to create FRU: %s\n", 978 topo_strerror(topo_mod_errno(mod))); 979 } 980 nvlist_free(auth); 981 topo_mod_strfree(mod, part); 982 topo_mod_strfree(mod, rev); 983 topo_mod_strfree(mod, serial); 984 985 /* Set the FRU, whether NULL or not */ 986 result = topo_node_fru_set(t_node, frufmri, 0, &err); 987 if (result != 0) { 988 topo_mod_seterrno(mod, err); 989 } 990 nvlist_free(frufmri); 991 992 return (result); 993 } 994 995 996 int 997 pi_set_label(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, tnode_t *t_node) 998 { 999 int result; 1000 int err; 1001 char *label; 1002 1003 if (mod == NULL || mdp == NULL) { 1004 return (-1); 1005 } 1006 1007 /* 1008 * Get the label, if any, from the mde node and apply it as the label 1009 * for this topology node. Note that a NULL label will inherit the 1010 * label from topology node's parent. 1011 */ 1012 label = pi_get_label(mod, mdp, mde_node); 1013 result = topo_node_label_set(t_node, label, &err); 1014 topo_mod_strfree(mod, label); 1015 if (result != 0) { 1016 topo_mod_seterrno(mod, err); 1017 topo_mod_dprintf(mod, "pi_set_label: failed with label %s " 1018 "on node_0x%llx: %s\n", (label == NULL ? "NULL" : label), 1019 (uint64_t)mde_node, topo_strerror(err)); 1020 } 1021 1022 return (result); 1023 } 1024 1025 1026 /* 1027 * Calculate the system information for a node. Inherit the data if 1028 * possible, but always create an appropriate property group. 1029 */ 1030 int 1031 pi_set_system(topo_mod_t *mod, tnode_t *t_node) 1032 { 1033 int result; 1034 int err; 1035 struct utsname uts; 1036 char isa[MAXNAMELEN]; 1037 1038 if (mod == NULL || t_node == NULL) { 1039 return (-1); 1040 } 1041 1042 result = topo_pgroup_create(t_node, &sys_pgroup, &err); 1043 if (result != 0 && err != ETOPO_PROP_DEFD) { 1044 /* 1045 * We failed to create the property group and it was not 1046 * already defined. Set the err code and return failure. 1047 */ 1048 topo_mod_seterrno(mod, err); 1049 return (-1); 1050 } 1051 1052 result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 1053 &err); 1054 if (result != 0 && err != ETOPO_PROP_DEFD) { 1055 isa[0] = '\0'; 1056 result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)); 1057 if (result == -1) { 1058 /* Preserve the error and continue */ 1059 topo_mod_dprintf(mod, "pi_set_system: failed to " 1060 "read SI_ARCHITECTURE: %d\n", errno); 1061 } 1062 if (strnlen(isa, MAXNAMELEN) > 0) { 1063 result = topo_prop_set_string(t_node, 1064 TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 1065 TOPO_PROP_IMMUTABLE, isa, &err); 1066 if (result != 0) { 1067 /* Preserve the error and continue */ 1068 topo_mod_seterrno(mod, err); 1069 topo_mod_dprintf(mod, "pi_set_auth: failed to " 1070 "set property %s (%d) : %s\n", 1071 TOPO_PROP_ISA, err, topo_strerror(err)); 1072 } 1073 } 1074 } 1075 1076 result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, 1077 TOPO_PROP_MACHINE, &err); 1078 if (result != 0 && err != ETOPO_PROP_DEFD) { 1079 result = uname(&uts); 1080 if (result == -1) { 1081 /* Preserve the error and continue */ 1082 topo_mod_seterrno(mod, errno); 1083 topo_mod_dprintf(mod, "pi_set_system: failed to " 1084 "read uname: %d\n", errno); 1085 } 1086 if (strnlen(uts.machine, sizeof (uts.machine)) > 0) { 1087 result = topo_prop_set_string(t_node, 1088 TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, 1089 TOPO_PROP_IMMUTABLE, uts.machine, &err); 1090 if (result != 0) { 1091 /* Preserve the error and continue */ 1092 topo_mod_seterrno(mod, err); 1093 topo_mod_dprintf(mod, "pi_set_auth: failed to " 1094 "set property %s (%d) : %s\n", 1095 TOPO_PROP_MACHINE, err, topo_strerror(err)); 1096 } 1097 } 1098 } 1099 1100 return (0); 1101 } 1102 1103 1104 tnode_t * 1105 pi_node_bind(topo_mod_t *mod, md_t *mdp, mde_cookie_t mde_node, 1106 tnode_t *t_parent, const char *hc_name, topo_instance_t inst, 1107 nvlist_t *fmri) 1108 { 1109 int result; 1110 tnode_t *t_node; 1111 1112 if (t_parent == NULL) { 1113 topo_mod_dprintf(mod, 1114 "cannot bind for node_0x%llx instance %d type %s\n", 1115 (uint64_t)mde_node, inst, hc_name); 1116 return (NULL); 1117 } 1118 1119 /* Bind this node to the parent */ 1120 t_node = topo_node_bind(mod, t_parent, hc_name, inst, fmri); 1121 if (t_node == NULL) { 1122 topo_mod_dprintf(mod, 1123 "failed to bind node_0x%llx instance %d: %s\n", 1124 (uint64_t)mde_node, (uint32_t)inst, 1125 topo_strerror(topo_mod_errno(mod))); 1126 return (NULL); 1127 } 1128 topo_mod_dprintf(mod, "bound node_0x%llx instance %d type %s\n", 1129 (uint64_t)mde_node, inst, hc_name); 1130 1131 /* 1132 * We have bound the node. Now decorate it with an appropriate 1133 * FRU and label (which may be inherited from the parent). 1134 */ 1135 result = pi_set_frufmri(mod, mdp, mde_node, hc_name, inst, t_parent, 1136 t_node); 1137 if (result != 0) { 1138 /* 1139 * Though we have failed to set the FRU FMRI we still continue. 1140 * The module errno is set by the called routine, so we report 1141 * the problem and move on. 1142 */ 1143 topo_mod_dprintf(mod, 1144 "failed to set FRU FMRI for node_0x%llx\n", 1145 (uint64_t)mde_node); 1146 } 1147 1148 result = pi_set_label(mod, mdp, mde_node, t_node); 1149 if (result != 0) { 1150 /* 1151 * Though we have failed to set the label, we still continue. 1152 * The module errno is set by the called routine, so we report 1153 * the problem and move on. 1154 */ 1155 topo_mod_dprintf(mod, "failed to set label for node_0x%llx\n", 1156 (uint64_t)mde_node); 1157 } 1158 1159 result = pi_set_auth(mod, mdp, mde_node, t_parent, t_node); 1160 if (result != 0) { 1161 /* 1162 * Though we have failed to set the authority, we still 1163 * continue. The module errno is set by the called routine, so 1164 * we report the problem and move on. 1165 */ 1166 topo_mod_dprintf(mod, "failed to set authority for " 1167 "node_0x%llx\n", (uint64_t)mde_node); 1168 } 1169 1170 result = pi_set_system(mod, t_node); 1171 if (result != 0) { 1172 /* 1173 * Though we have failed to set the system group, we still 1174 * continue. The module errno is set by the called routine, so 1175 * we report the problem and move on. 1176 */ 1177 topo_mod_dprintf(mod, "failed to set system for node_0x%llx\n", 1178 (uint64_t)mde_node); 1179 } 1180 1181 return (t_node); 1182 } 1183