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