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 * Opl Platform specific functions. 26 * 27 * called when : 28 * machine_type == MTYPE_OPL 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <ctype.h> 37 #include <string.h> 38 #include <varargs.h> 39 #include <fcntl.h> 40 #include <assert.h> 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 #include <sys/types.h> 44 #include <sys/utsname.h> 45 #include <sys/systeminfo.h> 46 #include <sys/openpromio.h> 47 #include <libintl.h> 48 #include <syslog.h> 49 #include <sys/dkio.h> 50 #include <pdevinfo.h> 51 #include <libprtdiag.h> 52 #include <libdevinfo.h> 53 #include <kstat.h> 54 55 /* 56 * Globals and externs 57 */ 58 #define KBYTE 1024 59 #define MBYTE (KBYTE * KBYTE) 60 #define HZ_TO_MHZ(x) ((((uint64_t)(x)) + 500000) / 1000000) 61 #define SCF_SECURE_MODE_KSTAT_NAMED "secure_mode" 62 #define SCF_STAT_MODE_UNLOCK 0 63 #define SCF_STAT_MODE_LOCK 1 64 #define SCF_SYSTEM_KSTAT_NAME "scf" 65 #ifndef TEXT_DOMAIN 66 #define TEXT_DOMAIN "SYS_TEST" 67 #endif /* TEXT_DOMAIN */ 68 #define IS_PCI_BRIDGE(name, type) \ 69 (((name) != NULL) && ((type) != NULL) && \ 70 (strncmp((name), "pci", 3) == 0) && \ 71 (strncmp((type), "pci", 3) == 0)) 72 73 /* 74 * Global functions and variables 75 * these functions will overlay the symbol table of libprtdiag 76 * at runtime (Opl systems only) 77 */ 78 struct cs_status { 79 int cs_number; 80 int status; 81 uint_t avail_hi; 82 uint_t avail_lo; 83 uint_t dimm_hi; 84 uint_t dimm_lo; 85 int dimms; 86 }; 87 88 int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag); 89 void *get_prop_val(Prop *prop); 90 void display_pci(Board_node *); 91 void display_ffb(Board_node *, int); 92 void display_sbus(Board_node *board); 93 void display_cpu_devices(Sys_tree *tree); 94 void display_cpus(Board_node *board); 95 void display_memoryconf(Sys_tree *tree, struct grp_info *grps); 96 void display_io_cards(struct io_card *list); 97 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 98 struct system_kstat_data *kstats); 99 Prop *find_prop(Prom_node *pnode, char *name); 100 101 /* Local functions */ 102 static void opl_disp_environ(void); 103 static void opl_disp_hw_revisions(Sys_tree *tree, Prom_node *root); 104 static uint64_t print_opl_memory_line(int lsb, struct cs_status *cs_stat, 105 int ngrps); 106 static uint64_t get_opl_mem_regs(Board_node *bnode); 107 void add_node(Sys_tree *root, Prom_node *pnode); 108 static int get_prop_size(Prop *prop); 109 110 /* 111 * Display all the leaf PCI nodes on this board that have "reg" property. 112 * If the "reg" property is NULL for a leaf node, skip parsing its sibling 113 * nodes and display the parent node properties. 114 */ 115 void 116 display_pci(Board_node *board) 117 { 118 struct io_card *card_list = NULL; 119 struct io_card card; 120 Prom_node *pci, *card_node; 121 char *name, *type; 122 int *int_val; 123 124 if (board == NULL) 125 return; 126 127 /* Initialize common information */ 128 card.board = board->board_num; 129 130 pci = board->nodes; 131 while (pci != NULL) { 132 name = get_node_name(pci); 133 134 /* Skip non-PCI board nodes */ 135 if ((name == NULL) || (strcmp(name, "pci") != 0)) { 136 pci = pci->sibling; 137 continue; 138 } 139 140 type = (char *)get_prop_val(find_prop(pci, "device_type")); 141 142 /* 143 * Skip PCI/ebus devices 144 * They have name == "pci" and type == "pci" 145 */ 146 if (strcmp(type, "pci") == 0) { 147 pci = pci->sibling; 148 continue; 149 } 150 151 card_node = pci; 152 while (card_node != NULL) { 153 int pci_parent_bridge = 0; 154 155 /* If it does have a child, skip to leaf child */ 156 if (card_node->child != NULL) { 157 card_node = card_node->child; 158 continue; 159 } 160 161 /* Get name of the card */ 162 name = (char *)get_prop_val(find_prop 163 (card_node, "name")); 164 165 /* Get type of card */ 166 type = (char *)get_prop_val(find_prop 167 (card_node, "device_type")); 168 169 /* Leaf pci-bridges are to be ignored */ 170 if (!IS_PCI_BRIDGE(name, type)) { 171 172 /* Get reg property of the node */ 173 int_val = (int *)get_prop_val(find_prop 174 (card_node, "reg")); 175 176 /* 177 * If no "reg" property check to see 178 * whether parent node has reg property. 179 * and check if parent is a bridge 180 */ 181 if (int_val == NULL) { 182 Prom_node *cparent = card_node->parent; 183 if (cparent == NULL) 184 break; 185 186 name = (char *)get_prop_val(find_prop 187 (cparent, "name")); 188 189 type = (char *)get_prop_val(find_prop 190 (cparent, "device_type")); 191 192 /* check if parent is a bridge */ 193 if (IS_PCI_BRIDGE(name, type)) 194 pci_parent_bridge = 1; 195 196 int_val = (int *)get_prop_val( 197 find_prop(cparent, "reg")); 198 199 if (int_val != NULL) 200 /* Switch to parent */ 201 card_node = cparent; 202 else 203 /* parent node has no reg */ 204 break; 205 } 206 207 if (!pci_parent_bridge) { 208 209 name = (char *)get_prop_val(find_prop 210 (card_node, "name")); 211 212 if (name == NULL) 213 card.name[0] = '\0'; 214 else { 215 (void) snprintf(card.name, 216 MAXSTRLEN, "%s", name); 217 } 218 219 /* Get the model of this card */ 220 name = (char *)get_prop_val(find_prop 221 (card_node, "model")); 222 223 if (name == NULL) { 224 (void) snprintf(card.model, 225 MAXSTRLEN, "%s", "N/A"); 226 } else { 227 (void) snprintf(card.model, 228 MAXSTRLEN, "%s", name); 229 } 230 231 /* insert card to the list */ 232 card_list = insert_io_card 233 (card_list, &card); 234 235 } 236 237 } 238 239 /* 240 * Parse sibling nodes. 241 * Then move up the parent's sibling upto the top 242 * intermediate node 243 * Stop if pci board node is reached. 244 */ 245 if (card_node->sibling != NULL) { 246 if (card_node == pci) 247 card_node = NULL; 248 else 249 card_node = card_node->sibling; 250 } else { 251 Prom_node *cparent; 252 cparent = card_node->parent; 253 card_node = NULL; 254 while (cparent != NULL) { 255 if (cparent == pci) 256 break; 257 if (cparent->sibling != NULL) { 258 card_node = cparent->sibling; 259 break; 260 } 261 cparent = cparent->parent; 262 } 263 } 264 265 } 266 267 /* On to the next board node */ 268 pci = pci->sibling; 269 270 } 271 272 display_io_cards(card_list); 273 free_io_cards(card_list); 274 } 275 276 /* 277 * There are no FFB's on OPL. 278 */ 279 /*ARGSUSED*/ 280 void 281 display_ffb(Board_node *board, int table) 282 { 283 } 284 285 /* 286 * There are no Sbus's on OPL. 287 */ 288 /*ARGSUSED*/ 289 void 290 display_sbus(Board_node *board) 291 { 292 } 293 294 /* 295 * Details of I/O information. Print out all the io cards. 296 */ 297 void 298 display_io_cards(struct io_card *list) 299 { 300 char *hdrfmt = "%-6.6s %-14.14s %-12.12s\n"; 301 302 struct io_card *p; 303 304 if (list == NULL) 305 return; 306 307 (void) textdomain(TEXT_DOMAIN); 308 309 log_printf(hdrfmt, gettext("LSB"), gettext("Name"), gettext("Model"), 310 0); 311 312 log_printf(hdrfmt, "---", "-----------------", "------------", 0); 313 314 for (p = list; p != NULL; p = p->next) { 315 316 /* Board number */ 317 log_printf(" %02d ", p->board, 0); 318 319 /* Card name */ 320 log_printf("%-15.15s", p->name, 0); 321 322 /* Card model */ 323 log_printf("%-12.12s", p->model, 0); 324 325 log_printf("\n", 0); 326 } 327 log_printf("\n", 0); 328 } 329 330 /* 331 * Details of CPU information. 332 */ 333 void 334 display_cpu_devices(Sys_tree *tree) 335 { 336 Board_node *bnode; 337 char *hdrfmt = 338 "%-5.5s %-8.8s %-20.20s %-8.8s %-8.8s %-8.8s %-8.8s\n"; 339 340 (void) textdomain(TEXT_DOMAIN); 341 342 /* 343 * Display the table header for CPUs . Then display the CPU 344 * frequency, cache size, and processor revision of all cpus. 345 */ 346 log_printf("\n", 0); 347 log_printf("====================================", 0); 348 log_printf(gettext(" CPUs "), 0); 349 log_printf("====================================", 0); 350 log_printf("\n\n", 0); 351 352 log_printf(hdrfmt, 353 "", 354 gettext("CPU"), 355 gettext(" CPU "), 356 gettext("Run"), 357 gettext("L2$"), 358 gettext("CPU"), 359 gettext("CPU"), 0); 360 361 log_printf(hdrfmt, 362 gettext("LSB"), 363 gettext("Chip"), 364 gettext(" ID "), 365 gettext("MHz"), 366 gettext(" MB"), 367 gettext("Impl."), 368 gettext("Mask"), 0); 369 370 log_printf(hdrfmt, 371 "---", "----", "--------------------", "----", 372 "---", "-----", "----", 0); 373 374 /* Now display all of the cpus on each board */ 375 for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) { 376 display_cpus(bnode); 377 } 378 379 log_printf("\n", 0); 380 } 381 382 /* 383 * Display the CPUs present on this board. 384 */ 385 void 386 display_cpus(Board_node *board) 387 { 388 int *impl, *mask, *cpuid, *portid, *l2cache_size; 389 uint_t freq; /* CPU clock frequency */ 390 Prom_node *pnode, *cpu; 391 char *name; 392 393 (void) textdomain(TEXT_DOMAIN); 394 395 /* 396 * Get the Cpus' properties for display 397 */ 398 for (pnode = board->nodes; pnode != NULL; pnode = pnode->sibling) { 399 char cpu_str[MAXSTRLEN], fcpu_str[MAXSTRLEN] = {0}; 400 401 name = get_node_name(pnode); 402 if ((name == NULL) || (strncmp(name, "cmp", 3) != 0)) { 403 continue; 404 } 405 406 portid = (int *)get_prop_val(find_prop(pnode, "portid")); 407 freq = (HZ_TO_MHZ(get_cpu_freq(pnode->child))); 408 l2cache_size = 409 (int *)get_prop_val 410 (find_prop(pnode->child, "l2-cache-size")); 411 impl = 412 (int *)get_prop_val 413 (find_prop(pnode->child, "implementation#")); 414 mask = (int *)get_prop_val(find_prop(pnode->child, "mask#")); 415 416 /* Lsb id */ 417 log_printf(" %02d ", board->board_num, 0); 418 419 if (portid != NULL) 420 log_printf("%3d ", (((*portid)>>3)&0x3), 0); 421 422 /* 423 * Specific parsing of the CMP/CORE/CPU chain. 424 * The internal cpu tree built by walk_di_tree() 425 * in common code can be illustrated by the diagram 426 * below: 427 * 428 * cmp->cpu->cpu->cpu->cpu->(next board nodes) 429 * / \ 430 * core core 431 * where "/" or "\" are children 432 * and "->" are siblings 433 */ 434 for (cpu = pnode->sibling; cpu != NULL; ) { 435 Prom_node *cpu_next = NULL; 436 437 name = get_node_name(cpu); 438 if ((name == NULL) || (strncmp(name, "cpu", 3) != 0)) { 439 break; 440 } 441 442 /* Id assigned to Virtual processor core */ 443 cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid")); 444 cpu_next = cpu->sibling; 445 446 if (cpu_next != NULL) { 447 name = get_node_name(cpu_next); 448 449 if ((name == NULL) || 450 (strncmp(name, "cpu", 3) != 0)) { 451 cpu_next = NULL; 452 } 453 } 454 455 if (cpuid != NULL) { 456 /* Used for printing in comma format */ 457 (void) sprintf(cpu_str, "%4d", *cpuid); 458 (void) strlcat(fcpu_str, cpu_str, MAXSTRLEN); 459 460 if (cpu_next != NULL) 461 (void) strlcat(fcpu_str, ",", MAXSTRLEN); 462 } else { 463 (void) sprintf(cpu_str, "%4s", "N/A"); 464 (void) strlcat(fcpu_str, cpu_str, MAXSTRLEN); 465 466 if (cpu_next != NULL) 467 (void) strlcat(fcpu_str, ",", MAXSTRLEN); 468 } 469 cpu = cpu_next; 470 } 471 472 log_printf("%-20.20s", fcpu_str, 0); 473 474 /* Running frequency */ 475 if (freq != 0) 476 log_printf(" %4ld ", freq, 0); 477 else 478 log_printf(" %4s ", "N/A", 0); 479 480 /* L2 cache size */ 481 if (l2cache_size == NULL) 482 log_printf(" %3s ", "N/A", 0); 483 else { 484 log_printf("%4.1f ", 485 (float)(*l2cache_size) / (float)(1<<20), 0); 486 } 487 488 489 /* Implementation number of processor */ 490 if (impl != NULL) 491 log_printf("%4d ", *impl, 0); 492 else 493 log_printf("%4s ", "N/A", 0); 494 495 /* Mask Set version */ 496 /* Bits 31:24 of VER register is mask. */ 497 /* Mask value : Non MTP mode - 00-7f, MTP mode - 80-ff */ 498 if (mask == NULL) 499 log_printf("%4s", "N/A", 0); 500 else 501 log_printf("%4d", (*mask)&0xff, 0); 502 503 log_printf("\n", 0); 504 505 } 506 } 507 508 /* 509 * Gather memory information: Details of memory information. 510 */ 511 static uint64_t 512 get_opl_mem_regs(Board_node *bnode) 513 { 514 Prom_node *pnode; 515 struct cs_status *cs_stat; 516 uint64_t total_mem = 0; 517 int cs_size, ngrps; 518 519 pnode = dev_find_node(bnode->nodes, "pseudo-mc"); 520 while (pnode != NULL) { 521 522 cs_size = get_prop_size(find_prop(pnode, "cs-status")); 523 524 if (cs_size > 0) { 525 526 /* OBP returns lists of 7 ints */ 527 cs_stat = (struct cs_status *)get_prop_val 528 (find_prop(pnode, "cs-status")); 529 530 /* 531 * The units of cs_size will be either number of bytes 532 * or number of int array elements as this is derived 533 * from the libprtdiag Prop node size field which has 534 * inconsistent units. Until this is addressed in 535 * libprtdiag, we need a heuristic to determine the 536 * number of CS groups. Given that the maximum number 537 * of CS groups is 2, the maximum number of cs-status 538 * array elements will be 2*7=14. Since this is smaller 539 * than the byte size of a single struct status, we use 540 * this to decide if we are dealing with bytes or array 541 * elements in determining the number of CS groups. 542 */ 543 if (cs_size < sizeof (struct cs_status)) { 544 /* cs_size is number of total int [] elements */ 545 ngrps = cs_size / 7; 546 } else { 547 /* cs_size is total byte count */ 548 ngrps = cs_size/sizeof (struct cs_status); 549 } 550 551 if (cs_stat != NULL) { 552 total_mem += 553 print_opl_memory_line(bnode->board_num, 554 cs_stat, ngrps); 555 } 556 } 557 558 pnode = dev_next_node(pnode, "pseudo-mc"); 559 } 560 return (total_mem); 561 } 562 563 /* 564 * Display memory information. 565 */ 566 /*ARGSUSED*/ 567 void 568 display_memoryconf(Sys_tree *tree, struct grp_info *grps) 569 { 570 Board_node *bnode = tree->bd_list; 571 uint64_t total_mem = 0, total_sys_mem = 0; 572 char *hdrfmt = "\n%-5.5s %-6.6s %-18.18s %-10.10s" 573 " %-8.8s %-10.10s"; 574 575 (void) textdomain(TEXT_DOMAIN); 576 577 log_printf("======================", 0); 578 log_printf(gettext(" Memory Configuration "), 0); 579 log_printf("======================", 0); 580 log_printf("\n", 0); 581 582 log_printf(hdrfmt, 583 "", 584 gettext("Memory"), 585 gettext("Available"), 586 gettext("Memory"), 587 gettext("DIMM"), 588 gettext("Number of"), 589 0); 590 591 log_printf(hdrfmt, 592 gettext("LSB"), 593 gettext("Group"), 594 gettext("Size"), 595 gettext("Status"), 596 gettext("Size"), 597 gettext("DIMMs"), 0); 598 599 log_printf(hdrfmt, 600 "---", "-------", "------------------", "-------", "------", 601 "---------", 0); 602 603 log_printf("\n", 0); 604 605 for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) { 606 total_mem += get_opl_mem_regs(bnode); 607 } 608 609 /* 610 * Sanity check to ensure that the total amount of system 611 * memory matches the total number of memory that 612 * we find here. Display error message if there is a mis-match. 613 */ 614 total_sys_mem = (((uint64_t)sysconf(_SC_PAGESIZE) * (uint64_t)sysconf 615 (_SC_PHYS_PAGES)) / MBYTE); 616 617 if (total_mem != total_sys_mem) { 618 log_printf(dgettext(TEXT_DOMAIN, 619 "\nError:total available size [%lldMB] does not match" 620 " total system memory [%lldMB]\n"), 621 total_mem, total_sys_mem, 0); 622 } 623 624 } 625 626 /* 627 * This function provides Opl's formatting of the memory config 628 * information that get_opl_mem_regs() has gathered. 629 */ 630 static uint64_t 631 print_opl_memory_line(int lsb, struct cs_status *cs_stat, int ngrps) 632 { 633 int i; 634 uint64_t total_board_mem = 0; 635 636 (void) textdomain(TEXT_DOMAIN); 637 638 for (i = 0; i < ngrps; i++) { 639 uint64_t mem_size; 640 641 mem_size = ((((uint64_t)cs_stat[i].avail_hi)<<32) + 642 cs_stat[i].avail_lo); 643 644 if (mem_size == 0) 645 continue; 646 647 /* Lsb Id */ 648 log_printf(" %02d ", lsb, 0); 649 650 /* Memory Group Number */ 651 if ((cs_stat[i].cs_number) == 0) 652 log_printf("%-6.6s", "A", 0); 653 else 654 log_printf("%-6.6s", "B", 0); 655 656 /* Memory Group Size */ 657 log_printf("%8lldMB ", mem_size/MBYTE, 0); 658 659 total_board_mem += (mem_size/MBYTE); 660 661 /* Memory Group Status */ 662 log_printf("%-11.11s", 663 cs_stat[i].status ? "partial": "okay", 0); 664 665 /* DIMM Size */ 666 log_printf("%4lldMB ", 667 ((((uint64_t)cs_stat[i].dimm_hi)<<32) 668 + cs_stat[i].dimm_lo)/MBYTE, 0); 669 670 /* Number of DIMMs */ 671 log_printf(" %2d\n", cs_stat[i].dimms); 672 } 673 return (total_board_mem); 674 } 675 676 /* 677 * Details of hardware revision and environmental status. 678 */ 679 /*ARGSUSED*/ 680 void 681 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 682 struct system_kstat_data *kstats) 683 { 684 /* Print the PROM revisions */ 685 if (flag) 686 opl_disp_hw_revisions(tree, root); 687 } 688 689 /* 690 * Gather and display hardware revision and environmental status 691 */ 692 /*ARGSUSED*/ 693 static void 694 opl_disp_hw_revisions(Sys_tree *tree, Prom_node *root) 695 { 696 char *version; 697 Prom_node *pnode; 698 699 (void) textdomain(TEXT_DOMAIN); 700 701 /* Print the header */ 702 log_printf("\n", 0); 703 log_printf("====================", 0); 704 log_printf(gettext(" Hardware Revisions "), 0); 705 log_printf("====================", 0); 706 log_printf("\n\n", 0); 707 708 /* Display Prom revision header */ 709 log_printf(gettext("System PROM revisions:"), 0); 710 log_printf("\n----------------------\n", 0); 711 log_printf("\n", 0); 712 713 /* Display OBP version info */ 714 pnode = dev_find_node(root, "openprom"); 715 if (pnode != NULL) { 716 version = (char *)get_prop_val(find_prop(pnode, "version")); 717 if (version != NULL) 718 log_printf("%s\n\n", version, 0); 719 else 720 log_printf("%s\n\n", "N/A", 0); 721 } 722 723 /* Print the header */ 724 log_printf("\n", 0); 725 log_printf("===================", 0); 726 log_printf(gettext(" Environmental Status "), 0); 727 log_printf("===================", 0); 728 log_printf("\n\n", 0); 729 730 opl_disp_environ(); 731 } 732 733 /* 734 * Gather environmental information 735 */ 736 static void 737 opl_disp_environ(void) 738 { 739 kstat_ctl_t *kc; 740 kstat_t *ksp; 741 kstat_named_t *k; 742 743 if ((kc = kstat_open()) == NULL) 744 return; 745 746 if ((ksp = kstat_lookup 747 (kc, "scfd", 0, SCF_SYSTEM_KSTAT_NAME)) == NULL) { 748 (void) kstat_close(kc); 749 return; 750 } 751 752 if (kstat_read(kc, ksp, NULL) == -1) { 753 (void) kstat_close(kc); 754 return; 755 } 756 757 if ((k = (kstat_named_t *)kstat_data_lookup 758 (ksp, SCF_SECURE_MODE_KSTAT_NAMED)) == NULL) { 759 (void) kstat_close(kc); 760 return; 761 } 762 763 if (k->value.c[0] == SCF_STAT_MODE_LOCK) 764 log_printf("Mode switch is in LOCK mode ", 0); 765 else if (k->value.c[0] == SCF_STAT_MODE_UNLOCK) 766 log_printf("Mode switch is in UNLOCK mode", 0); 767 else 768 log_printf("Mode switch is in UNKNOWN mode", 0); 769 770 log_printf("\n", 0); 771 772 (void) kstat_close(kc); 773 } 774 775 776 /* 777 * Calls do_devinfo() in order to use the libdevinfo device tree 778 * instead of OBP's device tree. 779 */ 780 int 781 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 782 { 783 return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); 784 } 785 786 /* 787 * Return the property value for the Prop 788 * passed in. (When using libdevinfo) 789 */ 790 void * 791 get_prop_val(Prop *prop) 792 { 793 if (prop == NULL) 794 return (NULL); 795 796 return ((void *)(prop->value.val_ptr)); 797 } 798 799 /* 800 * Return the property size for the Prop 801 * passed in. (When using libdevinfo) 802 */ 803 static int 804 get_prop_size(Prop *prop) 805 { 806 807 if ((prop != NULL) && (prop->size > 0)) 808 return (prop->size); 809 else 810 return (0); 811 } 812 813 814 /* 815 * Search a Prom node and retrieve the property with the correct 816 * name. (When using libdevinfo) 817 */ 818 Prop * 819 find_prop(Prom_node *pnode, char *name) 820 { 821 Prop *prop; 822 823 if (pnode == NULL) 824 return (NULL); 825 826 for (prop = pnode->props; prop != NULL; prop = prop->next) { 827 if (prop->name.val_ptr != NULL && 828 strcmp((char *)(prop->name.val_ptr), name) == 0) 829 break; 830 } 831 832 return (prop); 833 } 834 835 /* 836 * This function adds a board node to the board structure where that 837 * that node's physical component lives. 838 */ 839 void 840 add_node(Sys_tree *root, Prom_node *pnode) 841 { 842 int board; 843 Board_node *bnode; 844 Prom_node *p; 845 char *type; 846 847 if ((board = get_board_num(pnode)) == -1) { 848 type = get_node_type(pnode); 849 if ((type != NULL) && (strcmp(type, "cpu") == 0)) 850 board = get_board_num((pnode->parent)->parent); 851 } 852 853 /* find the node with the same board number */ 854 if ((bnode = find_board(root, board)) == NULL) { 855 bnode = insert_board(root, board); 856 bnode->board_type = UNKNOWN_BOARD; 857 } 858 859 /* now attach this prom node to the board list */ 860 /* Insert this node at the end of the list */ 861 pnode->sibling = NULL; 862 if (bnode->nodes == NULL) 863 bnode->nodes = pnode; 864 else { 865 p = bnode->nodes; 866 while (p->sibling != NULL) 867 p = p->sibling; 868 p->sibling = pnode; 869 } 870 871 } 872