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