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