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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2020 Peter Tribble. 25 */ 26 27 /* 28 * 29 * Cherrystone platform-specific functions 30 * 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <kstat.h> 37 #include <string.h> 38 #include <assert.h> 39 #include <libintl.h> 40 #include <note.h> 41 #include <syslog.h> 42 43 #include <sys/openpromio.h> 44 #include <sys/sysmacros.h> 45 46 #include <pdevinfo.h> 47 #include <display.h> 48 #include <pdevinfo_sun4u.h> 49 #include <display_sun4u.h> 50 51 #include <picl.h> 52 53 #include <sys/cheetahregs.h> 54 #include <sys/cherrystone.h> 55 #include "workfile.c" 56 57 #define SCHIZO_COMPAT_PROP "pci108e,8001" 58 59 #define MULTIPLE_BITS_SET(x) ((x)&((x)-1)) 60 61 #define MAX_PS 2 62 #define MAX_PS_SENSORS 3 63 #define MAX_DISKS 2 64 #define MAX_FANS 5 65 #define NUM_PCI_SLOTS 5 66 67 /* 68 * these functions will overlay the symbol table of libprtdiag 69 * at runtime (workgroup server systems only) 70 */ 71 void display_cpu_devices(Sys_tree *tree); 72 void display_pci(Board_node *board); 73 void display_io_cards(struct io_card *list); 74 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 75 struct system_kstat_data *kstats); 76 void display_ffb(Board_node *board, int table); 77 void display_memoryconf(Sys_tree *tree); 78 79 /* local functions */ 80 static void disp_envc_status(void); 81 static int print_temps(picl_nodehdl_t); 82 static int print_keyswitch(picl_nodehdl_t); 83 static int print_FSP_LEDS(picl_nodehdl_t); 84 static int print_disk(picl_nodehdl_t); 85 static int print_fans(picl_nodehdl_t); 86 static int print_ps(picl_nodehdl_t); 87 88 static void display_hw_revisions(Prom_node *root, 89 Board_node *bnode); 90 static void display_schizo_revisions(Board_node *bdlist); 91 92 93 void 94 display_cpu_devices(Sys_tree *tree) 95 { 96 Board_node *bnode; 97 98 log_printf(dgettext(TEXT_DOMAIN, 99 "\n========================= CPUs " 100 "===============================================\n\n" 101 " Run E$ CPU CPU \n" 102 "Brd CPU MHz MB Impl. Mask \n" 103 "--- ----- ---- ---- ------- ---- \n")); 104 105 bnode = tree->bd_list; 106 while (bnode != NULL) { 107 display_cpus(bnode); 108 bnode = bnode->next; 109 } 110 111 log_printf("\n"); 112 } 113 void 114 display_cpus(Board_node *board) 115 { 116 Prom_node *cpu; 117 uint_t freq; 118 int ecache_size; 119 int *l3_shares; 120 int *mid; 121 int *impl; 122 int *mask; 123 int *coreid; 124 char fru_prev = 'X'; /* Valid frus are 'A','B' */ 125 int mid_prev; 126 int ecache_size_prev = 0; 127 char fru_name; 128 129 /* 130 * display the CPUs' operating frequency, cache size, impl. field 131 * and mask revision. 132 */ 133 134 for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL; 135 cpu = dev_next_type(cpu, "cpu")) { 136 137 mid = (int *)get_prop_val(find_prop(cpu, "portid")); 138 if (mid == NULL) 139 mid = (int *)get_prop_val(find_prop(cpu, "cpuid")); 140 freq = HZ_TO_MHZ(get_cpu_freq(cpu)); 141 ecache_size = get_ecache_size(cpu); 142 impl = (int *)get_prop_val(find_prop(cpu, "implementation#")); 143 mask = (int *)get_prop_val(find_prop(cpu, "mask#")); 144 l3_shares = 145 (int *)get_prop_val(find_prop(cpu, "l3-cache-sharing")); 146 147 /* Do not display a failed CPU node */ 148 if ((impl == NULL) || (freq == 0) || (node_failed(cpu))) 149 continue; 150 151 fru_name = CHERRYSTONE_GETSLOT_LABEL(*mid); 152 if (CPU_IMPL_IS_CMP(*impl)) { 153 coreid = (int *)get_prop_val(find_prop(cpu, "reg")); 154 if (coreid == NULL) { 155 continue; 156 } 157 if ((fru_prev == 'X') || 158 ((fru_prev != 'X') && 159 (fru_name != fru_prev))) { 160 fru_prev = fru_name; 161 mid_prev = *mid; 162 ecache_size_prev = ecache_size; 163 continue; 164 } else { 165 /* 166 * Some CMP chips have a split E$, 167 * so the size for both cores is added 168 * together to get the total size for 169 * the chip. 170 * 171 * Still, other CMP chips have E$ (L3) 172 * which is logically shared, so the 173 * total size is equal to the core size. 174 */ 175 if ((l3_shares == NULL) || 176 ((l3_shares != NULL) && 177 MULTIPLE_BITS_SET(*l3_shares))) { 178 ecache_size += ecache_size_prev; 179 } 180 ecache_size_prev = 0; 181 fru_prev = 'X'; 182 } 183 } 184 185 log_printf(" %c", fru_name); 186 187 /* CPU Module ID */ 188 if (CPU_IMPL_IS_CMP(*impl)) { 189 log_printf("%3d,%3d ", mid_prev, *mid, 0); 190 } else 191 log_printf(" %2d ", *mid); 192 193 /* Running frequency */ 194 log_printf("%4u", freq); 195 196 if (ecache_size == 0) 197 log_printf(" N/A "); 198 else 199 log_printf(" %4.1f ", 200 (float)ecache_size / (float)(1<<20)); 201 /* Implementation */ 202 if (impl == NULL) { 203 log_printf(dgettext(TEXT_DOMAIN, " N/A ")); 204 } else { 205 if (IS_CHEETAH(*impl)) 206 log_printf(dgettext(TEXT_DOMAIN, 207 "US-III ")); 208 else if (IS_CHEETAH_PLUS(*impl)) 209 log_printf(dgettext(TEXT_DOMAIN, 210 "US-III+ ")); 211 else if (IS_JAGUAR(*impl)) 212 log_printf(dgettext(TEXT_DOMAIN, 213 "US-IV ")); 214 else if (IS_PANTHER(*impl)) 215 log_printf(dgettext(TEXT_DOMAIN, 216 "US-IV+ ")); 217 else 218 log_printf("%-6x ", *impl); 219 } 220 221 /* CPU Mask */ 222 if (mask == NULL) { 223 log_printf(dgettext(TEXT_DOMAIN, " N/A\n")); 224 } else { 225 log_printf(dgettext(TEXT_DOMAIN, " %d.%d\n"), 226 (*mask >> 4) & 0xf, *mask & 0xf); 227 } 228 } 229 } 230 231 void 232 display_memoryconf(Sys_tree *tree) 233 { 234 Board_node *bnode = tree->bd_list; 235 236 log_printf(dgettext(TEXT_DOMAIN, 237 "========================= Memory Configuration" 238 " ===============================\n\n" 239 " Logical Logical Logical\n" 240 " MC Bank Bank Bank DIMM " 241 "Interleave Interleaved\n" 242 "Brd ID num size Status Size " 243 "Factor with\n" 244 "--- --- ---- ------ ----------- ------ " 245 "---------- -----------")); 246 247 while (bnode != NULL) { 248 if (get_us3_mem_regs(bnode)) { 249 log_printf(dgettext(TEXT_DOMAIN, 250 "\nFailed to get memory information.\n")); 251 return; 252 } 253 bnode = bnode->next; 254 } 255 256 /* Display what we have found */ 257 display_us3_banks(); 258 } 259 260 /*ARGSUSED3*/ 261 void 262 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 263 struct system_kstat_data *kstats) 264 { 265 /* 266 * Now display the last powerfail time and the fatal hardware 267 * reset information. We do this under a couple of conditions. 268 * First if the user asks for it. The second is if the user 269 * told us to do logging, and we found a system failure. 270 */ 271 272 if (flag) { 273 /* 274 * display time of latest powerfail. Not all systems 275 * have this capability. For those that do not, this 276 * is just a no-op. 277 */ 278 disp_powerfail(root); 279 280 disp_envc_status(); 281 282 display_hw_revisions(root, tree->bd_list); 283 } 284 return; 285 286 } 287 288 /* 289 * display_pci 290 * Display all the PCI IO cards on this board. 291 */ 292 void 293 display_pci(Board_node *board) 294 { 295 struct io_card *card_list = NULL; 296 struct io_card card; 297 void *value; 298 Prom_node *pci; 299 Prom_node *card_node; 300 static int banner = FALSE; 301 302 char *slot_name_arr[NUM_PCI_SLOTS]; 303 int i; 304 305 if (board == NULL) 306 return; 307 308 (void) memset(&card, 0, sizeof (struct io_card)); 309 /* Initialize all the common information */ 310 card.display = TRUE; 311 card.board = board->board_num; 312 313 /* 314 * Search for each pci instance, then find/display all nodes under 315 * each instance node found. 316 */ 317 for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP); 318 pci != NULL; 319 pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) { 320 (void) snprintf(card.bus_type, MAXSTRLEN, 321 dgettext(TEXT_DOMAIN, "PCI")); 322 /* 323 * Get slot-name properties from parent node and 324 * store them in an array. 325 */ 326 value = (char *)get_prop_val( 327 find_prop(pci, "slot-names")); 328 329 if (value != NULL) { 330 /* array starts after first int */ 331 slot_name_arr[0] = (char *)value + sizeof (int); 332 for (i = 1; i < NUM_PCI_SLOTS; i++) { 333 slot_name_arr[i] = (char *)slot_name_arr[i - 1] 334 + strlen(slot_name_arr[i - 1]) +1; 335 } 336 } 337 /* 338 * Search for Children of this node ie. Cards. 339 * Note: any of these cards can be a pci-bridge 340 * that itself has children. If we find a 341 * pci-bridge we need to handle it specially. 342 */ 343 card_node = pci->child; 344 /* Generate the list of pci cards on pci instance: pci */ 345 fill_pci_card_list(pci, card_node, &card, &card_list, 346 slot_name_arr); 347 } /* end-for */ 348 349 if (!banner && card_list != NULL) { 350 log_printf(dgettext(TEXT_DOMAIN, 351 " Bus Max\n" 352 " IO Port Bus Freq Bus Dev,\n" 353 "Type ID Side Slot MHz Freq Func State " 354 "Name Model" 355 #ifdef DEBUG 356 " Notes" 357 #endif 358 "\n" 359 "---- ---- ---- ---- ---- ---- ---- ----- " 360 "-------------------------------- " 361 #ifdef DEBUG 362 "---------------------- " 363 #endif 364 "----------------------\n")); 365 banner = TRUE; 366 } 367 368 display_io_cards(card_list); 369 free_io_cards(card_list); 370 } 371 372 /* 373 * Print out all the io cards in the list. Also print the column 374 * headers if told to do so. 375 */ 376 void 377 display_io_cards(struct io_card *list) 378 { 379 struct io_card *p; 380 381 for (p = list; p != NULL; p = p -> next) { 382 log_printf(dgettext(TEXT_DOMAIN, 383 "%-4s %-3d %c %-1s %-3d"), 384 p->bus_type, p->schizo_portid, p->pci_bus, 385 p->slot_str, p->freq); 386 387 switch (p->pci_bus) { 388 case 'A': 389 log_printf(dgettext(TEXT_DOMAIN, " 66 ")); 390 break; 391 case 'B': 392 log_printf(dgettext(TEXT_DOMAIN, " 33 ")); 393 break; 394 default: 395 assert(0); 396 break; 397 } 398 399 log_printf(dgettext(TEXT_DOMAIN, 400 "%-1d,%-1d %-5s %-32.32s"), 401 p->dev_no, p->func_no, p->status, p->name); 402 if (strlen(p->name) > 32) 403 log_printf(dgettext(TEXT_DOMAIN, "+ ")); 404 else 405 log_printf(dgettext(TEXT_DOMAIN, " ")); 406 log_printf(dgettext(TEXT_DOMAIN, "%-22.22s"), p->model); 407 if (strlen(p->model) > 22) 408 log_printf(dgettext(TEXT_DOMAIN, "+")); 409 #ifdef DEBUG 410 log_printf("%s", p->notes); 411 #endif 412 log_printf("\n"); 413 } 414 } 415 416 /*ARGSUSED*/ 417 void 418 display_ffb(Board_node *board, int table) 419 { 420 /* NOP, since there are no FFB's on this platform. */ 421 } 422 423 424 /* 425 * local functions 426 */ 427 428 429 static void 430 disp_envc_status() 431 { 432 int err; 433 char *system = "SYSTEM"; 434 picl_nodehdl_t system_node, root; 435 436 log_printf(dgettext(TEXT_DOMAIN, 437 "\n" 438 "========================= Environmental Status " 439 "=========================\n\n")); 440 441 err = picl_initialize(); 442 if (err != PICL_SUCCESS) { 443 exit_code = PD_INTERNAL_FAILURE; 444 goto err_out; 445 } 446 err = picl_get_root(&root); 447 if (err != PICL_SUCCESS) { 448 exit_code = PD_INTERNAL_FAILURE; 449 goto err_out; 450 } 451 err = find_child_device(root, system, &system_node); 452 if (err != PICL_SUCCESS) { 453 exit_code = PD_INTERNAL_FAILURE; 454 goto err_out; 455 } 456 457 err = print_temps(system_node); 458 err |= print_keyswitch(system_node); 459 err |= print_FSP_LEDS(system_node); 460 err |= print_disk(system_node); 461 err |= print_fans(system_node); 462 err |= print_ps(system_node); 463 464 if (err != PICL_SUCCESS) 465 goto err_out; 466 467 return; 468 469 err_out: 470 log_printf(dgettext(TEXT_DOMAIN, 471 "\nEnvironmental reporting error: %s\n"), 472 picl_strerror(err)); 473 } 474 475 static int 476 print_ps(picl_nodehdl_t system_node) 477 { 478 int i, j, err = 0; 479 int32_t number; 480 picl_nodehdl_t *ps; 481 picl_nodehdl_t *ps_fail_sensor; 482 char name[PICL_PROPNAMELEN_MAX]; 483 char fault_state[PICL_PROPNAMELEN_MAX]; 484 485 log_printf(dgettext(TEXT_DOMAIN, "\n\n" 486 "Power Supplies:\n" 487 "---------------\n" 488 "\n" 489 "Supply Status Fault Fan Fail Temp Fail\n" 490 "------ ------------ -------- --------- ---------\n")); 491 492 err = fill_device_array_from_id(system_node, "PSVC_PS", &number, &ps); 493 if (err != PICL_SUCCESS) { 494 return (err); 495 } 496 497 for (i = 0; i < MAX_PS; i++) { 498 err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name, 499 PICL_PROPNAMELEN_MAX); 500 if (err != PICL_SUCCESS) 501 continue; 502 503 log_printf(dgettext(TEXT_DOMAIN, "%6-s"), name); 504 err = picl_get_propval_by_name(ps[i], "FaultInformation", 505 fault_state, PICL_PROPNAMELEN_MAX); 506 if (err != PICL_SUCCESS) { 507 free(ps); 508 return (err); 509 } 510 log_printf(dgettext(TEXT_DOMAIN, " [%-12s]"), fault_state); 511 if (strcmp(fault_state, "NO AC POWER") == 0) { 512 log_printf("\n"); 513 continue; 514 } 515 516 err = fill_device_array_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR", 517 &number, &ps_fail_sensor); 518 519 if (err != PICL_SUCCESS) { 520 free(ps); 521 return (err); 522 } 523 log_printf(" "); 524 for (j = 0; j < MAX_PS_SENSORS; j++) { 525 err = picl_get_propval_by_name(ps_fail_sensor[j], 526 "State", fault_state, PICL_PROPNAMELEN_MAX); 527 if (err != PICL_SUCCESS) { 528 if (err == PICL_FAILURE) { 529 break; 530 } 531 free(ps); 532 free(ps_fail_sensor); 533 return (err); 534 } 535 log_printf(dgettext(TEXT_DOMAIN, "%-10s"), fault_state); 536 } 537 log_printf("\n"); 538 free(ps_fail_sensor); 539 } 540 541 log_printf(dgettext(TEXT_DOMAIN, 542 "\n=================================\n\n")); 543 544 free(ps); 545 return (PICL_SUCCESS); 546 } 547 548 static int 549 print_fans(picl_nodehdl_t system_node) 550 { 551 int i, err; 552 int32_t number; 553 picl_nodehdl_t *fans; 554 picl_nodehdl_t phdl; 555 char prop[PICL_PROPNAMELEN_MAX]; 556 char parent[PICL_PROPNAMELEN_MAX]; 557 int32_t rpm; 558 559 err = fill_device_array_from_id(system_node, "PSVC_FAN", &number, 560 &fans); 561 if (err != PICL_SUCCESS) { 562 return (err); 563 } 564 565 log_printf(dgettext(TEXT_DOMAIN, 566 "\n=================================\n\n" 567 "Fan Status:\n" 568 "-----------\n\n" 569 "Fan Tray Fan RPM Status\n" 570 "----------- ---- ----- ----------\n")); 571 572 for (i = 0; i < MAX_FANS; i++) { 573 err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, prop, 574 PICL_PROPNAMELEN_MAX); 575 if (err != PICL_SUCCESS) 576 continue; 577 578 err = fill_device_from_id(fans[i], "PSVC_PARENT", &phdl); 579 if (err != PICL_SUCCESS) 580 continue; 581 err = picl_get_propval_by_name(phdl, PICL_PROP_NAME, parent, 582 PICL_PROPNAMELEN_MAX); 583 if (err != PICL_SUCCESS) 584 continue; 585 586 log_printf(dgettext(TEXT_DOMAIN, "%-16s"), parent); 587 588 589 log_printf(dgettext(TEXT_DOMAIN, "%-16s"), prop); 590 591 err = picl_get_propval_by_name(fans[i], "Fan-speed", 592 &rpm, sizeof (rpm)); 593 if (err != PICL_SUCCESS) { 594 free(fans); 595 return (err); 596 } 597 log_printf(dgettext(TEXT_DOMAIN, "%5d "), rpm); 598 599 err = picl_get_propval_by_name(fans[i], "FaultInformation", 600 prop, PICL_PROPNAMELEN_MAX); 601 if (err != PICL_SUCCESS) { 602 free(fans); 603 return (err); 604 } 605 log_printf(dgettext(TEXT_DOMAIN, " [%s]\n"), prop); 606 } 607 log_printf(dgettext(TEXT_DOMAIN, 608 "\n=================================\n\n")); 609 free(fans); 610 return (PICL_SUCCESS); 611 } 612 613 static int 614 print_disk(picl_nodehdl_t system_node) 615 { 616 int i, err; 617 int32_t number; 618 picl_nodehdl_t *disks; 619 char state[PICL_PROPNAMELEN_MAX]; 620 621 err = fill_device_array_from_id(system_node, "PSVC_DISK", &number, 622 &disks); 623 if (err != PICL_SUCCESS) { 624 return (err); 625 } 626 627 log_printf(dgettext(TEXT_DOMAIN, 628 "Disk Status:\n" 629 "------------\n")); 630 for (i = 0; i < MAX_DISKS; i++) { 631 err = picl_get_propval_by_name(disks[i], "FaultInformation", 632 state, PICL_PROPNAMELEN_MAX); 633 634 switch (err) { 635 case PICL_SUCCESS: 636 log_printf(dgettext(TEXT_DOMAIN, 637 "DISK %d: [%3s]\n"), i, state); 638 break; 639 case PICL_INVALIDHANDLE: 640 log_printf(dgettext(TEXT_DOMAIN, 641 "DISK %d: [ NOT PRESENT ]\n"), i); 642 break; 643 default: 644 free(disks); 645 return (err); 646 } 647 } 648 free(disks); 649 return (PICL_SUCCESS); 650 } 651 652 static int 653 print_FSP_LEDS(picl_nodehdl_t system_node) 654 { 655 int err; 656 int32_t number; 657 picl_nodehdl_t *fsp_led; 658 char fault_state[PICL_PROPNAMELEN_MAX]; 659 char locate_state[PICL_PROPNAMELEN_MAX]; 660 661 err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number, 662 &fsp_led); 663 if (err != PICL_SUCCESS) { 664 return (err); 665 } 666 667 assert(number == 2); 668 err = picl_get_propval_by_name(fsp_led[0], "State", &fault_state, 669 PICL_PROPNAMELEN_MAX); 670 if (err != PICL_SUCCESS) { 671 free(fsp_led); 672 return (err); 673 } 674 675 if (strcmp(fault_state, PSVC_LED_ON) == 0) 676 exit_code = PD_SYSTEM_FAILURE; 677 678 err = picl_get_propval_by_name(fsp_led[1], "State", &locate_state, 679 PICL_PROPNAMELEN_MAX); 680 if (err != PICL_SUCCESS) { 681 free(fsp_led); 682 return (err); 683 } 684 685 log_printf(dgettext(TEXT_DOMAIN, 686 "System LED Status:\n\n" 687 " LOCATOR FAULT POWER\n" 688 " ------- ------- -------\n" 689 " [%3s] [%3s] [ ON]"), 690 locate_state, fault_state); 691 692 log_printf(dgettext(TEXT_DOMAIN, 693 "\n\n=================================\n\n")); 694 free(fsp_led); 695 return (err); 696 } 697 698 static int 699 print_keyswitch(picl_nodehdl_t system_node) 700 { 701 int err; 702 picl_nodehdl_t *keyswitch; 703 int32_t number; 704 char ks_pos[PICL_PROPNAMELEN_MAX]; 705 706 err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number, 707 &keyswitch); 708 if (err != PICL_SUCCESS) { 709 return (err); 710 } 711 err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos, 712 PICL_PROPNAMELEN_MAX); 713 if (err != PICL_SUCCESS) { 714 free(keyswitch); 715 return (err); 716 } 717 718 log_printf(dgettext(TEXT_DOMAIN, 719 "Front Status Panel:\n" 720 "-------------------\n" 721 "Keyswitch position: %s\n\n"), ks_pos); 722 free(keyswitch); 723 return (err); 724 } 725 726 static int 727 print_temps(picl_nodehdl_t system_node) 728 { 729 int i; 730 int err; 731 picl_nodehdl_t *system_ts_nodes; 732 int32_t temp; 733 int32_t number; 734 char label[PICL_PROPNAMELEN_MAX]; 735 char state[PICL_PROPNAMELEN_MAX]; 736 char *p; 737 738 err = fill_device_array_from_id(system_node, "PSVC_TS", &number, 739 &system_ts_nodes); 740 if (err != PICL_SUCCESS) { 741 return (err); 742 } 743 744 log_printf(dgettext(TEXT_DOMAIN, 745 "System Temperatures (Celsius):\n" 746 "-------------------------------\n" 747 "Device\t\tTemperature\tStatus\n" 748 "---------------------------------------\n")); 749 750 for (i = 0; i < number; i++) { 751 err = picl_get_propval_by_name(system_ts_nodes[i], 752 "State", state, sizeof (state)); 753 if (err != PICL_SUCCESS) { 754 if (err == PICL_INVALIDHANDLE) { 755 (void) strcpy(state, "n/a"); 756 } else { 757 free(system_ts_nodes); 758 return (err); 759 } 760 } 761 err = picl_get_propval_by_name(system_ts_nodes[i], 762 PICL_PROP_NAME, label, PICL_PROPNAMELEN_MAX); 763 if (err != PICL_SUCCESS) { 764 if (err == PICL_INVALIDHANDLE) 765 /* This FRU isn't present. Skip it. */ 766 continue; 767 free(system_ts_nodes); 768 return (err); 769 } 770 771 /* 772 * The names in the tree are like "CPU0_DIE_TEMPERATURE_SENSOR". 773 * All we want to print is up to the first underscore. 774 */ 775 p = strchr(label, '_'); 776 if (p != NULL) 777 *p = '\0'; 778 779 err = picl_get_propval_by_name(system_ts_nodes[i], 780 "Temperature", &temp, sizeof (temp)); 781 if (err != PICL_SUCCESS) { 782 free(system_ts_nodes); 783 return (err); 784 } 785 log_printf("%s\t\t%3d\t\t%s\n", label, temp, state); 786 } 787 788 log_printf(dgettext(TEXT_DOMAIN, 789 "\n=================================\n\n")); 790 791 free(system_ts_nodes); 792 return (PICL_SUCCESS); 793 } 794 795 static void 796 display_hw_revisions(Prom_node *root, Board_node *bdlist) 797 { 798 Prom_node *pnode; 799 char *value; 800 801 log_printf(dgettext(TEXT_DOMAIN, "\n" 802 "========================= HW Revisions " 803 "=======================================\n\n")); 804 805 log_printf(dgettext(TEXT_DOMAIN, 806 "System PROM revisions:\n" 807 "----------------------\n")); 808 809 pnode = dev_find_node(root, "openprom"); 810 if (pnode != NULL) { 811 value = (char *)get_prop_val(find_prop(pnode, "version")); 812 log_printf(value); 813 } 814 815 log_printf(dgettext(TEXT_DOMAIN, "\n\n" 816 "IO ASIC revisions:\n" 817 "------------------\n" 818 " Port\n" 819 "Model ID Status Version\n" 820 "-------- ---- ------ -------\n")); 821 822 display_schizo_revisions(bdlist); 823 } 824 825 826 static void 827 display_schizo_revisions(Board_node *bdlist) 828 { 829 Prom_node *pnode; 830 int *int_val; 831 int portid; 832 int prev_portid = -1; 833 char *status_a = NULL; 834 char *status_b = NULL; 835 int revision; 836 #ifdef DEBUG 837 uint32_t a_notes, b_notes; 838 #endif 839 int pci_bus; 840 Board_node *bnode; 841 bnode = bdlist; 842 843 while (bnode != NULL) { 844 /* 845 * search this board node for all Schizos 846 */ 847 848 for (pnode = dev_find_node_by_compat(bnode->nodes, 849 SCHIZO_COMPAT_PROP); pnode != NULL; 850 pnode = dev_next_node_by_compat(pnode, 851 SCHIZO_COMPAT_PROP)) { 852 853 /* 854 * get the reg property to determine 855 * whether we are looking at side A or B 856 */ 857 858 int_val = (int *)get_prop_val 859 (find_prop(pnode, "reg")); 860 if (int_val != NULL) { 861 int_val ++; /* second integer in array */ 862 pci_bus = ((*int_val) & 0x7f0000); 863 } 864 865 /* get portid */ 866 int_val = (int *)get_prop_val 867 (find_prop(pnode, "portid")); 868 if (int_val == NULL) 869 continue; 870 871 portid = *int_val; 872 873 /* 874 * If this is a new portid and it is PCI bus B, 875 * we skip onto the PCI bus A. 876 */ 877 if ((portid != prev_portid) && (pci_bus == 0x700000)) { 878 prev_portid = portid; 879 /* status */ 880 status_b = (char *)get_prop_val 881 (find_prop(pnode, "status")); 882 #ifdef DEBUG 883 b_notes = pci_bus; 884 #endif 885 continue; /* skip to the next schizo */ 886 } 887 888 /* 889 * This must be side A of the same Schizo. 890 * Gather all its props and display them. 891 */ 892 #ifdef DEBUG 893 a_notes = pci_bus; 894 #endif 895 896 prev_portid = portid; 897 898 int_val = (int *)get_prop_val 899 (find_prop(pnode, "version#")); 900 if (int_val != NULL) 901 revision = *int_val; 902 else 903 revision = -1; 904 905 status_a = (char *)get_prop_val(find_prop 906 (pnode, "status")); 907 908 log_printf(dgettext(TEXT_DOMAIN, "Schizo ")); 909 910 log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0); 911 912 913 log_printf((status_a == NULL && status_b == NULL) ? 914 dgettext(TEXT_DOMAIN, " ok ") : 915 dgettext(TEXT_DOMAIN, " fail ")); 916 917 log_printf(dgettext(TEXT_DOMAIN, " %4d "), 918 revision); 919 #ifdef DEBUG 920 log_printf(" 0x%x 0x%x", a_notes, b_notes); 921 #endif 922 log_printf("\n"); 923 } 924 bnode = bnode->next; 925 } 926 } 927