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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2020 Peter Tribble. 25 * 26 * Serengeti Platform specific functions. 27 * 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <kstat.h> 34 #include <string.h> 35 #include <assert.h> 36 #include <alloca.h> 37 #include <libintl.h> 38 #include <fcntl.h> 39 #include <varargs.h> 40 41 #include <sys/openpromio.h> 42 #include <sys/sysmacros.h> 43 44 #include <sys/serengeti.h> 45 #include <sys/sgfrutypes.h> 46 47 #include <pdevinfo.h> 48 #include <display.h> 49 #include <pdevinfo_sun4u.h> 50 #include <display_sun4u.h> 51 #include <libprtdiag.h> 52 53 #include <config_admin.h> 54 55 #if !defined(TEXT_DOMAIN) 56 #define TEXT_DOMAIN "SYS_TEST" 57 #endif 58 59 #define SCHIZO_COMPATIBLE "pci108e,8001" 60 #define XMITS_COMPATIBLE "pci108e,8002" 61 62 #define ACTIVE 0 63 #define INACTIVE 1 64 #define DISPLAY_INFO 40 65 66 #define EVNT2STR(e) ((e) == CFGA_STAT_NONE ? "none" : \ 67 (e) == CFGA_STAT_EMPTY ? "empty" : \ 68 (e) == CFGA_STAT_DISCONNECTED ? "disconnected" : \ 69 (e) == CFGA_STAT_CONNECTED ? "connected" : \ 70 (e) == CFGA_STAT_UNCONFIGURED ? "unconfigured" : \ 71 (e) == CFGA_STAT_CONFIGURED ? "configured" : \ 72 "unknown") 73 74 #define COND2STR(c) ((c) == CFGA_COND_UNKNOWN ? "unknown" : \ 75 (c) == CFGA_COND_OK ? "ok" : \ 76 (c) == CFGA_COND_FAILING ? "failing" : \ 77 (c) == CFGA_COND_FAILED ? "failed" : \ 78 (c) == CFGA_COND_UNUSABLE ? "unusable" : \ 79 "???") 80 81 #define SG_CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000) 82 83 #define MAX_STATUS_LEN 8 84 #define SG_FAIL "fail" 85 #define SG_DISABLED "disabled" 86 #define SG_DEGRADED "degraded" 87 #define SG_OK "ok" 88 89 #define SG_SCHIZO_FAILED 1 90 #define SG_SCHIZO_GOOD 0 91 92 #define DEFAULT_MAX_FREQ 66 /* 66 MHz */ 93 #define PCIX_MAX_FREQ 100 /* 100 MHz */ 94 95 #define CFG_CPU "::cpu" 96 97 #define CFG_SET_FRU_NAME_NODE(str, num) \ 98 { \ 99 char tmp_str[MAX_FRU_NAME_LEN]; \ 100 sprintf(tmp_str, "/N%d", num); \ 101 strncat(str, tmp_str, sizeof (tmp_str)); \ 102 } 103 104 #define CFG_SET_FRU_NAME_CPU_BOARD(str, num) \ 105 { \ 106 char tmp_str[MAX_FRU_NAME_LEN]; \ 107 sprintf(tmp_str, ".%s%d", SG_HPU_TYPE_CPU_BOARD_ID, num); \ 108 strncat(str, tmp_str, sizeof (tmp_str)); \ 109 } 110 111 #define CFG_SET_FRU_NAME_MODULE(str, num) \ 112 { \ 113 char tmp_str[MAX_FRU_NAME_LEN]; \ 114 sprintf(tmp_str, "%s%d", CFG_CPU, num); \ 115 strncat(str, tmp_str, sizeof (tmp_str)); \ 116 } 117 118 extern int print_flag; 119 120 /* 121 * these functions will overlay the symbol table of libprtdiag 122 * at runtime (Serengeti systems only) 123 */ 124 int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag); 125 void *get_prop_val(Prop *prop); 126 Prop *find_prop(Prom_node *pnode, char *name); 127 char *get_node_name(Prom_node *pnode); 128 char *get_node_type(Prom_node *pnode); 129 void add_node(Sys_tree *, Prom_node *); 130 void display_pci(Board_node *); 131 void display_ffb(Board_node *, int); 132 void display_io_cards(struct io_card *list); 133 void display_cpu_devices(Sys_tree *tree); 134 void display_cpus(Board_node *board); 135 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 136 struct system_kstat_data *kstats); 137 void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats); 138 void get_failed_parts(void); 139 int display_failed_parts(Sys_tree *tree); 140 void display_memoryconf(Sys_tree *tree); 141 void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 142 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id); 143 144 /* Local Functions */ 145 static void serengeti_display_hw_revisions(Prom_node *root, 146 Board_node *bnode); 147 static Board_node *serengeti_find_board(Sys_tree *root, int board, int nodeid); 148 static Board_node *serengeti_insert_board(Sys_tree *root, int board, int nid); 149 static int display_schizo_revisions(Board_node *bdlist, int mode); 150 static void display_sgsbbc_revisions(Board_node *bdlist); 151 static void serengeti_display_board_info(int state); 152 static void serengeti_display_board_info_header(int state); 153 static boolean_t cpu_node_configured(char *const node); 154 static void display_io_max_bus_speed(struct io_card *p); 155 static void display_io_slot_info(struct io_card *p); 156 static void get_slot_name(struct io_card *card, char *slot_name); 157 158 /* The bus max freq is determined based on board level in use */ 159 int board_bus_max_freq = DEFAULT_MAX_FREQ; /* 66MHz default */ 160 161 /* 162 * Serengeti now uses both the devinfo tree and the OBP tree for it's 163 * prtdiag. The devinfo tree is used for getting the HW config of the 164 * system and the OBP device tree is used for listing the failed HW 165 * in the system. This is because devinfo currently does not include 166 * any PROM nodes with a status of 'fail' so we need to go to OBP to 167 * get a list of failed HW. We use the tree flag to allow the same code 168 * to walk both trees. 169 * 170 * We really need to look at having a single tree for all platforms! 171 */ 172 #define DEVINFO_TREE 1 173 #define OBP_TREE 2 174 175 static int tree = DEVINFO_TREE; 176 177 #ifdef DEBUG 178 #define D_PRINTFINDENT printfindent 179 void 180 printfindent(int indent, char *fmt, ...) 181 { 182 va_list ap; 183 int i = 0; 184 for (i = 0; i < indent; i ++) 185 printf("\t"); 186 187 va_start(ap); 188 (void) vprintf(fmt, ap); 189 va_end(ap); 190 } 191 #else 192 #define D_PRINTFINDENT 193 #endif 194 195 /* 196 * display_pci 197 * Display all the PCI IO cards on this board. 198 */ 199 void 200 display_pci(Board_node *board) 201 { 202 struct io_card *card_list = NULL; 203 struct io_card card; 204 void *value; 205 Prom_node *pci; 206 Prom_node *card_node; 207 Prom_node *pci_bridge_node; 208 Prom_node *child_pci_bridge_node; 209 char *slot_name = NULL; /* info in "slot-names" prop */ 210 char *child_name; 211 char *name, *type; 212 char *pname, *ptype; 213 char buf[MAXSTRLEN]; 214 int *int_val; 215 int pci_bus; 216 int pci_bridge = 0; 217 int pci_bridge_dev_no; 218 char *slot_name_arr[SG_MAX_SLOTS_PER_IO_BD] = {NULL}; 219 int i; 220 int portid; 221 int level = 0; 222 int version, *pversion; 223 #ifdef DEBUG 224 int slot_name_bits; 225 #endif 226 227 if (board == NULL) 228 return; 229 230 /* Initialize all the common information */ 231 card.display = TRUE; 232 card.board = board->board_num; 233 card.node_id = board->node_id; 234 235 /* 236 * Search for each schizo and xmits, then find/display all nodes under 237 * each schizo and xmits node found. 238 */ 239 for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE); 240 pci != NULL; 241 pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) { 242 243 /* set max freq for this board */ 244 board_bus_max_freq = DEFAULT_MAX_FREQ; 245 /* 246 * Find out if this is a PCI or cPCI IO Board. 247 * If "enum-impl" property exists in pci node => cPCI. 248 */ 249 value = get_prop_val(find_prop(pci, "enum-impl")); 250 if (value == NULL) { 251 (void) sprintf(card.bus_type, "PCI"); 252 } else { 253 (void) sprintf(card.bus_type, "cPCI"); 254 } 255 256 if (strstr((char *)get_prop_val( 257 find_prop(pci, "compatible")), XMITS_COMPATIBLE)) { 258 sprintf(card.notes, "%s", XMITS_COMPATIBLE); 259 /* 260 * With XMITS 3.X and PCI-X mode, the bus speed 261 * can be higher than 66MHZ. 262 */ 263 value = (int *)get_prop_val 264 (find_prop(pci, "module-revision#")); 265 if (value) { 266 pversion = (int *)value; 267 version = *pversion; 268 if (version >= 4) 269 board_bus_max_freq = PCIX_MAX_FREQ; 270 } 271 } else if (strstr((char *)get_prop_val( 272 find_prop(pci, "compatible")), SCHIZO_COMPATIBLE)) 273 sprintf(card.notes, "%s", SCHIZO_COMPATIBLE); 274 else 275 sprintf(card.notes, " "); 276 277 /* 278 * Get slot-name properties from parent node and 279 * store them in an array. 280 */ 281 value = (char *)get_prop_val(find_prop(pci, "slot-names")); 282 if (value != NULL) { 283 #ifdef DEBUG 284 /* save the 4 byte bitmask */ 285 slot_name_bits = *(int *)value; 286 #endif 287 /* array starts after first int */ 288 slot_name_arr[0] = (char *)value + sizeof (int); 289 290 D_PRINTFINDENT(0, "slot_name_arr[0] is [%s]\n", 291 slot_name_arr[0]); 292 293 for (i = 1; i < SG_MAX_SLOTS_PER_IO_BD; i++) { 294 slot_name_arr[i] = (char *)slot_name_arr[i - 1] 295 + strlen(slot_name_arr[i - 1]) +1; 296 297 D_PRINTFINDENT(0, "slot_name_arr[%d] is [%s]\n", i, 298 slot_name_arr[i]); 299 300 } 301 } 302 303 /* 304 * Search for Children of this node ie. Cards. 305 * Note: any of these cards can be a pci-bridge 306 * that itself has children. If we find a 307 * pci-bridge we need to handle it specially. 308 * 309 * There can now be the condition of a pci-bridge 310 * being the child of a pci-bridge which create a 311 * two levels of pci-bridges. This special condition 312 * needs to be handled as well. The variable level 313 * is used to track the depth of the tree. This 314 * variable is then used to find instances of this case. 315 */ 316 level = 0; 317 card_node = pci->child; 318 while (card_node != NULL) { 319 pci_bridge = 0; 320 321 /* If it doesn't have a name, skip it */ 322 name = (char *)get_prop_val( 323 find_prop(card_node, "name")); 324 if (name == NULL) { 325 card_node = card_node->sibling; 326 continue; 327 } 328 D_PRINTFINDENT(level, "NAME is %s\n", name); 329 330 type = (char *)get_prop_val( 331 find_prop(card_node, "device_type")); 332 333 /* 334 * get dev# and func# for this card from the 335 * 'reg' property. 336 */ 337 int_val = (int *)get_prop_val( 338 find_prop(card_node, "reg")); 339 if (int_val != NULL) { 340 card.dev_no = (((*int_val) & 0xF800) >> 11); 341 card.func_no = (((*int_val) & 0x700) >> 8); 342 } else { 343 card.dev_no = -1; 344 card.func_no = -1; 345 } 346 347 /* 348 * If this is a pci-bridge, then store it's dev# 349 * as it's children nodes need this to get their slot#. 350 * We set the pci_bridge flag so that we know we are 351 * looking at a pci-bridge node. This flag gets reset 352 * every time we enter this while loop. 353 */ 354 355 /* 356 * Check for a PCI-PCI Bridge for PCI and cPCI 357 * IO Boards using the name and type properties. 358 * 359 * If level is greater then 0, then check the parent 360 * node to see if it was also a pci-bridge. We do not 361 * this when level is 0 as this will see the schizo or 362 * xmits device as a pci-bridge node. This will mess 363 * up the slot number of child nodes. 364 */ 365 if ((type != NULL) && 366 (strncmp(name, "pci", 3) == 0) && 367 (strcmp(type, "pci") == 0)) { 368 if (level > 0) { 369 pname = (char *)get_prop_val( 370 find_prop(card_node->parent, 371 "name")); 372 ptype = (char *)get_prop_val( 373 find_prop(card_node->parent, 374 "device_type")); 375 376 if ((ptype != NULL) && 377 (pname != NULL) && 378 (strncmp(pname, "pci", 3) == 0) && 379 (strcmp(ptype, "pci") == 0)) { 380 child_pci_bridge_node = 381 card_node; 382 } else { 383 pci_bridge_dev_no = card.dev_no; 384 pci_bridge_node = card_node; 385 } 386 } else { 387 pci_bridge_dev_no = card.dev_no; 388 pci_bridge_node = card_node; 389 } 390 pci_bridge = TRUE; 391 392 D_PRINTFINDENT(level, 393 "pci_bridge_dev_no is [%d]\n", 394 pci_bridge_dev_no); 395 } 396 397 /* 398 * Get slot-names property from slot_names_arr. 399 * If we are the child of a pci_bridge we use the 400 * dev# of the pci_bridge as an index to get 401 * the slot number. We know that we are a child of 402 * a pci-bridge if our parent is the same as the last 403 * pci_bridge node found above. 404 */ 405 if (type) 406 D_PRINTFINDENT(level, 407 "*** name is [%s] - type is [%s]\n", 408 name, type); 409 else 410 D_PRINTFINDENT(level, 411 "*** name is [%s]\n", name); 412 413 if (card.dev_no != -1) { 414 /* 415 * We compare this cards parent node with the 416 * pci_bridge_node to see if it's a child. 417 */ 418 if (((level > 0) && 419 (card_node->parent->parent == 420 pci_bridge_node)) || 421 (card_node->parent == pci_bridge_node)) { 422 /* use dev_no of pci_bridge */ 423 D_PRINTFINDENT(level, 424 " pci_bridge_dev_no is [%d]\n", 425 pci_bridge_dev_no); 426 427 slot_name = 428 slot_name_arr[pci_bridge_dev_no -1]; 429 } else { 430 /* use cards own dev_no */ 431 D_PRINTFINDENT(level, 432 " card.dev_no is [%d]\n", 433 card.dev_no); 434 435 slot_name = 436 slot_name_arr[card.dev_no - 1]; 437 } 438 439 get_slot_name(&card, slot_name); 440 441 } else { 442 (void) sprintf(card.slot_str, "%c", '-'); 443 } 444 445 /* 446 * Get the portid of the schizo and xmits that this card 447 * lives under. 448 */ 449 portid = -1; 450 value = get_prop_val(find_prop(pci, "portid")); 451 if (value != NULL) { 452 portid = *(int *)value; 453 } 454 card.schizo_portid = portid; 455 456 #ifdef DEBUG 457 (void) sprintf(card.notes, "%s portid [%d] dev_no[%d]" 458 " slot_name[%s] name_bits[%d]", 459 card.notes, 460 portid, 461 card.dev_no, slot_name, 462 slot_name_bits); 463 #endif 464 465 /* 466 * Find out whether this is PCI bus A or B 467 * using the 'reg' property. 468 */ 469 int_val = (int *)get_prop_val 470 (find_prop(pci, "reg")); 471 472 if (int_val != NULL) { 473 int_val ++; /* skip over first integer */ 474 pci_bus = ((*int_val) & 0x7f0000); 475 if (pci_bus == 0x600000) 476 card.pci_bus = 'A'; 477 else if (pci_bus == 0x700000) 478 card.pci_bus = 'B'; 479 else 480 card.pci_bus = '-'; 481 } else { 482 card.pci_bus = '-'; 483 } 484 485 486 /* 487 * Check for failed status. 488 */ 489 if (node_status(card_node, SG_FAIL)) 490 strncpy(card.status, SG_FAIL, 491 sizeof (SG_FAIL)); 492 else if (node_status(card_node, SG_DISABLED)) 493 strncpy(card.status, SG_DISABLED, 494 sizeof (SG_DISABLED)); 495 else 496 strncpy(card.status, SG_OK, 497 sizeof (SG_OK)); 498 499 /* Get the model of this card */ 500 value = get_prop_val(find_prop(card_node, "model")); 501 if (value == NULL) 502 card.model[0] = '\0'; 503 else { 504 (void) sprintf(card.model, "%s", 505 (char *)value); 506 /* Skip sgsbbc nodes, they are not cards */ 507 if (strcmp(card.model, "SUNW,sgsbbc") == 0) { 508 card_node = card_node->sibling; 509 continue; 510 } 511 } 512 513 /* 514 * Check if further processing is necessary to display 515 * this card uniquely. 516 */ 517 distinguish_identical_io_cards(name, card_node, &card); 518 519 /* 520 * The card may have a "clock-frequency" but we 521 * are not interested in that. Instead we get the 522 * "clock-frequency" of the PCI Bus that the card 523 * resides on. PCI-A can operate at 33Mhz or 66Mhz 524 * depending on what card is plugged into the Bus. 525 * PCI-B always operates at 33Mhz. 526 * 527 */ 528 int_val = get_prop_val(find_prop(pci, 529 "clock-frequency")); 530 if (int_val != NULL) { 531 card.freq = SG_CLK_FREQ_TO_MHZ(*int_val); 532 } else { 533 card.freq = -1; 534 } 535 536 /* 537 * Figure out how we want to display the name 538 */ 539 value = get_prop_val(find_prop(card_node, 540 "compatible")); 541 if (value != NULL) { 542 /* use 'name'-'compatible' */ 543 (void) sprintf(buf, "%s-%s", name, 544 (char *)value); 545 } else { 546 /* just use 'name' */ 547 (void) sprintf(buf, "%s", name); 548 } 549 name = buf; 550 551 /* 552 * If this node has children, add the device_type 553 * of the child to the name value of this card. 554 */ 555 child_name = (char *)get_node_name(card_node->child); 556 if ((card_node->child != NULL) && 557 (child_name != NULL)) { 558 value = get_prop_val(find_prop(card_node->child, 559 "device_type")); 560 if (value != NULL) { 561 /* add device_type of child to name */ 562 (void) sprintf(card.name, "%s/%s (%s)", 563 name, child_name, 564 (char *)value); 565 } else { 566 /* just add childs name */ 567 (void) sprintf(card.name, "%s/%s", name, 568 child_name); 569 } 570 } else { 571 (void) sprintf(card.name, "%s", (char *)name); 572 } 573 574 /* 575 * If this is a pci-bridge, then add the word 576 * 'pci-bridge' to it's model. 577 */ 578 if (pci_bridge) { 579 if (strlen(card.model) == 0) 580 (void) sprintf(card.model, 581 "%s", "pci-bridge"); 582 else 583 (void) sprintf(card.model, 584 "%s/pci-bridge", card.model); 585 } 586 587 /* insert this card in the list to be displayed later */ 588 card_list = insert_io_card(card_list, &card); 589 590 /* 591 * If we are dealing with a pci-bridge, we need to move 592 * down to the children of this bridge if there are any. 593 * 594 * If we are not, we are either dealing with a regular 595 * card (in which case we move onto the sibling of this 596 * card) or we are dealing with a child of a pci-bridge 597 * (in which case we move onto the child's siblings or 598 * if there are no more siblings for this child, we 599 * move onto the parents siblings). 600 * 601 * Once we reach the last child node of a pci-bridge, 602 * we need to back up the tree to the parents sibling 603 * node. If our parent has no more siblings, we need 604 * to check our grand parent for siblings. 605 * 606 * If we have no more siblings, we simply point to 607 * to the child's sibling which moves us onto the next 608 * bus leaf. 609 * 610 * The variable level gets adjusted on some of the 611 * conditions as this is used to track level within 612 * the tree we have reached. 613 */ 614 if (pci_bridge) { 615 if (card_node->child != NULL) { 616 level++; 617 card_node = card_node->child; 618 } else 619 card_node = card_node->sibling; 620 } else { 621 if ((card_node->parent == pci_bridge_node) && 622 (card_node->sibling == NULL)) { 623 card_node = pci_bridge_node->sibling; 624 if (level > 0) 625 level--; 626 } else if ((card_node->parent == 627 child_pci_bridge_node) && 628 (card_node->parent->parent == 629 pci_bridge_node)) { 630 if ((child_pci_bridge_node->sibling) && 631 (card_node->sibling == NULL)) { 632 card_node = 633 child_pci_bridge_node-> \ 634 sibling; 635 if (level > 0) 636 level--; 637 } else if ((pci_bridge_node->sibling) && 638 (card_node->sibling == NULL)) { 639 card_node = 640 pci_bridge_node->sibling; 641 if (level > 1) 642 level = level - 2; 643 else if (level > 0) 644 level--; 645 } else 646 card_node = card_node->sibling; 647 } else 648 card_node = card_node->sibling; 649 } 650 } /* end-while */ 651 } /* end-for */ 652 653 display_io_cards(card_list); 654 free_io_cards(card_list); 655 } 656 657 /* 658 * display_ffb 659 * 660 * There are no FFB's on a Serengeti, however in the generic library, 661 * the display_ffb() function is implemented so we have to define an 662 * empty function here. 663 */ 664 /*ARGSUSED0*/ 665 void 666 display_ffb(Board_node *board, int table) 667 {} 668 669 static void 670 serengeti_display_board_info_header(int state) 671 { 672 char *fmt = "%-9s %-11s %-12s %-12s %-9s %-40s\n"; 673 674 log_printf("\n", 0); 675 log_printf("=========================", 0); 676 if (state == ACTIVE) 677 log_printf(dgettext(TEXT_DOMAIN, 678 " Active Boards for Domain "), 0); 679 else 680 log_printf(dgettext(TEXT_DOMAIN, 681 " Available Boards/Slots for Domain "), 0); 682 log_printf("===========================", 0); 683 log_printf("\n", 0); 684 log_printf("\n", 0); 685 686 log_printf(fmt, "", "Board", "Receptacle", "Occupant", "", "", 0); 687 688 log_printf(fmt, "FRU Name", "Type", "Status", "Status", 689 "Condition", "Info", 0); 690 691 log_printf(fmt, "---------", "-----------", "-----------", 692 "------------", "---------", 693 "----------------------------------------", 0); 694 } 695 696 static void 697 serengeti_display_board_info(int state) 698 { 699 int i, z, ret; 700 int nlist = 0; 701 int available_board_count = 0; 702 struct cfga_list_data *board_cfg = NULL; 703 char *err_string = NULL; 704 char tmp_id[CFGA_LOG_EXT_LEN + 1]; 705 char tmp_info[DISPLAY_INFO + 1]; 706 const char listops[] = "class=sbd"; 707 struct cfga_list_data dat; 708 cfga_flags_t flags = 0; 709 710 ret = config_list_ext(0, NULL, &board_cfg, &nlist, 711 NULL, listops, 712 &err_string, flags); 713 714 if (ret == CFGA_OK) { 715 serengeti_display_board_info_header(state); 716 for (i = 0; i < nlist; i++) { 717 dat = board_cfg[i]; 718 719 if ((state != ACTIVE) && 720 (dat.ap_o_state == CFGA_STAT_CONFIGURED)) 721 continue; 722 else if ((state == ACTIVE) && 723 (dat.ap_o_state != CFGA_STAT_CONFIGURED)) 724 continue; 725 if (state == INACTIVE) 726 available_board_count++; 727 728 memcpy(tmp_id, dat.ap_log_id, CFGA_LOG_EXT_LEN); 729 tmp_id[CFGA_LOG_EXT_LEN] = '\0'; 730 for (z = 0; z < strlen(tmp_id); z++) { 731 if (tmp_id[z] == '.') 732 tmp_id[z] = '/'; 733 } 734 log_printf("/%-8s ", tmp_id, 0); 735 log_printf("%-11s ", dat.ap_type, 0); 736 737 log_printf("%-12s ", EVNT2STR(dat.ap_r_state), 0); 738 log_printf("%-12s ", EVNT2STR(dat.ap_o_state), 0); 739 log_printf("%-8s ", COND2STR(dat.ap_cond), 0); 740 741 memcpy(tmp_info, dat.ap_info, DISPLAY_INFO); 742 tmp_info[DISPLAY_INFO - 1] = '\0'; 743 if (strlen(tmp_info) >= (DISPLAY_INFO - 1)) 744 tmp_info[DISPLAY_INFO - 2] = '+'; 745 log_printf("%-*s\n", (DISPLAY_INFO - 1), tmp_info, 0); 746 } 747 if ((state == INACTIVE) && 748 (available_board_count == 0)) { 749 log_printf(dgettext(TEXT_DOMAIN, 750 "There are currently no " 751 "Boards/Slots available " 752 "to this Domain\n"), 0); 753 } 754 } 755 if (board_cfg) 756 free(board_cfg); 757 if (err_string) 758 free(err_string); 759 } 760 761 /* 762 * add_node 763 * 764 * This function adds a board node to the board structure where that 765 * that node's physical component lives. 766 */ 767 void 768 add_node(Sys_tree *root, Prom_node *pnode) 769 { 770 int board = -1; 771 int portid = -1; 772 int nodeid = -1; 773 774 void *value = NULL; 775 Board_node *bnode = NULL; 776 Prom_node *p = NULL; 777 char *type; 778 779 /* Get the board number of this board from the portid prop */ 780 if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) { 781 if ((type = get_node_type(pnode)) && (strcmp(type, "cpu") == 0)) 782 value = 783 get_prop_val(find_prop(pnode->parent, "portid")); 784 } 785 if (value != NULL) { 786 portid = *(int *)value; 787 } 788 789 nodeid = SG_PORTID_TO_NODEID(portid); 790 board = SG_PORTID_TO_BOARD_NUM(portid); 791 792 /* find the board node with the same board number */ 793 if ((bnode = serengeti_find_board(root, board, nodeid)) == NULL) { 794 bnode = serengeti_insert_board(root, board, nodeid); 795 } 796 797 /* now attach this prom node to the board list */ 798 /* Insert this node at the end of the list */ 799 pnode->sibling = NULL; 800 if (bnode->nodes == NULL) 801 bnode->nodes = pnode; 802 else { 803 p = bnode->nodes; 804 while (p->sibling != NULL) 805 p = p->sibling; 806 p->sibling = pnode; 807 } 808 } 809 810 811 812 /* 813 * Print out all the io cards in the list. Also print the column 814 * headers if told to do so. 815 */ 816 void 817 display_io_cards(struct io_card *list) 818 { 819 char *fmt = "%-10s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-34s"; 820 821 static int banner = FALSE; /* Have we printed the column headings? */ 822 struct io_card *p; 823 824 if (list == NULL) 825 return; 826 827 if (banner == FALSE) { 828 log_printf(fmt, "", "", "", "", "", "Bus", "Max", 829 "", "", "", 0); 830 log_printf("\n", 0); 831 log_printf(fmt, "", "IO", "Port", "Bus", "", "Freq", "Bus", 832 "Dev,", "", "", 0); 833 log_printf("\n", 0); 834 log_printf(fmt, "FRU Name", "Type", " ID", "Side", "Slot", 835 "MHz", "Freq", "Func", "State", "Name", 0); 836 #ifdef DEBUG 837 log_printf("Model Notes\n", 0); 838 #else 839 log_printf("Model\n", 0); 840 #endif 841 842 log_printf(fmt, "----------", "----", "----", "----", "----", 843 "----", "----", "----", "-----", 844 "--------------------------------", 0); 845 #ifdef DEBUG 846 log_printf("---------------------- ", 0); 847 #endif 848 log_printf("----------------------\n", 0); 849 banner = TRUE; 850 } 851 852 for (p = list; p != NULL; p = p -> next) { 853 854 display_io_slot_info(p); 855 856 display_io_max_bus_speed(p); 857 858 log_printf("\n", 0); 859 } 860 } 861 862 static void 863 display_io_slot_info(struct io_card *p) 864 { 865 char fru_name[MAX_FRU_NAME_LEN] = ""; 866 867 SG_SET_FRU_NAME_NODE(fru_name, p->node_id); 868 SG_SET_FRU_NAME_IO_BOARD(fru_name, p->board); 869 SG_SET_FRU_NAME_MODULE(fru_name, p->schizo_portid % 2); 870 871 log_printf("%-8s ", fru_name, 0); 872 log_printf("%-4s ", p->bus_type, 0); 873 log_printf("%-3d ", p->schizo_portid, 0); 874 log_printf("%c ", p->pci_bus, 0); 875 log_printf("%-1s ", p->slot_str, 0); 876 log_printf("%-3d ", p->freq, 0); 877 } 878 879 #define BUS_SPEED_PRINT(speed) log_printf(" %d ", speed, 0) 880 881 static void 882 display_io_max_bus_speed(struct io_card *p) 883 { 884 int speed = board_bus_max_freq; 885 886 switch (p->pci_bus) { 887 case 'A': 888 BUS_SPEED_PRINT(speed); 889 break; 890 case 'B': 891 if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) { 892 if ((strncmp(p->slot_str, "1", 1) == 0) || 893 (strncmp(p->slot_str, "0", 1) == 0)) 894 BUS_SPEED_PRINT(33); 895 else 896 BUS_SPEED_PRINT(speed); 897 } else 898 BUS_SPEED_PRINT(33); 899 break; 900 default: 901 log_printf(" - ", 0); 902 break; 903 } 904 905 log_printf("%-1d,%-1d ", p->dev_no, p->func_no, 0); 906 log_printf("%-5s ", p->status, 0); 907 908 log_printf("%-32.32s%c ", p->name, 909 ((strlen(p->name) > 32) ? '+' : ' '), 0); 910 log_printf("%-22.22s%c", p->model, 911 ((strlen(p->model) > 22) ? '+' : ' '), 0); 912 #ifdef DEBUG 913 log_printf(" %s", p->notes, 0); 914 #endif /* DEBUG */ 915 } 916 917 void 918 display_cpu_devices(Sys_tree *tree) 919 { 920 Board_node *bnode; 921 922 /* printf formats */ 923 char *fmt1 = "%-10s %-7s %-4s %-4s %-7s %-4s\n"; 924 925 /* 926 * Display the table header for CPUs . Then display the CPU 927 * frequency, cache size, and processor revision of all cpus. 928 */ 929 log_printf("\n", 0); 930 log_printf("=========================", 0); 931 log_printf(" CPUs ", 0); 932 log_printf("=========================", 0); 933 log_printf("======================", 0); 934 log_printf("\n", 0); 935 log_printf("\n", 0); 936 937 log_printf(fmt1, "", "CPU ", "Run", " E$", "CPU", "CPU", 0); 938 939 log_printf(fmt1, "FRU Name", "ID ", "MHz", " MB", 940 "Impl.", "Mask", 0); 941 942 log_printf(fmt1, "----------", "-------", "----", "----", 943 "-------", "----", 0); 944 945 /* Now display all of the cpus on each board */ 946 bnode = tree->bd_list; 947 while (bnode != NULL) { 948 display_cpus(bnode); 949 bnode = bnode->next; 950 } 951 952 log_printf("\n", 0); 953 } 954 955 static boolean_t 956 cpu_node_configured(char *const node) 957 { 958 int ret, i; 959 int nlist = 0; 960 boolean_t rv; 961 char *err_string = NULL; 962 char *const *ap_args = NULL; 963 struct cfga_list_data *statlist = NULL; 964 struct cfga_list_data dat; 965 cfga_flags_t flags = CFGA_FLAG_LIST_ALL; 966 967 if (node == NULL) 968 return (FALSE); 969 970 ap_args = &node; 971 ret = config_list_ext(1, &node, &statlist, &nlist, 972 NULL, NULL, &err_string, flags); 973 974 if (ret == CFGA_OK) { 975 dat = statlist[0]; 976 977 if (dat.ap_o_state == CFGA_STAT_CONFIGURED) 978 rv = TRUE; 979 else 980 rv = FALSE; 981 } else { 982 rv = FALSE; 983 } 984 if (statlist) 985 free(statlist); 986 if (err_string) 987 free(err_string); 988 return (rv); 989 } 990 991 /* 992 * Display the CPUs present on this board. 993 */ 994 void 995 display_cpus(Board_node *board) 996 { 997 Prom_node *cpu; 998 uint_t freq; /* CPU clock frequency */ 999 int ecache_size; /* External cache size */ 1000 int board_num = board->board_num; 1001 int *mid; 1002 int *impl; 1003 int *mask; 1004 int decoded_mask; 1005 int *coreid; 1006 int mid_prev = -1; 1007 int ecache_size_prev = 0; 1008 char fru_prev[MAX_FRU_NAME_LEN] = ""; 1009 1010 /* 1011 * display the CPUs' operating frequency, cache size, impl. field 1012 * and mask revision. 1013 */ 1014 for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL; 1015 cpu = dev_next_type(cpu, "cpu")) { 1016 char fru_name[MAX_FRU_NAME_LEN] = ""; 1017 char cfg_fru_name[MAX_FRU_NAME_LEN] = ""; 1018 1019 mid = (int *)get_prop_val(find_prop(cpu, "portid")); 1020 if (mid == NULL) 1021 mid = (int *)get_prop_val(find_prop(cpu, "cpuid")); 1022 freq = SG_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu)); 1023 ecache_size = get_ecache_size(cpu); 1024 impl = (int *)get_prop_val(find_prop(cpu, "implementation#")); 1025 mask = (int *)get_prop_val(find_prop(cpu, "mask#")); 1026 1027 /* Do not display a failed CPU node */ 1028 if ((impl == NULL) || (freq == 0) || (node_failed(cpu))) 1029 continue; 1030 1031 /* FRU Name */ 1032 SG_SET_FRU_NAME_NODE(fru_name, board->node_id); 1033 1034 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board_num); 1035 SG_SET_FRU_NAME_MODULE(fru_name, *mid % 4); 1036 1037 if (CPU_IMPL_IS_CMP(*impl)) { 1038 coreid = (int *)get_prop_val(find_prop(cpu, 1039 "reg")); 1040 if (coreid == NULL) { 1041 continue; 1042 } 1043 1044 /* 1045 * The assumption is made that 2 cores will always be 1046 * listed together in the device tree. If either core 1047 * is "bad" then the FRU will not be listed. 1048 * 1049 * As display_cpus on Serengeti does actually process 1050 * all cpu's per board a copy of the fru_name needs to 1051 * be made as the following core may not be its 1052 * sibling. If this is the case it is assumed that a 1053 * sibling core has failed, so the fru should not be 1054 * displayed. 1055 * 1056 * For the first instance of a core, fru_prev is 1057 * expected to be empty. The current values are then 1058 * stored and the next board->nodes is processed. If 1059 * this is a sibling core, the ecache size it tallied 1060 * and the previous value reset and processing 1061 * continues. 1062 * 1063 * If the following core is not a sibling, the new 1064 * values are stored and the next board->nodes is 1065 * processed. 1066 */ 1067 if (strncmp(fru_prev, "", sizeof (fru_prev)) == 0) { 1068 strncpy(fru_prev, fru_name, sizeof (fru_name)); 1069 mid_prev = *mid; 1070 ecache_size_prev = ecache_size; 1071 continue; 1072 } else { 1073 if (strncmp(fru_name, fru_prev, 1074 sizeof (fru_prev)) == 0) { 1075 /* 1076 * Jaguar has a split E$, so the size 1077 * for both cores must be added together 1078 * to get the total size for the entire 1079 * chip. 1080 * 1081 * Panther E$ (L3) is logically shared, 1082 * so the total size is equal to the 1083 * core size. 1084 */ 1085 if (IS_JAGUAR(*impl)) { 1086 ecache_size += ecache_size_prev; 1087 } 1088 1089 ecache_size_prev = 0; 1090 strncpy(fru_prev, "", 1091 sizeof (fru_prev)); 1092 } else { 1093 mid_prev = *mid; 1094 ecache_size_prev = ecache_size; 1095 strncpy(fru_prev, fru_name, 1096 sizeof (fru_name)); 1097 continue; 1098 } 1099 } 1100 } 1101 1102 /* 1103 * If cpu is not configured, do not display it 1104 */ 1105 CFG_SET_FRU_NAME_NODE(cfg_fru_name, board->node_id); 1106 CFG_SET_FRU_NAME_CPU_BOARD(cfg_fru_name, board_num); 1107 CFG_SET_FRU_NAME_MODULE(cfg_fru_name, *mid % 4); 1108 1109 if (!(cpu_node_configured(cfg_fru_name))) { 1110 continue; 1111 } 1112 1113 1114 log_printf("%-10s ", fru_name, 0); 1115 1116 /* CPU MID */ 1117 if (CPU_IMPL_IS_CMP(*impl)) { 1118 log_printf("%3d,%3d ", mid_prev, *mid, 0); 1119 mid_prev = -1; 1120 } else 1121 log_printf("%3d ", *mid, 0); 1122 1123 /* Running frequency */ 1124 log_printf(" %4u ", freq, 0); 1125 1126 /* Ecache size */ 1127 if (ecache_size == 0) 1128 log_printf("%3s ", "N/A", 0); 1129 else 1130 log_printf("%4.1f ", 1131 (float)ecache_size / (float)(1<<20), 1132 0); 1133 1134 /* Implementation */ 1135 if (impl == NULL) { 1136 log_printf("%6s ", " N/A", 0); 1137 } else { 1138 switch (*impl) { 1139 case CHEETAH_IMPL: 1140 log_printf("%-7s ", "US-III", 0); 1141 break; 1142 case CHEETAH_PLUS_IMPL: 1143 log_printf("%-7s ", "US-III+", 0); 1144 break; 1145 case JAGUAR_IMPL: 1146 log_printf("%-7s ", "US-IV", 0); 1147 break; 1148 case PANTHER_IMPL: 1149 log_printf("%-7s ", "US-IV+", 0); 1150 break; 1151 default: 1152 log_printf("%-7x ", *impl, 0); 1153 break; 1154 } 1155 } 1156 1157 /* CPU Mask */ 1158 if (mask == NULL) { 1159 log_printf(" %3s ", "N/A", 0); 1160 } else { 1161 if (IS_CHEETAH(*impl)) 1162 decoded_mask = REMAP_CHEETAH_MASK(*mask); 1163 else 1164 decoded_mask = *mask; 1165 1166 log_printf(" %d.%d ", 1167 (decoded_mask >> 4) & 0xf, 1168 decoded_mask & 0xf, 0); 1169 } 1170 1171 log_printf("\n", 0); 1172 } 1173 } 1174 1175 1176 /*ARGSUSED3*/ 1177 void 1178 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 1179 struct system_kstat_data *kstats) 1180 { 1181 log_printf("\n", 0); 1182 log_printf("=========================", 0); 1183 log_printf(dgettext(TEXT_DOMAIN, " Hardware Failures "), 0); 1184 log_printf("==================================", 0); 1185 log_printf("\n", 0); 1186 1187 /* 1188 * Get a list of failed parts (ie. devices with a status of 1189 * 'fail') from the OBP device tree and display them. 1190 */ 1191 get_failed_parts(); 1192 1193 /* return unless -v option specified */ 1194 if (!flag) { 1195 log_printf("\n", 0); 1196 return; 1197 } 1198 1199 /* 1200 * display time of latest powerfail. Not all systems 1201 * have this capability. For those that do not, this 1202 * is just a no-op. 1203 */ 1204 disp_powerfail(root); 1205 1206 /* Print the PROM revisions here */ 1207 serengeti_display_hw_revisions(root, tree->bd_list); 1208 } 1209 1210 /* 1211 * local functions - functions that are only needed inside this library 1212 */ 1213 1214 static void 1215 serengeti_display_hw_revisions(Prom_node *root, Board_node *bdlist) 1216 { 1217 Prom_node *pnode; 1218 char *value; 1219 1220 /* Print the header */ 1221 log_printf("\n", 0); 1222 log_printf("=========================", 0); 1223 log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0); 1224 log_printf("=======================================", 0); 1225 log_printf("\n", 0); 1226 log_printf("\n", 0); 1227 1228 /* Display Prom revision header */ 1229 log_printf("System PROM revisions:\n", 0); 1230 log_printf("----------------------\n", 0); 1231 1232 /* 1233 * Display OBP version info 1234 */ 1235 pnode = dev_find_node(root, "openprom"); 1236 if (pnode != NULL) { 1237 value = (char *)get_prop_val(find_prop(pnode, "version")); 1238 log_printf("%s\n\n", value, 0); 1239 } else { 1240 log_printf("OBP ???\n\n", value, 0); 1241 } 1242 1243 /* 1244 * Display ASIC revisions 1245 */ 1246 log_printf("IO ASIC revisions:\n", 0); 1247 log_printf("------------------\n", 0); 1248 1249 log_printf(" Port\n", 0); 1250 log_printf("FRU Name Model ID Status", 0); 1251 #ifdef DEBUG 1252 log_printf(" Version Notes\n", 0); 1253 #else 1254 log_printf(" Version\n", 0); 1255 #endif 1256 /* ---------FRU Name--Model-----------Port-Status */ 1257 log_printf("----------- --------------- ---- ---------- " 1258 #ifdef DEBUG 1259 "------- " 1260 #endif 1261 "-------\n", 0); 1262 /* 1263 * Display SCHIZO version info 1264 */ 1265 display_schizo_revisions(bdlist, SG_SCHIZO_GOOD); 1266 1267 /* 1268 * Display sgsbbc version info 1269 */ 1270 display_sgsbbc_revisions(bdlist); 1271 } 1272 1273 /* 1274 * This function displays Schizo and Xmits revision of boards 1275 */ 1276 static int 1277 display_schizo_revisions(Board_node *bdlist, int mode) 1278 { 1279 Prom_node *pnode; 1280 int *int_val; 1281 int portid; 1282 int prev_portid = -1; 1283 char *model; 1284 char *status_a, *status_b; 1285 char status[MAX_STATUS_LEN]; 1286 int version; 1287 int node_id; 1288 #ifdef DEBUG 1289 uint32_t a_notes, b_notes; 1290 #endif 1291 int pci_bus; 1292 /* 1293 * rv is used when mode is set to SG_SCHIZO_FAILED. 1294 * We need to signal if a failure is found so that 1295 * the correct headers/footers can be printed. 1296 * 1297 * rv = 1 implies a failed/disavled schizo device 1298 * rv = 0 implies all other cases 1299 */ 1300 int rv = 0; 1301 Board_node *bnode; 1302 void *value; 1303 1304 bnode = bdlist; 1305 while (bnode != NULL) { 1306 /* 1307 * search this board node for all Schizos 1308 */ 1309 for (pnode = dev_find_node_by_compatible(bnode->nodes, 1310 SCHIZO_COMPATIBLE); pnode != NULL; 1311 pnode = dev_next_node_by_compatible(pnode, 1312 SCHIZO_COMPATIBLE)) { 1313 1314 char fru_name[MAX_FRU_NAME_LEN] = ""; 1315 1316 /* 1317 * get the reg property to determine 1318 * whether we are looking at side A or B 1319 */ 1320 int_val = (int *)get_prop_val 1321 (find_prop(pnode, "reg")); 1322 if (int_val != NULL) { 1323 int_val ++; /* second integer in array */ 1324 pci_bus = ((*int_val) & 0x7f0000); 1325 } 1326 1327 /* get portid */ 1328 int_val = (int *)get_prop_val 1329 (find_prop(pnode, "portid")); 1330 if (int_val == NULL) 1331 continue; 1332 1333 portid = *int_val; 1334 1335 /* 1336 * If this is a new portid and it is PCI bus B, 1337 * we skip onto the PCI bus A. (PCI-A and PCI-B share 1338 * the same portid) 1339 */ 1340 if ((portid != prev_portid) && (pci_bus == 0x700000)) { 1341 prev_portid = portid; 1342 /* status */ 1343 status_b = (char *)get_prop_val 1344 (find_prop(pnode, "status")); 1345 #ifdef DEBUG 1346 b_notes = pci_bus; 1347 #endif 1348 continue; /* skip to the next schizo */ 1349 } 1350 1351 /* 1352 * This must be side A of the same Schizo. 1353 * Gather all its props and display them. 1354 */ 1355 #ifdef DEBUG 1356 a_notes = pci_bus; 1357 #endif 1358 1359 prev_portid = portid; 1360 1361 /* get the node-id */ 1362 node_id = SG_PORTID_TO_NODEID(portid); 1363 1364 /* model */ 1365 model = (char *)get_prop_val 1366 (find_prop(pnode, "model")); 1367 1368 /* version */ 1369 value = (int *)get_prop_val 1370 (find_prop(pnode, "module-revision#")); 1371 1372 if (value) 1373 int_val = (int *)value; 1374 else 1375 int_val = (int *)get_prop_val 1376 (find_prop(pnode, "version#")); 1377 if (int_val != NULL) 1378 version = *int_val; 1379 else 1380 version = -1; 1381 1382 /* status */ 1383 status_a = (char *)get_prop_val(find_prop 1384 (pnode, "status")); 1385 1386 /* 1387 * Display the data 1388 */ 1389 /* FRU Name */ 1390 SG_SET_FRU_NAME_NODE(fru_name, node_id); 1391 SG_SET_FRU_NAME_IO_BOARD(fru_name, 1392 SG_IO_BD_PORTID_TO_BD_NUM(portid)); 1393 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1394 1395 if (mode == SG_SCHIZO_FAILED) { 1396 if ((status_a != (char *)NULL) && 1397 ((status_b != (char *)NULL))) { 1398 if ((strcmp 1399 (status_a, SG_DISABLED) == 0) && 1400 (strcmp(status_b, 1401 SG_DISABLED) == 0)) { 1402 log_printf("\tFRU Type : %s\n ", 1403 model, 0); 1404 log_printf("\tLocation : %s\n", 1405 fru_name, 0); 1406 log_printf 1407 ("\tPROM status: %s\n\n", 1408 SG_DISABLED, 0); 1409 rv = 1; 1410 } 1411 } 1412 continue; 1413 } 1414 /* 1415 * This section of code is executed when displaying 1416 * non-failed schizo devices. If the mode is set to 1417 * SG_SCHIZO_FAILED, then this section of code will 1418 * not be executed 1419 */ 1420 if ((status_a == (char *)NULL) && 1421 ((status_b == (char *)NULL))) 1422 sprintf(status, " %s ", SG_OK); 1423 else if ((status_a == (char *)NULL) && 1424 ((strcmp(status_b, SG_DISABLED) == 0))) 1425 sprintf(status, " %s", SG_DEGRADED); 1426 else if ((status_b == (char *)NULL) && 1427 ((strcmp(status_a, SG_DISABLED) == 0))) 1428 sprintf(status, " %s", SG_DEGRADED); 1429 else 1430 continue; 1431 1432 log_printf("%-12s", fru_name, 0); 1433 1434 /* model */ 1435 1436 if (model != NULL) 1437 log_printf("%-15s ", model, 0); 1438 else 1439 log_printf("%-15s ", "unknown", 0); 1440 /* portid */ 1441 log_printf("%-3d ", portid, 0); 1442 1443 /* status */ 1444 log_printf("%s", status, 0); 1445 1446 /* version */ 1447 log_printf(" %-4d ", version, 0); 1448 #ifdef DEBUG 1449 log_printf("0x%x 0x%x", a_notes, b_notes, 0); 1450 log_printf(" %d", portid, 0); 1451 #endif 1452 log_printf("\n", 0); 1453 } 1454 bnode = bnode->next; 1455 } 1456 return (rv); 1457 } 1458 1459 static void 1460 display_sgsbbc_revisions(Board_node *bdlist) 1461 { 1462 1463 Prom_node *pnode; 1464 int *int_val; 1465 int portid; 1466 char *model; 1467 char *status; 1468 int revision; 1469 int node_id; 1470 Board_node *bnode; 1471 1472 #ifdef DEBUG 1473 char *slot_name; 1474 char notes[30]; 1475 char *value; 1476 #endif 1477 1478 bnode = bdlist; 1479 while (bnode != NULL) { 1480 /* 1481 * search this board node for all sgsbbc's 1482 */ 1483 for (pnode = dev_find_node_by_type(bnode->nodes, "model", 1484 "SUNW,sgsbbc"); pnode != NULL; 1485 pnode = dev_next_node_by_type(pnode, "model", 1486 "SUNW,sgsbbc")) { 1487 1488 char fru_name[MAX_FRU_NAME_LEN] = ""; 1489 1490 /* 1491 * We need to go to this node's parent to 1492 * get a portid to tell us what board it is on 1493 */ 1494 int_val = (int *)get_prop_val 1495 (find_prop(pnode->parent, "portid")); 1496 if (int_val == NULL) 1497 continue; 1498 1499 portid = *int_val; 1500 /* get the node-id */ 1501 node_id = SG_PORTID_TO_NODEID(portid); 1502 1503 /* model */ 1504 model = (char *)get_prop_val 1505 (find_prop(pnode, "model")); 1506 1507 /* status */ 1508 status = (char *)get_prop_val(find_prop 1509 (pnode, "status")); 1510 1511 /* revision */ 1512 int_val = (int *)get_prop_val 1513 (find_prop(pnode, "revision-id")); 1514 if (int_val != NULL) 1515 revision = *int_val; 1516 else 1517 revision = -1; 1518 1519 #ifdef DEBUG 1520 value = (char *)get_prop_val( 1521 find_prop(pnode->parent, "slot-names")); 1522 if (value != NULL) { 1523 /* Skip the 4 byte bitmask */ 1524 slot_name = (char *)value + sizeof (int); 1525 } else { 1526 strcpy(slot_name, "not_found"); 1527 } 1528 (void) sprintf(notes, "[%s] portid [%d]", slot_name, 1529 portid); 1530 #endif 1531 /* 1532 * Display the data 1533 */ 1534 /* FRU Name */ 1535 SG_SET_FRU_NAME_NODE(fru_name, node_id); 1536 SG_SET_FRU_NAME_IO_BOARD(fru_name, 1537 SG_IO_BD_PORTID_TO_BD_NUM(portid)); 1538 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1539 log_printf("%-12s", fru_name, 0); 1540 1541 /* model */ 1542 if (model != NULL) 1543 log_printf("%-15s ", model, 0); 1544 else 1545 log_printf("%-15s ", "unknown", 0); 1546 /* portid */ 1547 log_printf("%-3d ", portid, 0); 1548 /* status */ 1549 if (status == (char *)NULL) 1550 log_printf(" ok ", 0); 1551 else 1552 log_printf(" fail ", 0); 1553 /* revision */ 1554 log_printf(" %-4d ", revision, 0); 1555 #ifdef DEBUG 1556 log_printf("%s", notes, 0); 1557 #endif 1558 log_printf("\n", 0); 1559 } 1560 bnode = bnode->next; 1561 } 1562 } 1563 1564 /*ARGSUSED0*/ 1565 void 1566 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats) 1567 { 1568 serengeti_display_board_info(ACTIVE); 1569 serengeti_display_board_info(INACTIVE); 1570 } 1571 1572 /* 1573 * display_failed_parts 1574 * 1575 * Display the failed parts in the system. This function looks for 1576 * the status property in all PROM nodes contained in the Sys_tree 1577 * passed in. 1578 */ 1579 int 1580 display_failed_parts(Sys_tree *tree) 1581 { 1582 int system_failed = 0; 1583 int bank_failed = 0; 1584 int schizo_failed = FALSE; 1585 int portid, nodeid, board; 1586 Board_node *bnode = tree->bd_list; 1587 Prom_node *pnode; 1588 int *coreid, *impl; 1589 print_flag = TRUE; 1590 1591 /* 1592 * go through all of the OBP nodes looking for 1593 * failed units. 1594 */ 1595 while (bnode != NULL) { 1596 1597 pnode = find_failed_node(bnode->nodes); 1598 if ((pnode != NULL) && !system_failed) { 1599 system_failed = TRUE; 1600 log_printf("\n", 0); 1601 log_printf(dgettext(TEXT_DOMAIN, 1602 "Failed Field Replaceable Units (FRU) in " 1603 "System:\n"), 0); 1604 log_printf("==========================" 1605 "====================\n", 0); 1606 } 1607 1608 while (pnode != NULL) { 1609 void *status; 1610 char *name, *type, *model; 1611 1612 char fru_name[MAX_FRU_NAME_LEN] = ""; 1613 1614 status = get_prop_val(find_prop(pnode, "status")); 1615 name = get_node_name(pnode); 1616 1617 /* sanity check of data retreived from PROM */ 1618 if ((status == NULL) || (name == NULL)) { 1619 pnode = next_failed_node(pnode); 1620 continue; 1621 } 1622 1623 type = get_node_type(pnode); 1624 portid = get_id(pnode); 1625 model = (char *)get_prop_val 1626 (find_prop(pnode, "model")); 1627 1628 /* 1629 * Determine whether FRU is CPU module, Mem Controller, 1630 * PCI card, schizo,xmits or sgsbbc. 1631 */ 1632 if ((model != NULL) && strstr(model, "sgsbbc")) { 1633 /* 1634 * sgsbbc / bootbus-controller 1635 */ 1636 portid = get_id(pnode->parent); 1637 nodeid = SG_PORTID_TO_NODEID(portid); 1638 board = SG_PORTID_TO_BOARD_NUM(portid); 1639 1640 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1641 SG_SET_FRU_NAME_IO_BOARD(fru_name, board); 1642 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1643 1644 log_printf("\tFailed Device : %s (%s)\n", model, 1645 name, 0); 1646 log_printf("\tLocation : %s\n", fru_name, 0); 1647 1648 } else if (strstr(name, "pci") && (portid == -1)) { 1649 /* 1650 * PCI Bridge if name = pci and it doesn't 1651 * have a portid. 1652 */ 1653 portid = get_id(pnode->parent); 1654 nodeid = SG_PORTID_TO_NODEID(portid); 1655 board = SG_PORTID_TO_BOARD_NUM(portid); 1656 1657 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1658 SG_SET_FRU_NAME_IO_BOARD(fru_name, board); 1659 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1660 1661 log_printf("\tFRU type : ", 0); 1662 log_printf("PCI Bridge Device\n", 0); 1663 log_printf("\tLocation : %s\n", fru_name, 0); 1664 1665 } else if ((type != NULL) && 1666 (strstr(type, "cpu") || 1667 strstr(type, "memory-controller"))) { 1668 /* 1669 * CPU or memory controller 1670 */ 1671 portid = get_id(pnode); 1672 /* 1673 * For cpu nodes that belong to a CMP, the 1674 * portid is stored in the parent "cmp" node. 1675 */ 1676 if (portid == -1) 1677 portid = get_id(pnode->parent); 1678 nodeid = SG_PORTID_TO_NODEID(portid); 1679 board = SG_PORTID_TO_BOARD_NUM(portid); 1680 1681 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1682 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board); 1683 SG_SET_FRU_NAME_MODULE(fru_name, portid % 4); 1684 1685 log_printf("\tFRU type : ", 0); 1686 1687 if (strstr(type, "memory-controller")) 1688 log_printf("Memory Controller on ", 0); 1689 1690 log_printf("UltraSPARC module\n", 0); 1691 1692 log_printf("\tLocation : %s\n", fru_name, 0); 1693 1694 } else { 1695 /* 1696 * It should only be a PCI card if we get to 1697 * here but lets check to be sure. 1698 */ 1699 char *parents_model, *grandparents_model; 1700 Prom_node *parent_pnode; 1701 int pci_card_found = 0; 1702 1703 if (pnode->parent != NULL) 1704 parent_pnode = pnode->parent; 1705 1706 /* 1707 * Is our parent a schizo or xmits 1708 */ 1709 parents_model = (char *)get_prop_val 1710 (find_prop(pnode->parent, "model")); 1711 if ((parents_model != NULL) && 1712 (strstr(parents_model, "SUNW,schizo") || 1713 strstr(parents_model, "SUNW,xmits"))) { 1714 portid = get_id(pnode->parent); 1715 pci_card_found = TRUE; 1716 } 1717 1718 /* 1719 * Is our grandparent a schizo xmits 1720 */ 1721 grandparents_model = (char *)get_prop_val 1722 (find_prop(parent_pnode->parent, "model")); 1723 if ((grandparents_model != NULL) && 1724 (strstr(grandparents_model, 1725 "SUNW,schizo") || 1726 strstr(grandparents_model, 1727 "SUNW,xmits"))) { 1728 portid = get_id(parent_pnode->parent); 1729 pci_card_found = TRUE; 1730 } 1731 1732 if (pci_card_found) { 1733 nodeid = SG_PORTID_TO_NODEID(portid); 1734 board = SG_PORTID_TO_BOARD_NUM(portid); 1735 1736 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1737 SG_SET_FRU_NAME_IO_BOARD(fru_name, 1738 board); 1739 SG_SET_FRU_NAME_MODULE(fru_name, 1740 portid % 2); 1741 1742 log_printf("\tFRU type :", 0); 1743 log_printf(" PCI Card\n", 0); 1744 log_printf("\tLocation : %s\n", 1745 fru_name, 0); 1746 } 1747 } 1748 log_printf("\tPROM status: %s\n\n", status, 0); 1749 1750 pnode = next_failed_node(pnode); 1751 } 1752 bnode = bnode->next; 1753 1754 } 1755 1756 bank_failed = display_us3_failed_banks(system_failed); 1757 schizo_failed = display_schizo_revisions(tree->bd_list, 1758 SG_SCHIZO_FAILED); 1759 if (system_failed || bank_failed || schizo_failed) 1760 return (1); 1761 else 1762 return (0); 1763 } 1764 1765 1766 /* 1767 * This routine displays the memory configuration for all boards in the 1768 * system. 1769 */ 1770 void 1771 display_memoryconf(Sys_tree *tree) 1772 { 1773 Board_node *bnode = tree->bd_list; 1774 1775 log_printf("========================= Memory Configuration" 1776 " ===============================\n", 0); 1777 log_printf("\n Logical Logical Logical ", 0); 1778 log_printf("\n Port Bank Bank Bank " 1779 "DIMM Interleave Interleave", 0); 1780 log_printf("\nFRU Name ID Num Size Status " 1781 "Size Factor Segment", 0); 1782 log_printf("\n------------- ---- ---- ------ ----------- " 1783 "------ ---------- ----------", 0); 1784 1785 while (bnode != NULL) { 1786 if (get_us3_mem_regs(bnode)) { 1787 log_printf(dgettext(TEXT_DOMAIN, 1788 "\nFailed to get memory information.\n"), 0); 1789 return; 1790 } 1791 bnode = bnode->next; 1792 } 1793 1794 /* Display what we have found */ 1795 display_us3_banks(); 1796 } 1797 1798 /* 1799 * This function provides Serengeti's formatting of the memory config 1800 * information that get_us3_mem_regs() and display_us3_banks() code has 1801 * gathered. It overrides the generic print_us3_memory_line() code 1802 * which prints an error message. 1803 */ 1804 void 1805 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 1806 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id) 1807 { 1808 int nodeid, board, mcid; 1809 char fru_name[MAX_FRU_NAME_LEN] = ""; 1810 1811 mcid = SG_PORTID_TO_SAFARI_ID(portid); 1812 nodeid = SG_PORTID_TO_NODEID(portid); 1813 board = SG_PORTID_TO_BOARD_NUM(portid); 1814 1815 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1816 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board); 1817 SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4); 1818 SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2); 1819 1820 log_printf("\n%-13s %2d %2d %4lldMB %11-s %4lldMB " 1821 " %2d-way %d", 1822 fru_name, mcid, 1823 (bank_id % 4), bank_size, bank_status, dimm_size, 1824 intlv, seg_id, 0); 1825 } 1826 1827 void 1828 print_us3_failed_memory_line(int portid, int bank_id, char *bank_status) 1829 { 1830 int nodeid, board, mcid; 1831 char fru_name[MAX_FRU_NAME_LEN] = ""; 1832 1833 mcid = SG_PORTID_TO_SAFARI_ID(portid); 1834 nodeid = SG_PORTID_TO_NODEID(portid); 1835 board = SG_PORTID_TO_BOARD_NUM(portid); 1836 1837 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1838 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board); 1839 SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4); 1840 SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2); 1841 1842 log_printf("\tFRU type : ", 0); 1843 log_printf("Physical Memory Bank\n", 0); 1844 log_printf("\tLocation : %s (Logical Bank %2d)\n", 1845 fru_name, (bank_id %4), 0); 1846 log_printf("\tPROM status: %s\n\n", bank_status, 0); 1847 } 1848 1849 1850 /* 1851 * Find the requested board struct in the system device tree. 1852 * 1853 * This function overrides the functionality of the generic find_board() 1854 * function in libprtdiag, but since we need to pass another parameter, 1855 * we cannot simply overlay the symbol table. 1856 */ 1857 static Board_node * 1858 serengeti_find_board(Sys_tree *root, int board, int nodeid) 1859 { 1860 Board_node *bnode = root->bd_list; 1861 1862 while ((bnode != NULL) && 1863 ((board != bnode->board_num) || (nodeid != bnode->node_id))) { 1864 bnode = bnode->next; 1865 } 1866 return (bnode); 1867 } 1868 1869 1870 /* 1871 * Add a board to the system list in order (sorted by NodeID then board#). 1872 * Initialize all pointer fields to NULL. 1873 */ 1874 static Board_node * 1875 serengeti_insert_board(Sys_tree *root, int board, int nodeid) 1876 { 1877 Board_node *bnode; 1878 Board_node *temp = root->bd_list; 1879 1880 if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) { 1881 perror("malloc"); 1882 exit(1); 1883 } 1884 1885 bnode->nodes = NULL; 1886 bnode->next = NULL; 1887 bnode->board_num = board; 1888 bnode->node_id = nodeid; 1889 bnode->board_type = UNKNOWN_BOARD; 1890 1891 if (temp == NULL) 1892 root->bd_list = bnode; 1893 1894 else if ((temp->board_num > board) && (temp->node_id >= nodeid)) { 1895 bnode->next = temp; 1896 root->bd_list = bnode; 1897 1898 } else { 1899 while ((temp->next != NULL) && 1900 ((board > temp->next->board_num) || 1901 (nodeid > temp->node_id))) 1902 temp = temp->next; 1903 1904 bnode->next = temp->next; 1905 temp->next = bnode; 1906 } 1907 root->board_cnt++; 1908 1909 return (bnode); 1910 } 1911 1912 /* 1913 * We call do_devinfo() in order to use the libdevinfo device tree 1914 * instead of OBP's device tree. 1915 */ 1916 int 1917 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 1918 { 1919 1920 return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); 1921 1922 } 1923 1924 /* 1925 * return the property value for the Prop passed in depending on 1926 * which tree (OBP/DEVINFO) is being used. 1927 */ 1928 void * 1929 get_prop_val(Prop *prop) 1930 { 1931 if (prop == NULL) 1932 return (NULL); 1933 1934 /* Check which tree is being used. */ 1935 if (tree == DEVINFO_TREE) 1936 return ((void *)(prop->value.val_ptr)); 1937 else { 1938 if (prop->value.opp.holds_array) 1939 return ((void *)(prop->value.opp.oprom_array)); 1940 else 1941 return ((void *)(&prop->value.opp.oprom_node[0])); 1942 } 1943 } 1944 1945 /* 1946 * Search a Prom node and retrieve the property with the correct 1947 * name depending on which tree (OBP/DEVINFO) is being used. 1948 */ 1949 Prop * 1950 find_prop(Prom_node *pnode, char *name) 1951 { 1952 Prop *prop; 1953 1954 if (pnode == NULL) 1955 return (NULL); 1956 1957 if (pnode->props == NULL) 1958 return (NULL); 1959 1960 prop = pnode->props; 1961 1962 /* Check which tree is being used. */ 1963 if (tree == DEVINFO_TREE) { 1964 while ((prop != NULL) && 1965 (strcmp((char *)(prop->name.val_ptr), name))) 1966 prop = prop->next; 1967 } else { 1968 while ((prop != NULL) && (strcmp((char *) 1969 (prop->name.opp.oprom_array), name))) 1970 prop = prop->next; 1971 } 1972 return (prop); 1973 } 1974 1975 /* 1976 * This function searches through the properties of the node passed in 1977 * and returns a pointer to the value of the name property 1978 * depending on which tree (OBP/DEVINFO) is being used. 1979 */ 1980 char * 1981 get_node_name(Prom_node *pnode) 1982 { 1983 Prop *prop; 1984 1985 if (pnode == NULL) 1986 return (NULL); 1987 1988 prop = pnode->props; 1989 while (prop != NULL) { 1990 /* Check which tree is being used. */ 1991 if (tree == DEVINFO_TREE) { 1992 if (strcmp("name", (char *)prop->name.val_ptr) == 0) 1993 return ((char *)prop->value.val_ptr); 1994 } else { 1995 if (strcmp("name", prop->name.opp.oprom_array) == 0) 1996 return (prop->value.opp.oprom_array); 1997 } 1998 prop = prop->next; 1999 } 2000 return (NULL); 2001 } 2002 2003 /* 2004 * This function searches through the properties of the node passed in 2005 * and returns a pointer to the value of the device_type property 2006 * depending on which tree (OBP/DEVINFO) is being used. 2007 */ 2008 char * 2009 get_node_type(Prom_node *pnode) 2010 { 2011 Prop *prop; 2012 2013 if (pnode == NULL) 2014 return (NULL); 2015 2016 prop = pnode->props; 2017 while (prop != NULL) { 2018 /* Check which tree is being used. */ 2019 if (tree == DEVINFO_TREE) { 2020 if (strcmp("device_type", (char *)prop->name.val_ptr) 2021 == 0) 2022 return ((char *)prop->value.val_ptr); 2023 } else { 2024 if (strcmp("device_type", prop->name.opp.oprom_array) 2025 == 0) 2026 return (prop->value.opp.oprom_array); 2027 } 2028 prop = prop->next; 2029 } 2030 return (NULL); 2031 } 2032 2033 /* 2034 * Take a snapshot of the OBP device tree and walk this snapshot 2035 * to find all failed HW (ie. devices with a status property of 2036 * 'fail'). Call display_failed_parts() to display the failed HW. 2037 */ 2038 void 2039 get_failed_parts(void) 2040 { 2041 int system_failed = 0; 2042 Sys_tree obp_sys_tree; /* system information */ 2043 2044 /* set the the system tree fields */ 2045 obp_sys_tree.sys_mem = NULL; 2046 obp_sys_tree.boards = NULL; 2047 obp_sys_tree.bd_list = NULL; 2048 obp_sys_tree.board_cnt = 0; 2049 2050 if (promopen(O_RDONLY)) { 2051 (void) fprintf(stderr, "%s", 2052 dgettext(TEXT_DOMAIN, "openprom device " 2053 "open failed")); 2054 return; 2055 } 2056 2057 if ((is_openprom() == 0) || (next(0) == 0)) { 2058 (void) fprintf(stderr, "%s", 2059 dgettext(TEXT_DOMAIN, "openprom device " 2060 "error encountered.")); 2061 return; 2062 } 2063 2064 tree = OBP_TREE; /* Switch to the OBP tree */ 2065 2066 (void) walk(&obp_sys_tree, NULL, next(0)); 2067 2068 system_failed = display_failed_parts(&obp_sys_tree); 2069 2070 if (!system_failed) { 2071 log_printf(dgettext(TEXT_DOMAIN, 2072 "No Hardware failures found in System\n"), 0); 2073 } 2074 promclose(); 2075 tree = DEVINFO_TREE; /* Switch back to the DEVINFO tree */ 2076 } 2077 2078 /* 2079 * get_slot_name figures out the slot no. for the card. In the case of 2080 * XMITS slots 2 & 3 and slots 6 & 7 are reversed in slot_name by OBP 2081 * so we need to cater for this to correctly identify the slot no. 2082 */ 2083 static void 2084 get_slot_name(struct io_card *card, char *slot_name) 2085 { 2086 char tmp_ptr[2]; 2087 2088 if (strlen(slot_name) != 0) { 2089 if (strcmp(card->notes, XMITS_COMPATIBLE) == 0) { 2090 (void) sprintf(tmp_ptr, "%c", 2091 slot_name[strlen(slot_name) -1]); 2092 switch (tmp_ptr[0]) { 2093 case '2': 2094 (void) sprintf(card->slot_str, "%c", '3'); 2095 break; 2096 case '3': 2097 (void) sprintf(card->slot_str, "%c", '2'); 2098 break; 2099 case '6': 2100 (void) sprintf(card->slot_str, "%c", '7'); 2101 break; 2102 case '7': 2103 (void) sprintf(card->slot_str, "%c", '6'); 2104 break; 2105 default: 2106 (void) sprintf(card->slot_str, "%c", 2107 slot_name[strlen(slot_name) -1]); 2108 } 2109 } else 2110 (void) sprintf(card->slot_str, "%c", 2111 slot_name[strlen(slot_name) -1]); 2112 } else 2113 (void) sprintf(card->slot_str, "-"); 2114 } 2115