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