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