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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2020 Peter Tribble. 26 * 27 * Javelin Platform specific functions. 28 * 29 * called when : 30 * machine_type == MTYPE_JAVELIN 31 * 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <ctype.h> 38 #include <string.h> 39 #include <kvm.h> 40 #include <varargs.h> 41 #include <errno.h> 42 #include <time.h> 43 #include <dirent.h> 44 #include <fcntl.h> 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/types.h> 48 #include <sys/utsname.h> 49 #include <sys/openpromio.h> 50 #include <kstat.h> 51 #include <libintl.h> 52 #include <syslog.h> 53 #include <sys/dkio.h> 54 #include "pdevinfo.h" 55 #include "display.h" 56 #include "pdevinfo_sun4u.h" 57 #include "display_sun4u.h" 58 #include "libprtdiag.h" 59 60 #if !defined(TEXT_DOMAIN) 61 #define TEXT_DOMAIN "SYS_TEST" 62 #endif 63 64 extern int print_flag; 65 66 /* 67 * these functions will overlay the symbol table of libprtdiag 68 * at runtime (workgroup server systems only) 69 */ 70 int error_check(Sys_tree *tree, struct system_kstat_data *kstats); 71 void display_memoryconf(Sys_tree *tree); 72 int disp_fail_parts(Sys_tree *tree); 73 void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats); 74 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 75 struct system_kstat_data *kstats); 76 void display_boardnum(int num); 77 void display_pci(Board_node *); 78 void display_io_cards(struct io_card *list); 79 void display_ffb(Board_node *, int); 80 void read_platform_kstats(Sys_tree *tree, 81 struct system_kstat_data *sys_kstat, 82 struct envctrl_kstat_data *ep); 83 84 /* local functions */ 85 static int disp_envc_status(struct system_kstat_data *); 86 static void tazjav_disp_asic_revs(Sys_tree *); 87 static int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *); 88 static Prom_node *dev_next_node_sibling(Prom_node *root, char *name); 89 90 91 int 92 error_check(Sys_tree *tree, struct system_kstat_data *kstats) 93 { 94 int exit_code = 0; /* init to all OK */ 95 96 #ifdef lint 97 kstats = kstats; 98 #endif 99 /* 100 * silently check for any types of machine errors 101 */ 102 print_flag = 0; 103 if (disp_fail_parts(tree) || disp_envc_status(kstats)) { 104 /* set exit_code to show failures */ 105 exit_code = 1; 106 } 107 print_flag = 1; 108 109 return (exit_code); 110 } 111 112 /* Search for and return the node's sibling */ 113 static Prom_node * 114 dev_next_node_sibling(Prom_node *root, char *name) 115 { 116 if (root == NULL) 117 return (NULL); 118 119 /* look at your siblings */ 120 if (dev_find_node(root->sibling, name) != NULL) 121 return (root->sibling); 122 123 return (NULL); /* not found */ 124 } 125 126 /* 127 * This function displays memory configurations specific to Tazmo/Javelin. 128 * The PROM device tree is read to obtain this information. 129 * Some of the information obtained is memory interleave factor, 130 * DIMM sizes, DIMM socket names. 131 */ 132 void 133 display_memoryconf(Sys_tree *tree) 134 { 135 Board_node *bnode; 136 Prom_node *memory; 137 Prom_node *bank; 138 Prom_node *dimm; 139 uint_t *preg; 140 uint_t interlv; 141 unsigned long size = 0; 142 int bank_count = 0; 143 char *sock_name; 144 char *status; 145 Prop *status_prop; 146 char interleave[8]; 147 int total_size = 0; 148 149 log_printf("\n", 0); 150 log_printf("=========================", 0); 151 log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0); 152 log_printf("=========================", 0); 153 log_printf("\n", 0); 154 log_printf("\n", 0); 155 bnode = tree->bd_list; 156 memory = dev_find_node(bnode->nodes, "memory"); 157 preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave"))); 158 if (preg) { 159 interlv = preg[4]; 160 log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0); 161 } 162 log_printf(" Interlv. Socket Size\n", 0); 163 log_printf("Bank Group Name (MB) Status\n", 0); 164 log_printf("---- ----- ------ ---- ------\n", 0); 165 166 dimm = bnode->nodes; 167 for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL; 168 bank = dev_next_node(bank, "bank")) { 169 int bank_size = 0; 170 uint_t *reg_prop; 171 172 preg = (uint_t *)(get_prop_val( 173 find_prop(bank, "bank-interleave"))); 174 175 reg_prop = (uint_t *)(get_prop_val( 176 find_prop(bank, "reg"))); 177 178 /* 179 * Skip empty banks 180 */ 181 if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) { 182 bank_count++; 183 continue; 184 } 185 186 if (preg) { 187 interlv = preg[2]; 188 (void) sprintf(interleave, " %d ", interlv); 189 bank_size = (preg[0]<<12) + (preg[1]>>20); 190 } else { 191 (void) sprintf(interleave, "%s", "none"); 192 preg = (uint_t *)(get_prop_val(find_prop(bank, "reg"))); 193 if (preg) { 194 bank_size = (preg[2]<<12) + (preg[3]>>20); 195 } 196 } 197 for (dimm = dev_find_node(bank, "dimm"); dimm != NULL; 198 dimm = dev_next_node_sibling(dimm, "dimm")) { 199 char dimm_status[16]; 200 201 sock_name = (char *)(get_prop_val( 202 find_prop(dimm, "socket-name"))); 203 preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg"))); 204 size = (preg[2]<<12) + (preg[3]>>20); 205 if ((status_prop = find_prop(dimm, "status")) == NULL) { 206 (void) sprintf(dimm_status, "%s", "OK"); 207 } else { 208 status = (char *)(get_prop_val(status_prop)); 209 (void) sprintf(dimm_status, "%s", status); 210 } 211 log_printf("%3d %5s %6s %4d %6s\n", 212 bank_count, interleave, sock_name, 213 size, dimm_status, 0); 214 } 215 total_size += bank_size; 216 bank_count++; 217 } 218 log_printf("\n", 0); 219 } 220 221 /* 222 * disp_fail_parts 223 * 224 * Display the failed parts in the system. This function looks for 225 * the status property in all PROM nodes. On systems where 226 * the PROM does not supports passing diagnostic information 227 * thruogh the device tree, this routine will be silent. 228 */ 229 int 230 disp_fail_parts(Sys_tree *tree) 231 { 232 int exit_code; 233 int system_failed = 0; 234 Board_node *bnode = tree->bd_list; 235 Prom_node *pnode; 236 char *fru; 237 char *sock_name; 238 char slot_str[MAXSTRLEN]; 239 240 exit_code = 0; 241 242 /* go through all of the boards looking for failed units. */ 243 while (bnode != NULL) { 244 /* find failed chips */ 245 pnode = find_failed_node(bnode->nodes); 246 if ((pnode != NULL) && !system_failed) { 247 system_failed = 1; 248 exit_code = 1; 249 if (print_flag == 0) { 250 return (exit_code); 251 } 252 log_printf("\n", 0); 253 log_printf(dgettext(TEXT_DOMAIN, "Failed Field " 254 "Replaceable Units (FRU) in System:\n"), 0); 255 log_printf("==========================" 256 "====================\n", 0); 257 } 258 259 while (pnode != NULL) { 260 void *value; 261 char *name; /* node name string */ 262 char *type; /* node type string */ 263 264 value = get_prop_val(find_prop(pnode, "status")); 265 name = get_node_name(pnode); 266 267 /* sanity check of data retreived from PROM */ 268 if ((value == NULL) || (name == NULL)) { 269 pnode = next_failed_node(pnode); 270 continue; 271 } 272 273 274 log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"), 275 name, 0); 276 277 log_printf(dgettext(TEXT_DOMAIN, "\tPROM fault " 278 "string: %s\n"), value, 0); 279 280 log_printf(dgettext(TEXT_DOMAIN, "\tFailed Field " 281 "Replaceable Unit is "), 0); 282 283 /* 284 * Determine whether FRU is CPU module, system 285 * board, or SBus card. 286 */ 287 if ((name != NULL) && (strstr(name, "sbus"))) { 288 289 log_printf(dgettext(TEXT_DOMAIN, "SBus " 290 "Card %d\n"), get_sbus_slot(pnode), 0); 291 292 } else if (((name = get_node_name(pnode)) != 293 NULL) && (strstr(name, "pci"))) { 294 295 log_printf(dgettext(TEXT_DOMAIN, "system " 296 "board\n"), 0); 297 298 } else if (((name = get_node_name(pnode)) != 299 NULL) && (strstr(name, "ffb"))) { 300 301 log_printf(dgettext(TEXT_DOMAIN, "FFB " 302 "Card %d\n"), tazmo_physical_slot( 303 dev_find_node(bnode->nodes, "slot2dev"), 304 pnode, -1, slot_str), 0); 305 306 } else if (((name = get_node_name(pnode->parent)) != 307 NULL) && (strstr(name, "pci"))) { 308 309 (void) tazmo_physical_slot(NULL, 310 pnode->parent, 311 get_pci_device(pnode), 312 slot_str); 313 log_printf(dgettext(TEXT_DOMAIN, "PCI Card " 314 "in %s\n"), slot_str, 0); 315 316 } else if (((type = get_node_type(pnode)) != NULL) && 317 (strstr(type, "cpu"))) { 318 319 log_printf( 320 dgettext(TEXT_DOMAIN, "UltraSPARC " 321 "module Module %d\n"), 322 get_id(pnode)); 323 324 } else if (((type = get_node_type(pnode)) != NULL) && 325 (strstr(type, "memory-module"))) { 326 327 fru = (char *)(get_prop_val( 328 find_prop(pnode, "fru"))); 329 sock_name = (char *)(get_prop_val( 330 find_prop(pnode, "socket-name"))); 331 log_printf( 332 dgettext(TEXT_DOMAIN, "%s in " 333 "socket %s\n"), fru, 334 sock_name, 0); 335 } 336 pnode = next_failed_node(pnode); 337 } 338 bnode = bnode->next; 339 } 340 341 if (!system_failed) { 342 log_printf("\n", 0); 343 log_printf(dgettext(TEXT_DOMAIN, "No failures found " 344 "in System\n"), 0); 345 log_printf("===========================\n", 0); 346 } 347 348 if (system_failed) 349 return (1); 350 else 351 return (0); 352 } 353 354 void 355 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats) 356 { 357 #ifdef lint 358 kstats = kstats; 359 #endif 360 /* Display failed units */ 361 (void) disp_fail_parts(tree); 362 } 363 364 365 void 366 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 367 struct system_kstat_data *kstats) 368 { 369 /* 370 * Now display the last powerfail time and the fatal hardware 371 * reset information. We do this under a couple of conditions. 372 * First if the user asks for it. The second is iof the user 373 * told us to do logging, and we found a system failure. 374 */ 375 if (flag) { 376 /* 377 * display time of latest powerfail. Not all systems 378 * have this capability. For those that do not, this 379 * is just a no-op. 380 */ 381 disp_powerfail(root); 382 383 (void) disp_envc_status(kstats); 384 385 tazjav_disp_asic_revs(tree); 386 387 platform_disp_prom_version(tree); 388 } 389 return; 390 391 } 392 393 /* ARGSUSED */ 394 void 395 display_boardnum(int num) 396 { 397 log_printf("SYS ", 0); 398 } 399 400 401 402 /* 403 * display_pci 404 * Display all the PCI IO cards on this board. 405 */ 406 407 /* ARGSUSED */ 408 void 409 display_pci(Board_node *board) 410 { 411 struct io_card *card_list = NULL; 412 struct io_card card; 413 void *value; 414 Prom_node *pci; 415 Prom_node *card_node; 416 417 if (board == NULL) 418 return; 419 420 /* Initialize all the common information */ 421 card.display = 1; 422 card.board = board->board_num; 423 (void) sprintf(card.bus_type, "PCI"); 424 425 for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL; 426 pci = dev_next_node(pci, PCI_NAME)) { 427 char *name; 428 Prom_node *prev_parent = NULL; 429 int prev_device = -1; 430 int pci_pci_bridge = 0; 431 432 /* 433 * If we have reached a pci-to-pci bridge node, 434 * we are one level below the 'pci' nodes level 435 * in the device tree. To get back to that level, 436 * the search should continue with the sibling of 437 * the parent or else the remaining 'pci' cards 438 * will not show up in the output. 439 */ 440 if (find_prop(pci, "upa-portid") == NULL) { 441 if ((pci->parent->sibling != NULL) && 442 (strcmp(get_prop_val( 443 find_prop(pci->parent->sibling, 444 "name")), PCI_NAME) == 0)) 445 pci = pci->parent->sibling; 446 else { 447 pci = pci->parent->sibling; 448 continue; 449 } 450 } 451 452 /* Skip all failed nodes for now */ 453 if (node_failed(pci)) 454 continue; 455 456 /* Fill in frequency */ 457 value = get_prop_val(find_prop(pci, "clock-frequency")); 458 if (value == NULL) 459 card.freq = -1; 460 else 461 card.freq = ((*(int *)value) + 500000) / 1000000; 462 463 /* Walk through the PSYCHO children */ 464 card_node = pci->child; 465 while (card_node != NULL) { 466 Prop *compat = NULL; 467 468 /* If it doesn't have a name, skip it */ 469 name = (char *)get_prop_val( 470 find_prop(card_node, "name")); 471 if (name == NULL) { 472 card_node = card_node->sibling; 473 continue; 474 } 475 476 /* 477 * If this is a PCI bridge, then display its 478 * children. 479 */ 480 if (strcmp(name, "pci") == 0) { 481 card_node = card_node->child; 482 pci_pci_bridge = 1; 483 continue; 484 } 485 486 /* Get the slot number for this card */ 487 if (pci_pci_bridge) { 488 card.slot = tazmo_physical_slot( 489 dev_find_node(board->nodes, "slot2dev"), 490 pci, 491 get_pci_to_pci_device(card_node->parent), 492 card.slot_str); 493 } else 494 card.slot = tazmo_physical_slot( 495 dev_find_node(board->nodes, "slot2dev"), 496 pci, 497 get_pci_device(card_node), 498 card.slot_str); 499 500 /* 501 * Check that duplicate devices are not reported 502 * on Tazmo. 503 */ 504 if ((card_node->parent == prev_parent) && 505 (get_pci_device(card_node) == prev_device) && 506 (pci_pci_bridge == 0)) 507 card.slot = -1; 508 prev_parent = card_node->parent; 509 prev_device = get_pci_device(card_node); 510 511 512 if (card.slot == -1 || strstr(name, "ebus")) { 513 card_node = card_node->sibling; 514 continue; 515 } 516 517 /* XXX - Don't know how to get status for PCI cards */ 518 card.status[0] = '\0'; 519 520 /* Get the model of this card */ 521 value = get_prop_val(find_prop(card_node, "model")); 522 if (value == NULL) 523 card.model[0] = '\0'; 524 else 525 (void) sprintf(card.model, "%s", 526 (char *)value); 527 528 /* 529 * Check if further processing is necessary to display 530 * this card uniquely. 531 */ 532 distinguish_identical_io_cards(name, card_node, &card); 533 534 535 /* 536 * If we haven't figured out the frequency yet, 537 * try and get it from the card. 538 */ 539 value = get_prop_val(find_prop(pci, "clock-frequency")); 540 if (value != NULL && card.freq == -1) 541 card.freq = ((*(int *)value) + 500000) 542 / 1000000; 543 544 545 value = get_prop_val(find_prop(card_node, 546 "compatible")); 547 548 /* 549 * On Tazmo, we would like to print out the last 550 * string of the "compatible" property if it exists. 551 * The IEEE 1275 spec. states that this last string 552 * will be the classcode name. 553 */ 554 if (value != NULL) { 555 char *tval; 556 int index; 557 const int always = 1; 558 559 tval = (char *)value; 560 index = 0; 561 compat = find_prop(card_node, "compatible"); 562 while (always) { 563 if ((strlen(tval) + 1) == 564 (compat->size - index)) 565 break; 566 index += strlen(tval) + 1; 567 tval += strlen(tval) + 1; 568 } 569 value = (void *)tval; 570 } 571 572 if (value != NULL) 573 (void) sprintf(card.name, "%s-%s", 574 (char *)name, (char *)value); 575 else 576 (void) sprintf(card.name, "%s", 577 (char *)name); 578 579 if (card.freq != -1) 580 card_list = insert_io_card(card_list, &card); 581 582 /* 583 * If we are done with the children of the pci bridge, 584 * we must continue with the remaining siblings of 585 * the pci-to-pci bridge. 586 */ 587 if ((card_node->sibling == NULL) && pci_pci_bridge) { 588 card_node = card_node->parent->sibling; 589 pci_pci_bridge = 0; 590 } else 591 card_node = card_node->sibling; 592 } 593 } 594 595 display_io_cards(card_list); 596 free_io_cards(card_list); 597 } 598 599 600 /* 601 * Print out all the io cards in the list. Also print the column 602 * headers if told to do so. 603 */ 604 void 605 display_io_cards(struct io_card *list) 606 { 607 static int banner = 0; /* Have we printed the column headings? */ 608 struct io_card *p; 609 610 if (list == NULL) 611 return; 612 613 if (banner == 0) { 614 log_printf(" Bus Freq\n", 0); 615 log_printf("Brd Type MHz Slot " 616 "Name " 617 "Model", 0); 618 log_printf("\n", 0); 619 log_printf("--- ---- ---- ---- " 620 "-------------------------------- " 621 "----------------------", 0); 622 log_printf("\n", 0); 623 banner = 1; 624 } 625 626 for (p = list; p != NULL; p = p -> next) { 627 log_printf("SYS ", p->board, 0); 628 log_printf("%-4s ", p->bus_type, 0); 629 log_printf("%3d ", p->freq, 0); 630 log_printf("%3d ", p->slot, 0); 631 log_printf("%-32.32s", p->name, 0); 632 if (strlen(p->name) > 32) 633 log_printf("+ ", 0); 634 else 635 log_printf(" ", 0); 636 log_printf("%-22.22s", p->model, 0); 637 if (strlen(p->model) > 22) 638 log_printf("+", 0); 639 log_printf("\n", 0); 640 } 641 } 642 643 /* 644 * display_ffb 645 * Display all FFBs on this board. It can either be in tabular format, 646 * or a more verbose format. 647 */ 648 void 649 display_ffb(Board_node *board, int table) 650 { 651 Prom_node *ffb; 652 void *value; 653 struct io_card *card_list = NULL; 654 struct io_card card; 655 656 if (board == NULL) 657 return; 658 659 /* Fill in common information */ 660 card.display = 1; 661 card.board = board->board_num; 662 (void) sprintf(card.bus_type, "UPA"); 663 card.freq = sys_clk; 664 665 for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL; 666 ffb = dev_next_node(ffb, FFB_NAME)) { 667 if (table == 1) { 668 /* Print out in table format */ 669 670 /* XXX - Get the slot number (hack) */ 671 card.slot = tazmo_physical_slot( 672 dev_find_node(board->nodes, "slot2dev"), 673 ffb, 674 -1, 675 card.slot_str); 676 677 /* Find out if it's single or double buffered */ 678 (void) sprintf(card.name, "FFB"); 679 value = get_prop_val(find_prop(ffb, "board_type")); 680 if (value != NULL) 681 if ((*(int *)value) & FFB_B_BUFF) 682 (void) sprintf(card.name, 683 "FFB, Double Buffered"); 684 else 685 (void) sprintf(card.name, 686 "FFB, Single Buffered"); 687 688 /* Print model number */ 689 card.model[0] = '\0'; 690 value = get_prop_val(find_prop(ffb, "model")); 691 if (value != NULL) 692 (void) sprintf(card.model, "%s", 693 (char *)value); 694 695 card_list = insert_io_card(card_list, &card); 696 } else { 697 /* print in long format */ 698 char device[MAXSTRLEN]; 699 int fd = -1; 700 struct dirent *direntp; 701 DIR *dirp; 702 union strap_un strap; 703 struct ffb_sys_info fsi; 704 705 /* Find the device node using upa address */ 706 value = get_prop_val(find_prop(ffb, "upa-portid")); 707 if (value == NULL) 708 continue; 709 710 (void) sprintf(device, "%s@%x", FFB_NAME, 711 *(int *)value); 712 if ((dirp = opendir("/devices")) == NULL) 713 continue; 714 715 while ((direntp = readdir(dirp)) != NULL) { 716 if (strstr(direntp->d_name, device) != NULL) { 717 (void) sprintf(device, "/devices/%s", 718 direntp->d_name); 719 fd = open(device, O_RDWR, 0666); 720 break; 721 } 722 } 723 (void) closedir(dirp); 724 725 if (fd == -1) 726 continue; 727 728 if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0) 729 continue; 730 731 log_printf("FFB Hardware Configuration:\n", 0); 732 log_printf("-----------------------------------\n", 0); 733 734 strap.ffb_strap_bits = fsi.ffb_strap_bits; 735 log_printf("\tBoard rev: %d\n", 736 (int)strap.fld.board_rev, 0); 737 log_printf("\tFBC version: " 738 "0x%x\n", fsi.fbc_version, 0); 739 log_printf("\tDAC: %s\n", 740 fmt_manf_id(fsi.dac_version, device), 0); 741 log_printf("\t3DRAM: %s\n", 742 fmt_manf_id(fsi.fbram_version, device), 0); 743 log_printf("\n", 0); 744 } 745 } 746 747 display_io_cards(card_list); 748 free_io_cards(card_list); 749 } 750 751 /* 752 * This module does the reading and interpreting of javelin system 753 * kstats. These kstats are created by the envctrl drivers. 754 */ 755 void 756 read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat, 757 struct envctrl_kstat_data *ep) 758 { 759 kstat_ctl_t *kc; 760 struct envctrltwo_kstat_data *ecp; 761 kstat_t *ksp; 762 763 if ((kc = kstat_open()) == NULL) { 764 return; 765 } 766 767 /* read the envctrltwo kstats */ 768 ecp = &sys_kstat->envc_data; 769 770 /* Read the power supply kstats */ 771 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0, 772 ENVCTRL_KSTAT_PSNAME2); 773 774 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) { 775 (void) memcpy(ecp->ps_kstats, ksp->ks_data, 776 ksp->ks_ndata * sizeof (envctrl_ps2_t)); 777 } else { 778 sys_kstat->envctrltwo_kstat_ok = B_FALSE; 779 return; 780 } 781 782 ecp->num_ps_kstats = ksp->ks_ndata; 783 784 /* Read the fan status kstats */ 785 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0, 786 ENVCTRL_KSTAT_FANSTAT); 787 788 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) { 789 (void) memcpy(ecp->fan_kstats, ksp->ks_data, 790 ksp->ks_ndata * sizeof (envctrl_fan_t)); 791 } else { 792 sys_kstat->envctrltwo_kstat_ok = B_FALSE; 793 return; 794 } 795 796 ecp->num_fan_kstats = ksp->ks_ndata; 797 798 /* Read the enclosure kstats */ 799 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0, 800 ENVCTRL_KSTAT_ENCL); 801 802 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) { 803 (void) memcpy(ecp->encl_kstats, ksp->ks_data, 804 ksp->ks_ndata * sizeof (envctrl_encl_t)); 805 } else { 806 sys_kstat->envctrltwo_kstat_ok = B_FALSE; 807 return; 808 } 809 810 ecp->num_encl_kstats = ksp->ks_ndata; 811 812 /* Read the temperature kstats */ 813 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0, 814 ENVCTRL_KSTAT_TEMPERATURE); 815 816 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) { 817 (void) memcpy(ecp->temp_kstats, ksp->ks_data, 818 ksp->ks_ndata * sizeof (envctrl_temp_t)); 819 } else { 820 sys_kstat->envctrltwo_kstat_ok = B_FALSE; 821 return; 822 } 823 824 ecp->num_temp_kstats = ksp->ks_ndata; 825 826 /* Read the disk kstats */ 827 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0, 828 ENVCTRL_KSTAT_DISK); 829 830 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) { 831 (void) memcpy(ecp->disk_kstats, ksp->ks_data, 832 ksp->ks_ndata * sizeof (envctrl_disk_t)); 833 } else { 834 sys_kstat->envctrltwo_kstat_ok = B_FALSE; 835 return; 836 } 837 838 ecp->num_disk_kstats = ksp->ks_ndata; 839 840 sys_kstat->envctrltwo_kstat_ok = 1; 841 return; 842 843 } 844 845 /* 846 * Walk the PROM device tree and build the system tree and root tree. 847 * Nodes that have a board number property are placed in the board 848 * structures for easier processing later. Child nodes are placed 849 * under their parents. ffb (Fusion Frame Buffer) nodes are handled 850 * specially, because they do not contain board number properties. 851 * This was requested from OBP, but was not granted. So this code 852 * must parse the MID of the FFB to find the board#. 853 */ 854 Prom_node * 855 walk(Sys_tree *tree, Prom_node *root, int id) 856 { 857 register int curnode; 858 Prom_node *pnode; 859 char *name; 860 char *type; 861 char *model; 862 int board_node = 0; 863 864 /* allocate a node for this level */ 865 if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) == 866 NULL) { 867 perror("malloc"); 868 exit(2); /* program errors cause exit 2 */ 869 } 870 871 /* assign parent Prom_node */ 872 pnode->parent = root; 873 pnode->sibling = NULL; 874 pnode->child = NULL; 875 876 /* read properties for this node */ 877 dump_node(pnode); 878 879 /* 880 * Place a node in a 'board' if it has 'board'-ness. The definition 881 * is that all nodes that are children of root should have a 882 * board# property. But the PROM tree does not exactly follow 883 * this. This is where we start hacking. The name 'ffb' can 884 * change, so watch out for this. 885 * 886 * The UltraSPARC, sbus, pci and ffb nodes will exit in 887 * the desktops and will not have board# properties. These 888 * cases must be handled here. 889 * 890 * PCI to PCI bridges also have the name "pci", but with different 891 * model property values. They should not be put under 'board'. 892 */ 893 name = get_node_name(pnode); 894 type = get_node_type(pnode); 895 model = (char *)get_prop_val(find_prop(pnode, "model")); 896 #ifdef DEBUG 897 if (name != NULL) 898 printf("name=%s ", name); 899 if (type != NULL) 900 printf("type=%s ", type); 901 if (model != NULL) 902 printf("model=%s", model); 903 printf("\n"); 904 905 if (model == NULL) 906 model = ""; 907 #endif 908 if (type == NULL) 909 type = ""; 910 if (name != NULL) { 911 if (has_board_num(pnode)) { 912 add_node(tree, pnode); 913 board_node = 1; 914 #ifdef DEBUG 915 printf("ADDED BOARD name=%s type=%s model=%s\n", 916 name, type, model); 917 #endif 918 } else if ((strcmp(name, FFB_NAME) == 0) || 919 (strcmp(type, "cpu") == 0) || 920 921 ((strcmp(name, "pci") == 0) && (model != NULL) && 922 (strcmp(model, "SUNW,psycho") == 0)) || 923 924 ((strcmp(name, "pci") == 0) && (model != NULL) && 925 (strcmp(model, "SUNW,sabre") == 0)) || 926 927 (strcmp(name, "counter-timer") == 0) || 928 (strcmp(name, "sbus") == 0) || 929 (strcmp(name, "memory") == 0) || 930 (strcmp(name, "mc") == 0) || 931 (strcmp(name, "associations") == 0)) { 932 add_node(tree, pnode); 933 board_node = 1; 934 #ifdef DEBUG 935 printf("ADDED BOARD name=%s type=%s model=%s\n", 936 name, type, model); 937 #endif 938 } 939 #ifdef DEBUG 940 else 941 printf("node not added: name=%s type=%s\n", name, type); 942 #endif 943 } 944 945 if (curnode = child(id)) { 946 pnode->child = walk(tree, pnode, curnode); 947 } 948 949 if (curnode = next(id)) { 950 if (board_node) { 951 return (walk(tree, root, curnode)); 952 } else { 953 pnode->sibling = walk(tree, root, curnode); 954 } 955 } 956 957 if (board_node) { 958 return (NULL); 959 } else { 960 return (pnode); 961 } 962 } 963 964 /* 965 * local functions 966 */ 967 968 /* 969 * disp_envc_status 970 * 971 * This routine displays the environmental status passed up from 972 * device drivers via kstats. The kstat names are defined in 973 * kernel header files included by this module. 974 * This is a Javelin specific environmental information display routine. 975 */ 976 static int 977 disp_envc_status(struct system_kstat_data *sys_kstats) 978 { 979 struct envctrltwo_kstat_data *ecp; 980 envctrl_ps2_t ps_ks; 981 envctrl_fan_t fans_ks; 982 envctrl_encl_t encl_ks; 983 envctrl_temp_t temp_ks; 984 envctrl_disk_t disk_ks; 985 char state[48]; 986 uchar_t val, fsp_value; 987 uchar_t disk_pr, disk_fl; 988 int i; 989 int exit_code = 0; 990 991 if (sys_kstats->envctrltwo_kstat_ok == 0) { 992 log_printf("\n", 0); 993 log_printf(dgettext(TEXT_DOMAIN, "Environmental information " 994 "is not available\n"), 0); 995 log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may " 996 "not be installed\n"), 0); 997 log_printf("\n", 0); 998 return (1); 999 } 1000 1001 ecp = &sys_kstats->envc_data; 1002 1003 log_printf("\n", 0); 1004 log_printf("=========================", 0); 1005 log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0); 1006 log_printf("=========================", 0); 1007 log_printf("\n", 0); 1008 log_printf("\n", 0); 1009 1010 log_printf("System Temperatures (Celsius):\n", 0); 1011 log_printf("------------------------------\n", 0); 1012 1013 for (i = 0; i < ecp->num_temp_kstats; i++) { 1014 temp_ks = ecp->temp_kstats[i]; 1015 log_printf("%10s %d", temp_ks.label, temp_ks.value); 1016 if (temp_ks.value >= temp_ks.shutdown_threshold) { 1017 log_printf(" CRITICAL\n", 0); 1018 exit_code = 1; 1019 } else if (temp_ks.value >= temp_ks.warning_threshold) { 1020 log_printf(" WARNING\n", 0); 1021 exit_code = 1; 1022 } else if (temp_ks.value < temp_ks.min) { 1023 log_printf(" WARNING\n", 0); 1024 exit_code = 1; 1025 } else 1026 log_printf("\n", 0); 1027 } 1028 1029 log_printf("\n", 0); 1030 log_printf("=================================\n", 0); 1031 log_printf("\n", 0); 1032 encl_ks = ecp->encl_kstats[0]; 1033 val = encl_ks.value & ENVCTRL_UE250_FSP_KEYMASK; 1034 fsp_value = encl_ks.value; 1035 switch (val) { 1036 case ENVCTRL_UE250_FSP_KEYOFF: 1037 (void) sprintf(state, "%s", "Off"); 1038 break; 1039 case ENVCTRL_UE250_FSP_KEYON: 1040 (void) sprintf(state, "%s", "On"); 1041 break; 1042 case ENVCTRL_UE250_FSP_KEYDIAG: 1043 (void) sprintf(state, "%s", "Diagnostic"); 1044 break; 1045 case ENVCTRL_UE250_FSP_KEYLOCKED: 1046 (void) sprintf(state, "%s", "Secure"); 1047 break; 1048 default: 1049 (void) sprintf(state, "%s", "Broken!"); 1050 exit_code = 1; 1051 break; 1052 } 1053 log_printf("Front Status Panel:\n", 0); 1054 log_printf("-------------------\n", 0); 1055 log_printf("Keyswitch position is in %s mode.\n", state); 1056 log_printf("\n", 0); 1057 val = fsp_value & (ENVCTRL_UE250_FSP_DISK_ERR | 1058 ENVCTRL_UE250_FSP_PS_ERR | ENVCTRL_UE250_FSP_TEMP_ERR | 1059 ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_ACTIVE); 1060 log_printf("System LED Status: DISK ERROR POWER \n", 0); 1061 log_printf(" [%3s] [ ON] \n", 1062 val & ENVCTRL_UE250_FSP_DISK_ERR ? "ON" : "OFF"); 1063 log_printf(" POWER SUPPLY ERROR ACTIVITY \n", 0); 1064 log_printf(" [%3s] [%3s] \n", 1065 val & ENVCTRL_UE250_FSP_PS_ERR ? "ON" : "OFF", 1066 val & ENVCTRL_UE250_FSP_ACTIVE ? "ON" : "OFF"); 1067 log_printf(" GENERAL ERROR THERMAL ERROR \n", 0); 1068 log_printf(" [%3s] [%3s] \n", 1069 val & ENVCTRL_UE250_FSP_GEN_ERR ? "ON" : "OFF", 1070 val & ENVCTRL_UE250_FSP_TEMP_ERR ? "ON" : "OFF"); 1071 if (val & (ENVCTRL_UE250_FSP_DISK_ERR | ENVCTRL_UE250_FSP_PS_ERR | 1072 ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_TEMP_ERR)) { 1073 exit_code = 1; 1074 } 1075 1076 log_printf("\n", 0); 1077 log_printf("=================================\n", 0); 1078 log_printf("\n", 0); 1079 disk_pr = disk_fl = 0; 1080 for (i = 0; i < ecp->num_disk_kstats; i++) { 1081 disk_ks = ecp->disk_kstats[i]; 1082 if (disk_ks.slot == -1) 1083 continue; 1084 disk_pr |= 1 << disk_ks.slot; 1085 if (disk_ks.disk_ok == 0) 1086 disk_fl |= 1 << disk_ks.slot; 1087 } 1088 1089 log_printf("Disk LED Status: OK = GREEN ERROR = YELLOW\n", 0); 1090 log_printf(" DISK 5: %7s DISK 3: %7s DISK 1: %7s\n", 1091 disk_pr & ENVCTRL_DISK_5 ? 1092 disk_fl & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]" : "[EMPTY]", 1093 disk_pr & ENVCTRL_DISK_3 ? 1094 disk_fl & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]" : "[EMPTY]", 1095 disk_pr & ENVCTRL_DISK_1 ? 1096 disk_fl & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]" : "[EMPTY]"); 1097 log_printf(" DISK 4: %7s DISK 2: %7s DISK 0: %7s\n", 1098 disk_pr & ENVCTRL_DISK_4 ? 1099 disk_fl & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]" : "[EMPTY]", 1100 disk_pr & ENVCTRL_DISK_2 ? 1101 disk_fl & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]" : "[EMPTY]", 1102 disk_pr & ENVCTRL_DISK_0 ? 1103 disk_fl & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]" : "[EMPTY]"); 1104 1105 log_printf("\n", 0); 1106 log_printf("=================================\n", 0); 1107 log_printf("\n", 0); 1108 log_printf("Fan Bank :\n", 0); 1109 log_printf("----------\n", 0); 1110 log_printf("\n", 0); 1111 1112 fans_ks = ecp->fan_kstats[0]; 1113 log_printf("Bank Speed Status\n", 0); 1114 log_printf(" (0-255) \n", 0); 1115 log_printf("---- ----- ------\n", 0); 1116 if (fans_ks.fans_ok == B_TRUE) 1117 log_printf(" SYS %5d OK\n", fans_ks.fanspeed); 1118 else if (fans_ks.fans_ok != B_TRUE) { 1119 log_printf(" SYS %5d FAILED\n", fans_ks.fanspeed); 1120 exit_code = 1; 1121 } 1122 1123 log_printf("\n", 0); 1124 log_printf("=================================\n", 0); 1125 log_printf("\n", 0); 1126 log_printf("Power Supplies:\n", 0); 1127 log_printf("---------------\n", 0); 1128 log_printf("\n", 0); 1129 log_printf("Supply Status\n", 0); 1130 log_printf("------ ------\n", 0); 1131 1132 for (i = 0; i < ecp->num_ps_kstats; i++) { 1133 ps_ks = ecp->ps_kstats[i]; 1134 if (ps_ks.ps_ok == B_TRUE) 1135 (void) sprintf(state, "%s", " OK "); 1136 else if (ps_ks.ps_ok != B_TRUE) { 1137 (void) sprintf(state, "%s", "FAILED: DC " 1138 "Power Failure"); 1139 exit_code = 1; 1140 } 1141 1142 log_printf(" %2d %s\n", ps_ks.slot, state); 1143 } 1144 1145 return (exit_code); 1146 } 1147 1148 void 1149 tazjav_disp_asic_revs(Sys_tree *tree) 1150 { 1151 Board_node *bnode; 1152 Prom_node *pnode; 1153 char *name; 1154 int *version; 1155 char *model; 1156 1157 /* Print the header */ 1158 log_printf("\n", 0); 1159 log_printf("=========================", 0); 1160 log_printf(" HW Revisions ", 0); 1161 log_printf("=========================", 0); 1162 log_printf("\n", 0); 1163 log_printf("\n", 0); 1164 1165 bnode = tree->bd_list; 1166 1167 log_printf("ASIC Revisions:\n", 0); 1168 log_printf("---------------\n", 0); 1169 1170 /* Find sysio and print rev */ 1171 for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL; 1172 pnode = dev_next_node(pnode, "sbus")) { 1173 version = (int *)get_prop_val(find_prop(pnode, "version#")); 1174 name = get_prop_val(find_prop(pnode, "name")); 1175 1176 if ((version != NULL) && (name != NULL)) { 1177 log_printf("SBus: %s Rev %d\n", name, *version, 0); 1178 } 1179 } 1180 1181 /* Find Psycho and print rev */ 1182 for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL; 1183 pnode = dev_next_node(pnode, "pci")) { 1184 Prom_node *parsib = pnode->parent->sibling; 1185 1186 if (find_prop(pnode, "upa-portid") == NULL) { 1187 if ((parsib != NULL) && 1188 (strcmp(get_prop_val( 1189 find_prop(parsib, "name")), 1190 PCI_NAME) == 0)) 1191 pnode = parsib; 1192 else { 1193 pnode = parsib; 1194 continue; 1195 } 1196 } 1197 1198 version = (int *)get_prop_val(find_prop(pnode, "version#")); 1199 name = get_prop_val(find_prop(pnode, "name")); 1200 1201 if ((version != NULL) && (name != NULL)) 1202 if (get_pci_bus(pnode) == 0) 1203 log_printf("STP2223BGA: Rev %d\n", *version, 0); 1204 } 1205 1206 /* Find Cheerio and print rev */ 1207 for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL; 1208 pnode = dev_next_node(pnode, "ebus")) { 1209 version = (int *)get_prop_val(find_prop(pnode, "revision-id")); 1210 name = get_prop_val(find_prop(pnode, "name")); 1211 1212 if ((version != NULL) && (name != NULL)) 1213 log_printf("STP2003QFP: Rev %d\n", *version, 0); 1214 } 1215 1216 /* Find System Controller and print rev */ 1217 for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL; 1218 pnode = dev_next_node(pnode, "sc")) { 1219 version = (int *)get_prop_val(find_prop(pnode, "version#")); 1220 model = (char *)get_prop_val(find_prop(pnode, "model")); 1221 name = get_prop_val(find_prop(pnode, "name")); 1222 1223 if ((version != NULL) && (name != NULL)) { 1224 if ((strcmp(model, "SUNW,sc-marvin") == 0)) 1225 log_printf("STP2205BGA: Rev %d\n", *version, 0); 1226 } 1227 } 1228 1229 /* Find the FEPS and print rev */ 1230 for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL; 1231 pnode = dev_next_node(pnode, "SUNW,hme")) { 1232 version = (int *)get_prop_val(find_prop(pnode, "hm-rev")); 1233 name = get_prop_val(find_prop(pnode, "name")); 1234 1235 if ((version != NULL) && (name != NULL)) { 1236 log_printf("FEPS: %s Rev ", name); 1237 if (*version == 0xa0) { 1238 log_printf("2.0\n", 0); 1239 } else if (*version == 0x20) { 1240 log_printf("2.1\n", 0); 1241 } else { 1242 log_printf("%x\n", *version, 0); 1243 } 1244 } 1245 } 1246 log_printf("\n", 0); 1247 1248 if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) { 1249 display_ffb(bnode, 0); 1250 } 1251 } 1252 1253 1254 /* 1255 * Determine the physical PCI slot based on which Psycho is the parent 1256 * of the PCI card. 1257 */ 1258 static int 1259 tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str) 1260 { 1261 int *upa_id = NULL; 1262 int *reg = NULL; 1263 int offset; 1264 char controller[MAXSTRLEN]; 1265 char *name; 1266 Prop *prop; 1267 char *devpath_p; 1268 char slotx[16] = ""; 1269 int *slot_names_mask; 1270 char *slot_names; 1271 int shift = 0; 1272 int slot; 1273 int slots, start_slot; 1274 1275 /* 1276 * If slotd != NULL, then we must return the physical PCI slot 1277 * number based on the information in the slot2dev associations 1278 * node. This routine is called from display_pci() with slotd 1279 * != NULL. If so, we return without obtaining the slot name. 1280 * If slotd == NULL, we look for the slot name through the 1281 * slot-names property in the bus node. 1282 */ 1283 1284 if (slotd != NULL) { 1285 (void) strcpy(str, ""); 1286 if ((prop = find_prop(parent, "upa-portid")) != NULL) 1287 upa_id = (int *)(get_prop_val(prop)); 1288 if ((prop = find_prop(parent, "reg")) != NULL) 1289 reg = (int *)(get_prop_val(prop)); 1290 if ((prop = find_prop(parent, "name")) != NULL) 1291 name = (char *)(get_prop_val(prop)); 1292 if ((upa_id == NULL) || (reg == NULL)) { 1293 return (-1); 1294 } 1295 offset = reg[1]; 1296 if (strcmp(name, "pci") == 0) { 1297 (void) sprintf(controller, "/pci@%x,%x/*@%x,*", 1298 *upa_id, offset, device); 1299 slots = 20; 1300 } else if (strcmp(name, "SUNW,ffb") == 0) { 1301 (void) sprintf(controller, "/*@%x,0", *upa_id); 1302 slots = 2; 1303 } 1304 1305 /* 1306 * Javelin and future projects will use 0 based 1307 * numbering for slots. 1308 */ 1309 start_slot = 0; 1310 slots = slots - 1; 1311 for (slot = start_slot; slot <= slots; slot++) { 1312 if (strcmp(name, "pci") == 0) 1313 (void) sprintf(slotx, "pci-slot#%d", slot); 1314 else if (strcmp(name, "SUNW,ffb") == 0) 1315 (void) sprintf(slotx, "graphics#%d", slot); 1316 if ((prop = find_prop(slotd, slotx)) != NULL) 1317 if ((devpath_p = (char *)(get_prop_val 1318 (prop))) != NULL) 1319 if (strcmp(devpath_p, controller) == 0) 1320 return (slot); 1321 } 1322 return (-1); 1323 } 1324 1325 /* 1326 * Get slot-names property from parent node. 1327 * This property consists of a 32 bit mask indicating which 1328 * devices are relevant to this bus node. Following are a 1329 * number of strings depending on how many bits are set in the 1330 * bit mask; the first string gives the label that is printed 1331 * on the chassis for the smallest device number, and so on. 1332 */ 1333 1334 prop = find_prop(parent, "slot-names"); 1335 if (prop == NULL) { 1336 (void) strcpy(str, ""); 1337 return (-1); 1338 } 1339 slot_names_mask = (int *)(get_prop_val(prop)); 1340 slot_names = (char *)slot_names_mask; 1341 1342 slot = 1; 1343 slot_names += 4; /* Skip the 4 byte bitmask */ 1344 1345 while (shift < 32) { 1346 /* 1347 * Shift through the bitmask looking to see if the 1348 * bit corresponding to "device" is set. If so, copy 1349 * the correcsponding string to the provided pointer. 1350 */ 1351 if (*slot_names_mask & slot) { 1352 if (shift == device) { 1353 (void) strcpy(str, slot_names); 1354 return (0); 1355 } 1356 slot_names += strlen(slot_names)+1; 1357 } 1358 shift++; 1359 slot = slot << 1; 1360 } 1361 return (-1); 1362 } 1363