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