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 * Tazmo Platform specific functions. 27 * 28 * called when : 29 * machine_type == MTYPE_TAZMO 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_envctrl_status(Sys_tree *, struct system_kstat_data *); 87 static void check_disk_presence(Sys_tree *, int *, int *, int *); 88 static void modify_device_path(char *, char *); 89 static int disk_present(char *); 90 static void tazjav_disp_asic_revs(Sys_tree *); 91 static int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *); 92 static Prom_node *dev_next_node_sibling(Prom_node *root, char *name); 93 94 95 int 96 error_check(Sys_tree *tree, struct system_kstat_data *kstats) 97 { 98 int exit_code = 0; /* init to all OK */ 99 100 #ifdef lint 101 kstats = kstats; 102 #endif 103 /* 104 * silently check for any types of machine errors 105 */ 106 print_flag = 0; 107 if (disp_fail_parts(tree) || disp_envctrl_status(tree, kstats)) { 108 /* set exit_code to show failures */ 109 exit_code = 1; 110 } 111 print_flag = 1; 112 113 return (exit_code); 114 } 115 116 /* Search for and return the node's sibling */ 117 static Prom_node * 118 dev_next_node_sibling(Prom_node *root, char *name) 119 { 120 if (root == NULL) 121 return (NULL); 122 123 /* look at your siblings */ 124 if (dev_find_node(root->sibling, name) != NULL) 125 return (root->sibling); 126 127 return (NULL); /* not found */ 128 } 129 130 /* 131 * This function displays memory configurations specific to Tazmo/Javelin. 132 * The PROM device tree is read to obtain this information. 133 * Some of the information obtained is memory interleave factor, 134 * DIMM sizes, DIMM socket names. 135 */ 136 void 137 display_memoryconf(Sys_tree *tree, struct grp_info *grps) 138 { 139 Board_node *bnode; 140 Prom_node *memory; 141 Prom_node *bank; 142 Prom_node *dimm; 143 uint_t *preg; 144 uint_t interlv; 145 unsigned long size = 0; 146 int bank_count = 0; 147 char *sock_name; 148 char *status; 149 Prop *status_prop; 150 char interleave[8]; 151 int total_size = 0; 152 #ifdef lint 153 grps = grps; 154 #endif 155 156 log_printf("\n", 0); 157 log_printf("=========================", 0); 158 log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0); 159 log_printf("=========================", 0); 160 log_printf("\n", 0); 161 log_printf("\n", 0); 162 bnode = tree->bd_list; 163 memory = dev_find_node(bnode->nodes, "memory"); 164 preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave"))); 165 if (preg) { 166 interlv = preg[4]; 167 log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0); 168 } 169 log_printf(" Interlv. Socket Size\n", 0); 170 log_printf("Bank Group Name (MB) Status\n", 0); 171 log_printf("---- ----- ------ ---- ------\n", 0); 172 173 dimm = bnode->nodes; 174 for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL; 175 bank = dev_next_node(bank, "bank")) { 176 int bank_size = 0; 177 uint_t *reg_prop; 178 179 preg = (uint_t *)(get_prop_val( 180 find_prop(bank, "bank-interleave"))); 181 182 reg_prop = (uint_t *)(get_prop_val( 183 find_prop(bank, "reg"))); 184 185 /* 186 * Skip empty banks 187 */ 188 if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) { 189 bank_count++; 190 continue; 191 } 192 193 if (preg) { 194 interlv = preg[2]; 195 (void) sprintf(interleave, " %d ", interlv); 196 bank_size = (preg[0]<<12) + (preg[1]>>20); 197 } else { 198 (void) sprintf(interleave, "%s", "none"); 199 preg = (uint_t *)(get_prop_val(find_prop(bank, "reg"))); 200 if (preg) { 201 bank_size = (preg[2]<<12) + (preg[3]>>20); 202 } 203 } 204 for (dimm = dev_find_node(bank, "dimm"); dimm != NULL; 205 dimm = dev_next_node_sibling(dimm, "dimm")) { 206 char dimm_status[16]; 207 208 sock_name = (char *)(get_prop_val( 209 find_prop(dimm, "socket-name"))); 210 preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg"))); 211 size = (preg[2]<<12) + (preg[3]>>20); 212 if ((status_prop = find_prop(dimm, "status")) == NULL) { 213 (void) sprintf(dimm_status, "%s", "OK"); 214 } else { 215 status = (char *)(get_prop_val(status_prop)); 216 (void) sprintf(dimm_status, "%s", status); 217 } 218 log_printf("%3d %5s %6s %4d %6s\n", 219 bank_count, interleave, sock_name, 220 size, dimm_status, 0); 221 } 222 total_size += bank_size; 223 bank_count++; 224 } 225 log_printf("\n", 0); 226 } 227 228 /* 229 * disp_fail_parts 230 * 231 * Display the failed parts in the system. This function looks for 232 * the status property in all PROM nodes. On systems where 233 * the PROM does not supports passing diagnostic information 234 * thruogh the device tree, this routine will be silent. 235 */ 236 int 237 disp_fail_parts(Sys_tree *tree) 238 { 239 int exit_code; 240 int system_failed = 0; 241 Board_node *bnode = tree->bd_list; 242 Prom_node *pnode; 243 char *fru; 244 char *sock_name; 245 char slot_str[MAXSTRLEN]; 246 247 exit_code = 0; 248 249 /* go through all of the boards looking for failed units. */ 250 while (bnode != NULL) { 251 /* find failed chips */ 252 pnode = find_failed_node(bnode->nodes); 253 if ((pnode != NULL) && !system_failed) { 254 system_failed = 1; 255 exit_code = 1; 256 if (print_flag == 0) { 257 return (exit_code); 258 } 259 log_printf("\n", 0); 260 log_printf(dgettext(TEXT_DOMAIN, "Failed Field " 261 "Replaceable Units (FRU) in System:\n"), 0); 262 log_printf("==========================" 263 "====================\n", 0); 264 } 265 266 while (pnode != NULL) { 267 void *value; 268 char *name; /* node name string */ 269 char *type; /* node type string */ 270 271 value = get_prop_val(find_prop(pnode, "status")); 272 name = get_node_name(pnode); 273 274 /* sanity check of data retreived from PROM */ 275 if ((value == NULL) || (name == NULL)) { 276 pnode = next_failed_node(pnode); 277 continue; 278 } 279 280 281 log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"), 282 name, 0); 283 284 log_printf(dgettext(TEXT_DOMAIN, 285 "\tPROM fault string: %s\n"), 286 value, 0); 287 288 log_printf(dgettext(TEXT_DOMAIN, 289 "\tFailed Field Replaceable Unit is "), 0); 290 291 /* 292 * Determine whether FRU is CPU module, system 293 * board, or SBus card. 294 */ 295 if ((name != NULL) && (strstr(name, "sbus"))) { 296 297 log_printf(dgettext(TEXT_DOMAIN, "SBus " 298 "Card %d\n"), get_sbus_slot(pnode), 0); 299 300 } else if (((name = get_node_name(pnode)) != 301 NULL) && (strstr(name, "pci"))) { 302 303 log_printf(dgettext(TEXT_DOMAIN, 304 "system board\n"), 0); 305 306 } else if (((name = get_node_name(pnode)) != 307 NULL) && (strstr(name, "ffb"))) { 308 309 log_printf(dgettext(TEXT_DOMAIN, 310 "FFB Card %d\n"), 311 tazmo_physical_slot( 312 dev_find_node(bnode->nodes, "slot2dev"), 313 pnode, -1, slot_str), 0); 314 315 } else if (((name = get_node_name(pnode->parent)) != 316 NULL) && (strstr(name, "pci"))) { 317 318 (void) tazmo_physical_slot( 319 NULL, 320 pnode->parent, 321 get_pci_device(pnode), 322 slot_str); 323 log_printf(dgettext(TEXT_DOMAIN, 324 "PCI Card in %s\n"), slot_str, 0); 325 326 } else if (((type = get_node_type(pnode)) != NULL) && 327 (strstr(type, "cpu"))) { 328 329 log_printf( 330 dgettext(TEXT_DOMAIN, 331 "UltraSPARC module Module %d\n"), 332 get_id(pnode)); 333 334 } else if (((type = get_node_type(pnode)) != NULL) && 335 (strstr(type, "memory-module"))) { 336 337 fru = (char *)(get_prop_val( 338 find_prop(pnode, "fru"))); 339 sock_name = (char *)(get_prop_val( 340 find_prop(pnode, "socket-name"))); 341 log_printf( 342 dgettext(TEXT_DOMAIN, 343 "%s in socket %s\n"), 344 fru, sock_name, 0); 345 } 346 pnode = next_failed_node(pnode); 347 } 348 bnode = bnode->next; 349 } 350 351 if (!system_failed) { 352 log_printf("\n", 0); 353 log_printf(dgettext(TEXT_DOMAIN, 354 "No failures found in System\n"), 0); 355 log_printf("===========================\n", 0); 356 } 357 358 if (system_failed) 359 return (1); 360 else 361 return (0); 362 } 363 364 void 365 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats) 366 { 367 #ifdef lint 368 kstats = kstats; 369 #endif 370 /* Display failed units */ 371 (void) disp_fail_parts(tree); 372 } 373 374 375 void 376 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 377 struct system_kstat_data *kstats) 378 { 379 /* 380 * Now display the last powerfail time and the fatal hardware 381 * reset information. We do this under a couple of conditions. 382 * First if the user asks for it. The second is iof the user 383 * told us to do logging, and we found a system failure. 384 */ 385 if (flag) { 386 /* 387 * display time of latest powerfail. Not all systems 388 * have this capability. For those that do not, this 389 * is just a no-op. 390 */ 391 disp_powerfail(root); 392 393 (void) disp_envctrl_status(tree, kstats); 394 395 tazjav_disp_asic_revs(tree); 396 397 platform_disp_prom_version(tree); 398 } 399 return; 400 401 } 402 403 /* ARGSUSED */ 404 void 405 display_boardnum(int num) 406 { 407 log_printf("SYS ", 0); 408 } 409 410 411 412 /* 413 * display_pci 414 * Display all the PCI IO cards on this board. 415 */ 416 417 /* ARGSUSED */ 418 void 419 display_pci(Board_node *board) 420 { 421 struct io_card *card_list = NULL; 422 struct io_card card; 423 void *value; 424 Prom_node *pci; 425 Prom_node *card_node; 426 427 if (board == NULL) 428 return; 429 430 /* Initialize all the common information */ 431 card.display = 1; 432 card.board = board->board_num; 433 (void) sprintf(card.bus_type, "PCI"); 434 435 for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL; 436 pci = dev_next_node(pci, PCI_NAME)) { 437 char *name; 438 Prom_node *prev_parent = NULL; 439 int prev_device = -1; 440 int pci_pci_bridge = 0; 441 442 /* 443 * If we have reached a pci-to-pci bridge node, 444 * we are one level below the 'pci' nodes level 445 * in the device tree. To get back to that level, 446 * the search should continue with the sibling of 447 * the parent or else the remaining 'pci' cards 448 * will not show up in the output. 449 */ 450 if (find_prop(pci, "upa-portid") == NULL) { 451 if ((pci->parent->sibling != NULL) && 452 (strcmp(get_prop_val( 453 find_prop(pci->parent->sibling, 454 "name")), PCI_NAME) == 0)) 455 pci = pci->parent->sibling; 456 else { 457 pci = pci->parent->sibling; 458 continue; 459 } 460 } 461 462 /* Skip all failed nodes for now */ 463 if (node_failed(pci)) 464 continue; 465 466 /* Fill in frequency */ 467 value = get_prop_val(find_prop(pci, "clock-frequency")); 468 if (value == NULL) 469 card.freq = -1; 470 else 471 card.freq = ((*(int *)value) + 500000) / 1000000; 472 473 /* Walk through the PSYCHO children */ 474 card_node = pci->child; 475 while (card_node != NULL) { 476 Prop *compat = NULL; 477 478 /* If it doesn't have a name, skip it */ 479 name = (char *)get_prop_val( 480 find_prop(card_node, "name")); 481 if (name == NULL) { 482 card_node = card_node->sibling; 483 continue; 484 } 485 486 /* 487 * If this is a PCI bridge, then display its 488 * children. 489 */ 490 if (strcmp(name, "pci") == 0) { 491 card_node = card_node->child; 492 pci_pci_bridge = 1; 493 continue; 494 } 495 496 /* Get the slot number for this card */ 497 if (pci_pci_bridge) { 498 card.slot = tazmo_physical_slot( 499 dev_find_node(board->nodes, "slot2dev"), 500 pci, 501 get_pci_to_pci_device( 502 card_node->parent), 503 card.slot_str); 504 } else 505 card.slot = tazmo_physical_slot( 506 dev_find_node(board->nodes, 507 "slot2dev"), 508 pci, 509 get_pci_device(card_node), 510 card.slot_str); 511 512 /* 513 * Check that duplicate devices are not reported 514 * on Tazmo. 515 */ 516 if ((card_node->parent == prev_parent) && 517 (get_pci_device(card_node) == prev_device) && 518 (pci_pci_bridge == 0)) 519 card.slot = -1; 520 prev_parent = card_node->parent; 521 prev_device = get_pci_device(card_node); 522 523 524 if (card.slot == -1 || strstr(name, "ebus")) { 525 card_node = card_node->sibling; 526 continue; 527 } 528 529 /* XXX - Don't know how to get status for PCI cards */ 530 card.status[0] = '\0'; 531 532 /* Get the model of this card */ 533 value = get_prop_val(find_prop(card_node, "model")); 534 if (value == NULL) 535 card.model[0] = '\0'; 536 else 537 (void) sprintf(card.model, "%s", 538 (char *)value); 539 540 /* 541 * Check if further processing is necessary to display 542 * this card uniquely. 543 */ 544 distinguish_identical_io_cards(name, card_node, &card); 545 546 /* 547 * If we haven't figured out the frequency yet, 548 * try and get it from the card. 549 */ 550 value = get_prop_val(find_prop(pci, "clock-frequency")); 551 if (value != NULL && card.freq == -1) 552 card.freq = ((*(int *)value) + 500000) 553 / 1000000; 554 555 556 value = get_prop_val(find_prop(card_node, 557 "compatible")); 558 559 /* 560 * On Tazmo, we would like to print out the last 561 * string of the "compatible" property if it exists. 562 * The IEEE 1275 spec. states that this last string 563 * will be the classcode name. 564 */ 565 if (value != NULL) { 566 char *tval; 567 int index; 568 const int always = 1; 569 570 tval = (char *)value; 571 index = 0; 572 compat = find_prop(card_node, "compatible"); 573 while (always) { 574 if ((strlen(tval) + 1) == 575 (compat->size - index)) 576 break; 577 index += strlen(tval) + 1; 578 tval += strlen(tval) + 1; 579 } 580 value = (void *)tval; 581 } 582 583 if (value != NULL) 584 (void) sprintf(card.name, "%s-%s", 585 (char *)name, (char *)value); 586 else 587 (void) sprintf(card.name, "%s", 588 (char *)name); 589 590 if (card.freq != -1) 591 card_list = insert_io_card(card_list, &card); 592 593 /* 594 * If we are done with the children of the pci bridge, 595 * we must continue with the remaining siblings of 596 * the pci-to-pci bridge. 597 */ 598 if ((card_node->sibling == NULL) && pci_pci_bridge) { 599 card_node = card_node->parent->sibling; 600 pci_pci_bridge = 0; 601 } else 602 card_node = card_node->sibling; 603 } 604 } 605 606 display_io_cards(card_list); 607 free_io_cards(card_list); 608 } 609 610 611 /* 612 * Print out all the io cards in the list. Also print the column 613 * headers if told to do so. 614 */ 615 void 616 display_io_cards(struct io_card *list) 617 { 618 static int banner = 0; /* Have we printed the column headings? */ 619 struct io_card *p; 620 621 if (list == NULL) 622 return; 623 624 if (banner == 0) { 625 log_printf(" Bus Freq\n", 0); 626 log_printf("Brd Type MHz Slot " 627 "Name Model", 0); 628 log_printf("\n", 0); 629 log_printf("--- ---- ---- ---- " 630 "-------------------------------- " 631 "----------------------", 0); 632 log_printf("\n", 0); 633 banner = 1; 634 } 635 636 for (p = list; p != NULL; p = p -> next) { 637 log_printf("SYS ", p->board, 0); 638 log_printf("%-4s ", p->bus_type, 0); 639 log_printf("%3d ", p->freq, 0); 640 log_printf("%3d ", p->slot, 0); 641 log_printf("%-32.32s", p->name, 0); 642 if (strlen(p->name) > 32) 643 log_printf("+ ", 0); 644 else 645 log_printf(" ", 0); 646 log_printf("%-22.22s", p->model, 0); 647 if (strlen(p->model) > 22) 648 log_printf("+", 0); 649 log_printf("\n", 0); 650 } 651 } 652 653 /* 654 * display_ffb 655 * Display all FFBs on this board. It can either be in tabular format, 656 * or a more verbose format. 657 */ 658 void 659 display_ffb(Board_node *board, int table) 660 { 661 Prom_node *ffb; 662 void *value; 663 struct io_card *card_list = NULL; 664 struct io_card card; 665 666 if (board == NULL) 667 return; 668 669 /* Fill in common information */ 670 card.display = 1; 671 card.board = board->board_num; 672 (void) sprintf(card.bus_type, "UPA"); 673 card.freq = sys_clk; 674 675 for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL; 676 ffb = dev_next_node(ffb, FFB_NAME)) { 677 if (table == 1) { 678 /* Print out in table format */ 679 680 /* XXX - Get the slot number (hack) */ 681 card.slot = tazmo_physical_slot( 682 dev_find_node(board->nodes, "slot2dev"), 683 ffb, 684 -1, 685 card.slot_str); 686 687 /* Find out if it's single or double buffered */ 688 (void) sprintf(card.name, "FFB"); 689 value = get_prop_val(find_prop(ffb, "board_type")); 690 if (value != NULL) 691 if ((*(int *)value) & FFB_B_BUFF) 692 (void) sprintf(card.name, 693 "FFB, Double Buffered"); 694 else 695 (void) sprintf(card.name, 696 "FFB, Single Buffered"); 697 698 /* Print model number */ 699 card.model[0] = '\0'; 700 value = get_prop_val(find_prop(ffb, "model")); 701 if (value != NULL) 702 (void) sprintf(card.model, "%s", 703 (char *)value); 704 705 card_list = insert_io_card(card_list, &card); 706 } else { 707 /* print in long format */ 708 char device[MAXSTRLEN]; 709 int fd = -1; 710 struct dirent *direntp; 711 DIR *dirp; 712 union strap_un strap; 713 struct ffb_sys_info fsi; 714 715 /* Find the device node using upa address */ 716 value = get_prop_val(find_prop(ffb, "upa-portid")); 717 if (value == NULL) 718 continue; 719 720 (void) sprintf(device, "%s@%x", FFB_NAME, 721 *(int *)value); 722 if ((dirp = opendir("/devices")) == NULL) 723 continue; 724 725 while ((direntp = readdir(dirp)) != NULL) { 726 if (strstr(direntp->d_name, device) != NULL) { 727 (void) sprintf(device, "/devices/%s", 728 direntp->d_name); 729 fd = open(device, O_RDWR, 0666); 730 break; 731 } 732 } 733 (void) closedir(dirp); 734 735 if (fd == -1) 736 continue; 737 738 if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0) 739 continue; 740 741 log_printf("FFB Hardware Configuration:\n", 0); 742 log_printf("-----------------------------------\n", 0); 743 744 strap.ffb_strap_bits = fsi.ffb_strap_bits; 745 log_printf("\tBoard rev: %d\n", 746 (int)strap.fld.board_rev, 0); 747 log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0); 748 log_printf("\tDAC: %s\n", 749 fmt_manf_id(fsi.dac_version, device), 0); 750 log_printf("\t3DRAM: %s\n", 751 fmt_manf_id(fsi.fbram_version, device), 0); 752 log_printf("\n", 0); 753 } 754 } 755 756 display_io_cards(card_list); 757 free_io_cards(card_list); 758 } 759 760 /* 761 * This module does the reading and interpreting of tazmo system 762 * kstats. These kstats are created by the environ driver: 763 */ 764 void 765 read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat, 766 struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep) 767 { 768 kstat_ctl_t *kc; 769 kstat_t *ksp; 770 771 if ((kc = kstat_open()) == NULL) { 772 return; 773 } 774 #ifdef lint 775 tree = tree; 776 bdp = bdp; 777 #endif 778 779 ep = &sys_kstat->env_data; 780 781 /* Read the power supply kstats */ 782 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0, 783 ENVCTRL_KSTAT_PSNAME); 784 785 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) { 786 (void) memcpy(ep->ps_kstats, ksp->ks_data, 787 MAX_DEVS * sizeof (envctrl_ps_t)); 788 } else { 789 sys_kstat->envctrl_kstat_ok = B_FALSE; 790 return; 791 } 792 793 /* Read the fan status kstats */ 794 ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0, 795 ENVCTRL_KSTAT_FANSTAT); 796 797 if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) { 798 (void) memcpy(ep->fan_kstats, ksp->ks_data, 799 ksp->ks_ndata * sizeof (envctrl_fan_t)); 800 } else { 801 sys_kstat->envctrl_kstat_ok = B_FALSE; 802 return; 803 } 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(ep->encl_kstats, ksp->ks_data, 811 ksp->ks_ndata * sizeof (envctrl_encl_t)); 812 } else { 813 sys_kstat->envctrl_kstat_ok = B_FALSE; 814 return; 815 } 816 817 sys_kstat->envctrl_kstat_ok = B_TRUE; 818 } 819 820 /* 821 * Walk the PROM device tree and build the system tree and root tree. 822 * Nodes that have a board number property are placed in the board 823 * structures for easier processing later. Child nodes are placed 824 * under their parents. ffb (Fusion Frame Buffer) nodes are handled 825 * specially, because they do not contain board number properties. 826 * This was requested from OBP, but was not granted. So this code 827 * must parse the MID of the FFB to find the board#. 828 */ 829 Prom_node * 830 walk(Sys_tree *tree, Prom_node *root, int id) 831 { 832 register int curnode; 833 Prom_node *pnode; 834 char *name; 835 char *type; 836 char *model; 837 int board_node = 0; 838 839 /* allocate a node for this level */ 840 if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) == 841 NULL) { 842 perror("malloc"); 843 exit(2); /* program errors cause exit 2 */ 844 } 845 846 /* assign parent Prom_node */ 847 pnode->parent = root; 848 pnode->sibling = NULL; 849 pnode->child = NULL; 850 851 /* read properties for this node */ 852 dump_node(pnode); 853 854 /* 855 * Place a node in a 'board' if it has 'board'-ness. The definition 856 * is that all nodes that are children of root should have a 857 * board# property. But the PROM tree does not exactly follow 858 * this. This is where we start hacking. The name 'ffb' can 859 * change, so watch out for this. 860 * 861 * The UltraSPARC, sbus, pci and ffb nodes will exit in 862 * the desktops and will not have board# properties. These 863 * cases must be handled here. 864 * 865 * PCI to PCI bridges also have the name "pci", but with different 866 * model property values. They should not be put under 'board'. 867 */ 868 name = get_node_name(pnode); 869 type = get_node_type(pnode); 870 model = (char *)get_prop_val(find_prop(pnode, "model")); 871 #ifdef DEBUG 872 if (name != NULL) 873 printf("name=%s ", name); 874 if (type != NULL) 875 printf("type=%s ", type); 876 if (model != NULL) 877 printf("model=%s", model); 878 printf("\n"); 879 880 if (model == NULL) 881 model = ""; 882 #endif 883 if (type == NULL) 884 type = ""; 885 if (name != NULL) { 886 if (has_board_num(pnode)) { 887 add_node(tree, pnode); 888 board_node = 1; 889 #ifdef DEBUG 890 printf("ADDED BOARD name=%s type=%s model=%s\n", 891 name, type, model); 892 #endif 893 } else if ((strcmp(name, FFB_NAME) == 0) || 894 (strcmp(type, "cpu") == 0) || 895 896 ((strcmp(name, "pci") == 0) && (model != NULL) && 897 (strcmp(model, "SUNW,psycho") == 0)) || 898 899 ((strcmp(name, "pci") == 0) && (model != NULL) && 900 (strcmp(model, "SUNW,sabre") == 0)) || 901 902 (strcmp(name, "counter-timer") == 0) || 903 (strcmp(name, "sbus") == 0) || 904 (strcmp(name, "memory") == 0) || 905 (strcmp(name, "mc") == 0) || 906 (strcmp(name, "associations") == 0)) { 907 add_node(tree, pnode); 908 board_node = 1; 909 #ifdef DEBUG 910 printf("ADDED BOARD name=%s type=%s model=%s\n", 911 name, type, model); 912 #endif 913 } 914 #ifdef DEBUG 915 else 916 printf("node not added: name=%s type=%s\n", name, type); 917 #endif 918 } 919 920 if (curnode = child(id)) { 921 pnode->child = walk(tree, pnode, curnode); 922 } 923 924 if (curnode = next(id)) { 925 if (board_node) { 926 return (walk(tree, root, curnode)); 927 } else { 928 pnode->sibling = walk(tree, root, curnode); 929 } 930 } 931 932 if (board_node) { 933 return (NULL); 934 } else { 935 return (pnode); 936 } 937 } 938 939 /* 940 * local functions 941 */ 942 943 /* 944 * disp_envctrl_status 945 * 946 * This routine displays the environmental status passed up from 947 * device drivers via kstats. The kstat names are defined in 948 * kernel header files included by this module. 949 */ 950 static int 951 disp_envctrl_status(Sys_tree *tree, struct system_kstat_data *sys_kstats) 952 { 953 int exit_code = 0; 954 int possible_failure; 955 int i; 956 uchar_t val; 957 char fan_type[16]; 958 char state[48]; 959 char name[16]; 960 envctrl_ps_t ps; 961 envctrl_fan_t fan; 962 envctrl_encl_t encl; 963 struct envctrl_kstat_data *ep; 964 uchar_t fsp_value; 965 int i4slot_backplane_value = -1; 966 int i8slot_backplane_value = -1; 967 int j8slot_backplane_value = -1; 968 static int first_8disk_bp = 0; 969 static int second_8disk_bp = 0; 970 static int first_4disk_bp = 0; 971 972 if (sys_kstats->envctrl_kstat_ok == 0) { 973 log_printf("\n", 0); 974 log_printf(dgettext(TEXT_DOMAIN, "Environmental information " 975 "is not available\n"), 0); 976 log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may " 977 "not be installed\n"), 0); 978 log_printf("\n", 0); 979 return (1); 980 } 981 982 ep = &sys_kstats->env_data; 983 984 check_disk_presence(tree, &first_4disk_bp, &first_8disk_bp, 985 &second_8disk_bp); 986 987 log_printf("\n", 0); 988 log_printf("=========================", 0); 989 log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0); 990 log_printf("=========================", 0); 991 log_printf("\n", 0); 992 log_printf("\n", 0); 993 994 log_printf("System Temperatures (Celsius):\n", 0); 995 log_printf("------------------------------\n", 0); 996 for (i = 0; i < MAX_DEVS; i++) { 997 encl = ep->encl_kstats[i]; 998 switch (encl.type) { 999 case ENVCTRL_ENCL_AMBTEMPR: 1000 if (encl.instance == I2C_NODEV) 1001 continue; 1002 (void) sprintf(name, "%s", "AMBIENT"); 1003 log_printf("%s %d", name, encl.value); 1004 if (encl.value > MAX_AMB_TEMP) { 1005 log_printf(" WARNING\n", 0); 1006 exit_code = 1; 1007 } else 1008 log_printf("\n", 0); 1009 break; 1010 case ENVCTRL_ENCL_CPUTEMPR: 1011 if (encl.instance == I2C_NODEV) 1012 continue; 1013 (void) sprintf(name, "%s %d", "CPU", encl.instance); 1014 log_printf("%s %d", name, encl.value); 1015 if (encl.value > MAX_CPU_TEMP) { 1016 log_printf(" WARNING\n", 0); 1017 exit_code = 1; 1018 } else 1019 log_printf("\n", 0); 1020 break; 1021 case ENVCTRL_ENCL_FSP: 1022 if (encl.instance == I2C_NODEV) 1023 continue; 1024 val = encl.value & ENVCTRL_FSP_KEYMASK; 1025 fsp_value = encl.value; 1026 switch (val) { 1027 case ENVCTRL_FSP_KEYOFF: 1028 (void) sprintf(state, "%s", "Off"); 1029 break; 1030 case ENVCTRL_FSP_KEYON: 1031 (void) sprintf(state, "%s", "On"); 1032 break; 1033 case ENVCTRL_FSP_KEYDIAG: 1034 (void) sprintf(state, "%s", "Diagnostic"); 1035 break; 1036 case ENVCTRL_FSP_KEYLOCKED: 1037 (void) sprintf(state, "%s", "Secure"); 1038 break; 1039 default: 1040 (void) sprintf(state, "%s", "Broken!"); 1041 exit_code = 1; 1042 break; 1043 } 1044 break; 1045 case ENVCTRL_ENCL_BACKPLANE4: 1046 case ENVCTRL_ENCL_BACKPLANE8: 1047 if (encl.instance == I2C_NODEV) 1048 continue; 1049 switch (encl.instance) { 1050 case 0: 1051 i4slot_backplane_value = 1052 encl.value & ENVCTRL_4SLOT_BACKPLANE; 1053 break; 1054 case 1: 1055 i8slot_backplane_value = 1056 encl.value & ENVCTRL_8SLOT_BACKPLANE; 1057 break; 1058 case 2: 1059 j8slot_backplane_value = 1060 encl.value & ENVCTRL_8SLOT_BACKPLANE; 1061 break; 1062 } 1063 default: 1064 break; 1065 } 1066 } 1067 1068 log_printf("=================================\n\n", 0); 1069 log_printf("Front Status Panel:\n", 0); 1070 log_printf("-------------------\n", 0); 1071 log_printf("Keyswitch position is in %s mode.\n", state); 1072 log_printf("\n", 0); 1073 val = fsp_value & (ENVCTRL_FSP_DISK_ERR | ENVCTRL_FSP_PS_ERR | 1074 ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_GEN_ERR | 1075 ENVCTRL_FSP_ACTIVE); 1076 log_printf("System LED Status: POWER GENERAL ERROR " 1077 " ACTIVITY\n", 0); 1078 log_printf(" [ ON] [%3s] " 1079 " [%3s]\n", val & ENVCTRL_FSP_GEN_ERR ? "ON" : "OFF", 1080 val & ENVCTRL_FSP_ACTIVE ? "ON" : "OFF"); 1081 log_printf(" DISK ERROR " 1082 "THERMAL ERROR POWER SUPPLY ERROR\n", 0); 1083 log_printf(" [%3s] [%3s] " 1084 " [%3s]\n", val & ENVCTRL_FSP_DISK_ERR ? "ON" : "OFF", 1085 val & ENVCTRL_FSP_TEMP_ERR ? "ON" : "OFF", 1086 val & ENVCTRL_FSP_PS_ERR ? "ON" : "OFF"); 1087 log_printf("\n", 0); 1088 /* record error conditions */ 1089 if (val & (ENVCTRL_FSP_GEN_ERR | ENVCTRL_FSP_DISK_ERR | 1090 ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_PS_ERR)) { 1091 exit_code = 1; 1092 } 1093 1094 1095 log_printf("Disk LED Status: OK = GREEN ERROR = YELLOW\n", 0); 1096 1097 if (j8slot_backplane_value != -1) { 1098 log_printf(" DISK 18: %7s DISK 19: %7s\n", 1099 second_8disk_bp & ENVCTRL_DISK_6 ? 1100 j8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]" 1101 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_7 ? 1102 j8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]" 1103 : "[EMPTY]"); 1104 log_printf(" DISK 16: %7s DISK 17: %7s\n", 1105 second_8disk_bp & ENVCTRL_DISK_4 ? 1106 j8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]" 1107 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_5 ? 1108 j8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]" 1109 : "[EMPTY]"); 1110 log_printf(" DISK 14: %7s DISK 15: %7s\n", 1111 second_8disk_bp & ENVCTRL_DISK_2 ? 1112 j8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]" 1113 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_3 ? 1114 j8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]" 1115 : "[EMPTY]"); 1116 log_printf(" DISK 12: %7s DISK 13: %7s\n", 1117 second_8disk_bp & ENVCTRL_DISK_0 ? 1118 j8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]" 1119 : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_1 ? 1120 j8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]" 1121 : "[EMPTY]"); 1122 } 1123 if (i8slot_backplane_value != -1) { 1124 log_printf(" DISK 10: %7s DISK 11: %7s\n", 1125 first_8disk_bp & ENVCTRL_DISK_6 ? 1126 i8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]" 1127 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_7 ? 1128 i8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]" 1129 : "[EMPTY]"); 1130 log_printf(" DISK 8: %7s DISK 9: %7s\n", 1131 first_8disk_bp & ENVCTRL_DISK_4 ? 1132 i8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]" 1133 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_5 ? 1134 i8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]" 1135 : "[EMPTY]"); 1136 log_printf(" DISK 6: %7s DISK 7: %7s\n", 1137 first_8disk_bp & ENVCTRL_DISK_2 ? 1138 i8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]" 1139 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_3 ? 1140 i8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]" 1141 : "[EMPTY]"); 1142 log_printf(" DISK 4: %7s DISK 5: %7s\n", 1143 first_8disk_bp & ENVCTRL_DISK_0 ? 1144 i8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]" 1145 : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_1 ? 1146 i8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]" 1147 : "[EMPTY]"); 1148 } 1149 if (i4slot_backplane_value != -1) { 1150 log_printf(" DISK 2: %7s DISK 3: %7s\n", 1151 first_4disk_bp & ENVCTRL_DISK_2 ? 1152 i4slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]" 1153 : "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_3 ? 1154 i4slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]" 1155 : "[EMPTY]"); 1156 log_printf(" DISK 0: %7s DISK 1: %7s\n", 1157 first_4disk_bp & ENVCTRL_DISK_0 ? 1158 i4slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]" 1159 : "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_1 ? 1160 i4slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]" 1161 : "[EMPTY]"); 1162 } 1163 1164 log_printf("=================================\n", 0); 1165 log_printf("\n", 0); 1166 1167 log_printf("Fans:\n", 0); 1168 log_printf("-----\n", 0); 1169 1170 log_printf("Fan Bank Speed Status\n", 0); 1171 log_printf("-------- ----- ------\n", 0); 1172 1173 for (i = 0; i < MAX_DEVS; i++) { 1174 fan = ep->fan_kstats[i]; 1175 1176 if (fan.instance == I2C_NODEV) 1177 continue; 1178 1179 switch (fan.type) { 1180 case ENVCTRL_FAN_TYPE_CPU: 1181 (void) sprintf(fan_type, "%s", "CPU"); 1182 break; 1183 case ENVCTRL_FAN_TYPE_PS: 1184 (void) sprintf(fan_type, "%s", "PWR"); 1185 break; 1186 case ENVCTRL_FAN_TYPE_AFB: 1187 (void) sprintf(fan_type, "%s", "AFB"); 1188 break; 1189 } 1190 if (fan.fans_ok == B_TRUE) { 1191 (void) sprintf(state, "%s", " OK "); 1192 } else { 1193 (void) sprintf(state, "FAILED (FAN# %d)", 1194 fan.fanflt_num); 1195 /* we know fan.instance != I2C_NODEV */ 1196 exit_code = 1; 1197 } 1198 if (fan.instance != I2C_NODEV) 1199 log_printf("%s %d %s\n", fan_type, 1200 fan.fanspeed, state); 1201 } 1202 1203 1204 log_printf("\n", 0); 1205 1206 log_printf("\n", 0); 1207 log_printf("Power Supplies:\n", 0); 1208 log_printf("---------------\n", 0); 1209 log_printf("Supply Rating Temp Status\n", 0); 1210 log_printf("------ ------ ---- ------\n", 0); 1211 for (i = 0; i < MAX_DEVS; i++) { 1212 ps = ep->ps_kstats[i]; 1213 if (ps.curr_share_ok == B_TRUE && 1214 ps.limit_ok == B_TRUE && ps.ps_ok == B_TRUE) { 1215 (void) sprintf(state, "%s", " OK "); 1216 possible_failure = 0; 1217 } else { 1218 if (ps.ps_ok != B_TRUE) { 1219 (void) sprintf(state, "%s", 1220 "FAILED: DC Power Failure"); 1221 possible_failure = 1; 1222 } else if (ps.curr_share_ok != B_TRUE) { 1223 (void) sprintf(state, "%s", 1224 "WARNING: Current Share Imbalance"); 1225 possible_failure = 1; 1226 } else if (ps.limit_ok != B_TRUE) { 1227 (void) sprintf(state, "%s", 1228 "WARNING: Current Overload"); 1229 possible_failure = 1; 1230 } 1231 } 1232 1233 if (ps.instance != I2C_NODEV && ps.ps_rating != 0) { 1234 log_printf(" %2d %4d W %2d %s\n", 1235 ps.instance, ps.ps_rating, ps.ps_tempr, state); 1236 if (possible_failure) 1237 exit_code = 1; 1238 } 1239 } 1240 1241 return (exit_code); 1242 } 1243 1244 /* 1245 * This function will return a bitmask for each of the 4 disk backplane 1246 * and the two 8 disk backplanes. It creates this mask by first obtaining 1247 * the PROM path of the controller for each slot using the "slot2dev" 1248 * node in the PROM tree. It then modifies the PROM path to obtain a 1249 * physical device path to the controller. The presence of the controller 1250 * is determined by trying to open the controller device and reading 1251 * some information from the device. Currently only supported on Tazmo. 1252 */ 1253 static void 1254 check_disk_presence(Sys_tree *tree, int *i4disk, int *i8disk, int *j8disk) 1255 { 1256 Board_node *bnode; 1257 Prom_node *slot2disk = NULL; 1258 Prop *slotprop; 1259 char *devpath_p; 1260 char devpath[MAXSTRLEN]; 1261 char slotx[16] = ""; 1262 int slot; 1263 int slot_ptr = 0; 1264 1265 bnode = tree->bd_list; 1266 *i4disk = *i8disk, *j8disk = 0; 1267 1268 slot2disk = dev_find_node(bnode->nodes, "slot2disk"); 1269 1270 for (slot = 0; slot < 20; slot++) { 1271 (void) sprintf(slotx, "slot#%d", slot); 1272 if ((slotprop = find_prop(slot2disk, slotx)) != NULL) 1273 if ((devpath_p = (char *)(get_prop_val(slotprop))) 1274 != NULL) { 1275 modify_device_path(devpath_p, devpath); 1276 if (disk_present(devpath)) { 1277 if (slot < 4) 1278 *i4disk |= 1 << slot_ptr; 1279 else if (slot < 12) 1280 *i8disk |= 1 << slot_ptr; 1281 else if (slot < 20) 1282 *j8disk |= 1 << slot_ptr; 1283 } 1284 } 1285 if ((slot == 3) || (slot == 11)) 1286 slot_ptr = 0; 1287 else 1288 slot_ptr++; 1289 } 1290 } 1291 1292 1293 1294 /* 1295 * modify_device_path 1296 * 1297 * This function modifies a string from the slot2disk association 1298 * PROM node to a physical device path name. For example if the 1299 * slot2disk association value is "/pci@1f,4000/scsi@3/disk@1", 1300 * the equivalent physical device path will be 1301 * "/devices/pci@1f,4000/scsi@3/sd@1,0:c,raw". 1302 * We use this path to attempt to probe the disk to check for its 1303 * presence in the enclosure. We access the 'c' partition 1304 * which represents the entire disk. 1305 */ 1306 static void 1307 modify_device_path(char *oldpath, char *newpath) 1308 { 1309 char *changeptr; 1310 long target; 1311 char targetstr[16]; 1312 1313 (void) strcpy(newpath, "/devices"); 1314 changeptr = strstr(oldpath, "disk@"); 1315 /* 1316 * The assumption here is that nothing but the 1317 * target id follows the disk@ substring. 1318 */ 1319 target = strtol(changeptr+5, NULL, 16); 1320 (void) strncat(newpath, oldpath, changeptr - oldpath); 1321 (void) sprintf(targetstr, "sd@%ld,0:c,raw", target); 1322 (void) strcat(newpath, targetstr); 1323 } 1324 1325 /* 1326 * Returns 0 if the device at devpath is not *physically* present. If it is, 1327 * then info on that device is placed in the dkinfop buffer, and 1 is returned. 1328 * Keep in mind that ioctl(DKIOCINFO)'s CDROMs owned by vold fail, so only 1329 * the dki_ctype field is set in that case. 1330 */ 1331 static int 1332 disk_present(char *devpath) 1333 { 1334 int search_file; 1335 struct stat stbuf; 1336 struct dk_cinfo dkinfo; 1337 1338 /* 1339 * Attempt to open the disk. If it fails, skip it. 1340 */ 1341 if ((search_file = open(devpath, O_RDONLY | O_NDELAY)) < 0) 1342 return (0); 1343 1344 /* 1345 * Must be a character device 1346 */ 1347 if (fstat(search_file, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) { 1348 (void) close(search_file); 1349 return (0); 1350 } 1351 1352 /* 1353 * Attempt to read the configuration info on the disk. 1354 * If it fails, we assume the disk's not there. 1355 * Note we must close the file for the disk before we 1356 * continue. 1357 */ 1358 if (ioctl(search_file, DKIOCINFO, &dkinfo) < 0) { 1359 (void) close(search_file); 1360 return (0); 1361 } 1362 (void) close(search_file); 1363 return (1); 1364 } 1365 1366 void 1367 tazjav_disp_asic_revs(Sys_tree *tree) 1368 { 1369 Board_node *bnode; 1370 Prom_node *pnode; 1371 char *name; 1372 int *version; 1373 char *model; 1374 1375 /* Print the header */ 1376 log_printf("\n", 0); 1377 log_printf("=========================", 0); 1378 log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0); 1379 log_printf("=========================", 0); 1380 log_printf("\n", 0); 1381 log_printf("\n", 0); 1382 1383 bnode = tree->bd_list; 1384 1385 log_printf("ASIC Revisions:\n", 0); 1386 log_printf("---------------\n", 0); 1387 1388 /* Find sysio and print rev */ 1389 for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL; 1390 pnode = dev_next_node(pnode, "sbus")) { 1391 version = (int *)get_prop_val(find_prop(pnode, "version#")); 1392 name = get_prop_val(find_prop(pnode, "name")); 1393 1394 if ((version != NULL) && (name != NULL)) { 1395 log_printf("SBus: %s Rev %d\n", 1396 name, *version, 0); 1397 } 1398 } 1399 1400 /* Find Psycho and print rev */ 1401 for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL; 1402 pnode = dev_next_node(pnode, "pci")) { 1403 Prom_node *parsib = pnode->parent->sibling; 1404 1405 if (find_prop(pnode, "upa-portid") == NULL) { 1406 if ((parsib != NULL) && 1407 (strcmp(get_prop_val( 1408 find_prop(parsib, "name")), 1409 PCI_NAME) == 0)) 1410 pnode = parsib; 1411 else { 1412 pnode = parsib; 1413 continue; 1414 } 1415 } 1416 1417 version = (int *)get_prop_val(find_prop(pnode, "version#")); 1418 name = get_prop_val(find_prop(pnode, "name")); 1419 1420 if ((version != NULL) && (name != NULL)) 1421 if (get_pci_bus(pnode) == 0) 1422 log_printf("STP2223BGA: Rev %d\n", *version, 0); 1423 } 1424 1425 /* Find Cheerio and print rev */ 1426 for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL; 1427 pnode = dev_next_node(pnode, "ebus")) { 1428 version = (int *)get_prop_val(find_prop(pnode, "revision-id")); 1429 name = get_prop_val(find_prop(pnode, "name")); 1430 1431 if ((version != NULL) && (name != NULL)) 1432 log_printf("STP2003QFP: Rev %d\n", *version, 0); 1433 } 1434 1435 /* Find System Controller and print rev */ 1436 for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL; 1437 pnode = dev_next_node(pnode, "sc")) { 1438 version = (int *)get_prop_val(find_prop(pnode, "version#")); 1439 model = (char *)get_prop_val(find_prop(pnode, "model")); 1440 name = get_prop_val(find_prop(pnode, "name")); 1441 1442 if ((version != NULL) && (name != NULL)) { 1443 if ((strcmp(model, "SUNW,sc-marvin") == 0)) 1444 log_printf("STP2205BGA: Rev %d\n", *version, 0); 1445 } 1446 } 1447 1448 /* Find the FEPS and print rev */ 1449 for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL; 1450 pnode = dev_next_node(pnode, "SUNW,hme")) { 1451 version = (int *)get_prop_val(find_prop(pnode, "hm-rev")); 1452 name = get_prop_val(find_prop(pnode, "name")); 1453 1454 if ((version != NULL) && (name != NULL)) { 1455 log_printf("FEPS: %s Rev ", name); 1456 if (*version == 0xa0) { 1457 log_printf("2.0\n", 0); 1458 } else if (*version == 0x20) { 1459 log_printf("2.1\n", 0); 1460 } else { 1461 log_printf("%x\n", *version, 0); 1462 } 1463 } 1464 } 1465 log_printf("\n", 0); 1466 1467 if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) { 1468 display_ffb(bnode, 0); 1469 } 1470 } 1471 1472 1473 /* 1474 * Determine the physical PCI slot based on which Psycho is the parent 1475 * of the PCI card. 1476 */ 1477 static int 1478 tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str) 1479 { 1480 int *upa_id = NULL; 1481 int *reg = NULL; 1482 int offset; 1483 char controller[MAXSTRLEN]; 1484 char *name; 1485 Prop *prop; 1486 char *devpath_p; 1487 char slotx[16] = ""; 1488 int *slot_names_mask; 1489 char *slot_names; 1490 int shift = 0; 1491 int slot; 1492 int slots, start_slot; 1493 1494 /* 1495 * If slotd != NULL, then we must return the physical PCI slot 1496 * number based on the information in the slot2dev associations 1497 * node. This routine is called from display_pci() with slotd 1498 * != NULL. If so, we return without obtaining the slot name. 1499 * If slotd == NULL, we look for the slot name through the 1500 * slot-names property in the bus node. 1501 */ 1502 1503 if (slotd != NULL) { 1504 (void) strcpy(str, ""); 1505 if ((prop = find_prop(parent, "upa-portid")) != NULL) 1506 upa_id = (int *)(get_prop_val(prop)); 1507 if ((prop = find_prop(parent, "reg")) != NULL) 1508 reg = (int *)(get_prop_val(prop)); 1509 if ((prop = find_prop(parent, "name")) != NULL) 1510 name = (char *)(get_prop_val(prop)); 1511 if ((upa_id == NULL) || (reg == NULL)) { 1512 return (-1); 1513 } 1514 offset = reg[1]; 1515 if (strcmp(name, "pci") == 0) { 1516 (void) sprintf(controller, "/pci@%x,%x/*@%x,*", 1517 *upa_id, offset, device); 1518 slots = 20; 1519 } else if (strcmp(name, "SUNW,ffb") == 0) { 1520 (void) sprintf(controller, "/*@%x,0", *upa_id); 1521 slots = 2; 1522 } 1523 1524 start_slot = 1; 1525 for (slot = start_slot; slot <= slots; slot++) { 1526 if (strcmp(name, "pci") == 0) 1527 (void) sprintf(slotx, "pci-slot#%d", slot); 1528 else if (strcmp(name, "SUNW,ffb") == 0) 1529 (void) sprintf(slotx, "graphics#%d", slot); 1530 if ((prop = find_prop(slotd, slotx)) != NULL) 1531 if ((devpath_p = (char *)(get_prop_val 1532 (prop))) != NULL) 1533 if (strcmp(devpath_p, controller) == 1534 NULL) 1535 return (slot); 1536 } 1537 return (-1); 1538 } 1539 1540 /* 1541 * Get slot-names property from parent node. 1542 * This property consists of a 32 bit mask indicating which 1543 * devices are relevant to this bus node. Following are a 1544 * number of strings depending on how many bits are set in the 1545 * bit mask; the first string gives the label that is printed 1546 * on the chassis for the smallest device number, and so on. 1547 */ 1548 1549 prop = find_prop(parent, "slot-names"); 1550 if (prop == NULL) { 1551 (void) strcpy(str, ""); 1552 return (-1); 1553 } 1554 slot_names_mask = (int *)(get_prop_val(prop)); 1555 slot_names = (char *)slot_names_mask; 1556 1557 slot = 1; 1558 slot_names += 4; /* Skip the 4 byte bitmask */ 1559 1560 while (shift < 32) { 1561 /* 1562 * Shift through the bitmask looking to see if the 1563 * bit corresponding to "device" is set. If so, copy 1564 * the correcsponding string to the provided pointer. 1565 */ 1566 if (*slot_names_mask & slot) { 1567 if (shift == device) { 1568 (void) strcpy(str, slot_names); 1569 return (0); 1570 } 1571 slot_names += strlen(slot_names)+1; 1572 } 1573 shift++; 1574 slot = slot << 1; 1575 } 1576 return (-1); 1577 } 1578