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 struct cfga_list_data *statlist = NULL; 963 struct cfga_list_data dat; 964 cfga_flags_t flags = CFGA_FLAG_LIST_ALL; 965 966 if (node == NULL) 967 return (FALSE); 968 969 ret = config_list_ext(1, &node, &statlist, &nlist, 970 NULL, NULL, &err_string, flags); 971 972 if (ret == CFGA_OK) { 973 dat = statlist[0]; 974 975 if (dat.ap_o_state == CFGA_STAT_CONFIGURED) 976 rv = TRUE; 977 else 978 rv = FALSE; 979 } else { 980 rv = FALSE; 981 } 982 if (statlist) 983 free(statlist); 984 if (err_string) 985 free(err_string); 986 return (rv); 987 } 988 989 /* 990 * Display the CPUs present on this board. 991 */ 992 void 993 display_cpus(Board_node *board) 994 { 995 Prom_node *cpu; 996 uint_t freq; /* CPU clock frequency */ 997 int ecache_size; /* External cache size */ 998 int board_num = board->board_num; 999 int *mid; 1000 int *impl; 1001 int *mask; 1002 int decoded_mask; 1003 int *coreid; 1004 int mid_prev = -1; 1005 int ecache_size_prev = 0; 1006 char fru_prev[MAX_FRU_NAME_LEN] = ""; 1007 1008 /* 1009 * display the CPUs' operating frequency, cache size, impl. field 1010 * and mask revision. 1011 */ 1012 for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL; 1013 cpu = dev_next_type(cpu, "cpu")) { 1014 char fru_name[MAX_FRU_NAME_LEN] = ""; 1015 char cfg_fru_name[MAX_FRU_NAME_LEN] = ""; 1016 1017 mid = (int *)get_prop_val(find_prop(cpu, "portid")); 1018 if (mid == NULL) 1019 mid = (int *)get_prop_val(find_prop(cpu, "cpuid")); 1020 freq = SG_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu)); 1021 ecache_size = get_ecache_size(cpu); 1022 impl = (int *)get_prop_val(find_prop(cpu, "implementation#")); 1023 mask = (int *)get_prop_val(find_prop(cpu, "mask#")); 1024 1025 /* Do not display a failed CPU node */ 1026 if ((impl == NULL) || (freq == 0) || (node_failed(cpu))) 1027 continue; 1028 1029 /* FRU Name */ 1030 SG_SET_FRU_NAME_NODE(fru_name, board->node_id); 1031 1032 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board_num); 1033 SG_SET_FRU_NAME_MODULE(fru_name, *mid % 4); 1034 1035 if (CPU_IMPL_IS_CMP(*impl)) { 1036 coreid = (int *)get_prop_val(find_prop(cpu, 1037 "reg")); 1038 if (coreid == NULL) { 1039 continue; 1040 } 1041 1042 /* 1043 * The assumption is made that 2 cores will always be 1044 * listed together in the device tree. If either core 1045 * is "bad" then the FRU will not be listed. 1046 * 1047 * As display_cpus on Serengeti does actually process 1048 * all cpu's per board a copy of the fru_name needs to 1049 * be made as the following core may not be its 1050 * sibling. If this is the case it is assumed that a 1051 * sibling core has failed, so the fru should not be 1052 * displayed. 1053 * 1054 * For the first instance of a core, fru_prev is 1055 * expected to be empty. The current values are then 1056 * stored and the next board->nodes is processed. If 1057 * this is a sibling core, the ecache size it tallied 1058 * and the previous value reset and processing 1059 * continues. 1060 * 1061 * If the following core is not a sibling, the new 1062 * values are stored and the next board->nodes is 1063 * processed. 1064 */ 1065 if (strncmp(fru_prev, "", sizeof (fru_prev)) == 0) { 1066 strncpy(fru_prev, fru_name, sizeof (fru_name)); 1067 mid_prev = *mid; 1068 ecache_size_prev = ecache_size; 1069 continue; 1070 } else { 1071 if (strncmp(fru_name, fru_prev, 1072 sizeof (fru_prev)) == 0) { 1073 /* 1074 * Jaguar has a split E$, so the size 1075 * for both cores must be added together 1076 * to get the total size for the entire 1077 * chip. 1078 * 1079 * Panther E$ (L3) is logically shared, 1080 * so the total size is equal to the 1081 * core size. 1082 */ 1083 if (IS_JAGUAR(*impl)) { 1084 ecache_size += ecache_size_prev; 1085 } 1086 1087 ecache_size_prev = 0; 1088 strncpy(fru_prev, "", 1089 sizeof (fru_prev)); 1090 } else { 1091 mid_prev = *mid; 1092 ecache_size_prev = ecache_size; 1093 strncpy(fru_prev, fru_name, 1094 sizeof (fru_name)); 1095 continue; 1096 } 1097 } 1098 } 1099 1100 /* 1101 * If cpu is not configured, do not display it 1102 */ 1103 CFG_SET_FRU_NAME_NODE(cfg_fru_name, board->node_id); 1104 CFG_SET_FRU_NAME_CPU_BOARD(cfg_fru_name, board_num); 1105 CFG_SET_FRU_NAME_MODULE(cfg_fru_name, *mid % 4); 1106 1107 if (!(cpu_node_configured(cfg_fru_name))) { 1108 continue; 1109 } 1110 1111 1112 log_printf("%-10s ", fru_name, 0); 1113 1114 /* CPU MID */ 1115 if (CPU_IMPL_IS_CMP(*impl)) { 1116 log_printf("%3d,%3d ", mid_prev, *mid, 0); 1117 mid_prev = -1; 1118 } else 1119 log_printf("%3d ", *mid, 0); 1120 1121 /* Running frequency */ 1122 log_printf(" %4u ", freq, 0); 1123 1124 /* Ecache size */ 1125 if (ecache_size == 0) 1126 log_printf("%3s ", "N/A", 0); 1127 else 1128 log_printf("%4.1f ", 1129 (float)ecache_size / (float)(1<<20), 1130 0); 1131 1132 /* Implementation */ 1133 if (impl == NULL) { 1134 log_printf("%6s ", " N/A", 0); 1135 } else { 1136 switch (*impl) { 1137 case CHEETAH_IMPL: 1138 log_printf("%-7s ", "US-III", 0); 1139 break; 1140 case CHEETAH_PLUS_IMPL: 1141 log_printf("%-7s ", "US-III+", 0); 1142 break; 1143 case JAGUAR_IMPL: 1144 log_printf("%-7s ", "US-IV", 0); 1145 break; 1146 case PANTHER_IMPL: 1147 log_printf("%-7s ", "US-IV+", 0); 1148 break; 1149 default: 1150 log_printf("%-7x ", *impl, 0); 1151 break; 1152 } 1153 } 1154 1155 /* CPU Mask */ 1156 if (mask == NULL) { 1157 log_printf(" %3s ", "N/A", 0); 1158 } else { 1159 if (IS_CHEETAH(*impl)) 1160 decoded_mask = REMAP_CHEETAH_MASK(*mask); 1161 else 1162 decoded_mask = *mask; 1163 1164 log_printf(" %d.%d ", 1165 (decoded_mask >> 4) & 0xf, 1166 decoded_mask & 0xf, 0); 1167 } 1168 1169 log_printf("\n", 0); 1170 } 1171 } 1172 1173 1174 /*ARGSUSED3*/ 1175 void 1176 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 1177 struct system_kstat_data *kstats) 1178 { 1179 log_printf("\n", 0); 1180 log_printf("=========================", 0); 1181 log_printf(dgettext(TEXT_DOMAIN, " Hardware Failures "), 0); 1182 log_printf("==================================", 0); 1183 log_printf("\n", 0); 1184 1185 /* 1186 * Get a list of failed parts (ie. devices with a status of 1187 * 'fail') from the OBP device tree and display them. 1188 */ 1189 get_failed_parts(); 1190 1191 /* return unless -v option specified */ 1192 if (!flag) { 1193 log_printf("\n", 0); 1194 return; 1195 } 1196 1197 /* 1198 * display time of latest powerfail. Not all systems 1199 * have this capability. For those that do not, this 1200 * is just a no-op. 1201 */ 1202 disp_powerfail(root); 1203 1204 /* Print the PROM revisions here */ 1205 serengeti_display_hw_revisions(root, tree->bd_list); 1206 } 1207 1208 /* 1209 * local functions - functions that are only needed inside this library 1210 */ 1211 1212 static void 1213 serengeti_display_hw_revisions(Prom_node *root, Board_node *bdlist) 1214 { 1215 Prom_node *pnode; 1216 char *value; 1217 1218 /* Print the header */ 1219 log_printf("\n", 0); 1220 log_printf("=========================", 0); 1221 log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0); 1222 log_printf("=======================================", 0); 1223 log_printf("\n", 0); 1224 log_printf("\n", 0); 1225 1226 /* Display Prom revision header */ 1227 log_printf("System PROM revisions:\n", 0); 1228 log_printf("----------------------\n", 0); 1229 1230 /* 1231 * Display OBP version info 1232 */ 1233 pnode = dev_find_node(root, "openprom"); 1234 if (pnode != NULL) { 1235 value = (char *)get_prop_val(find_prop(pnode, "version")); 1236 log_printf("%s\n\n", value, 0); 1237 } else { 1238 log_printf("OBP ???\n\n", value, 0); 1239 } 1240 1241 /* 1242 * Display ASIC revisions 1243 */ 1244 log_printf("IO ASIC revisions:\n", 0); 1245 log_printf("------------------\n", 0); 1246 1247 log_printf(" Port\n", 0); 1248 log_printf("FRU Name Model ID Status", 0); 1249 #ifdef DEBUG 1250 log_printf(" Version Notes\n", 0); 1251 #else 1252 log_printf(" Version\n", 0); 1253 #endif 1254 /* ---------FRU Name--Model-----------Port-Status */ 1255 log_printf("----------- --------------- ---- ---------- " 1256 #ifdef DEBUG 1257 "------- " 1258 #endif 1259 "-------\n", 0); 1260 /* 1261 * Display SCHIZO version info 1262 */ 1263 display_schizo_revisions(bdlist, SG_SCHIZO_GOOD); 1264 1265 /* 1266 * Display sgsbbc version info 1267 */ 1268 display_sgsbbc_revisions(bdlist); 1269 } 1270 1271 /* 1272 * This function displays Schizo and Xmits revision of boards 1273 */ 1274 static int 1275 display_schizo_revisions(Board_node *bdlist, int mode) 1276 { 1277 Prom_node *pnode; 1278 int *int_val; 1279 int portid; 1280 int prev_portid = -1; 1281 char *model; 1282 char *status_a, *status_b; 1283 char status[MAX_STATUS_LEN]; 1284 int version; 1285 int node_id; 1286 #ifdef DEBUG 1287 uint32_t a_notes, b_notes; 1288 #endif 1289 int pci_bus; 1290 /* 1291 * rv is used when mode is set to SG_SCHIZO_FAILED. 1292 * We need to signal if a failure is found so that 1293 * the correct headers/footers can be printed. 1294 * 1295 * rv = 1 implies a failed/disavled schizo device 1296 * rv = 0 implies all other cases 1297 */ 1298 int rv = 0; 1299 Board_node *bnode; 1300 void *value; 1301 1302 bnode = bdlist; 1303 while (bnode != NULL) { 1304 /* 1305 * search this board node for all Schizos 1306 */ 1307 for (pnode = dev_find_node_by_compatible(bnode->nodes, 1308 SCHIZO_COMPATIBLE); pnode != NULL; 1309 pnode = dev_next_node_by_compatible(pnode, 1310 SCHIZO_COMPATIBLE)) { 1311 1312 char fru_name[MAX_FRU_NAME_LEN] = ""; 1313 1314 /* 1315 * get the reg property to determine 1316 * whether we are looking at side A or B 1317 */ 1318 int_val = (int *)get_prop_val 1319 (find_prop(pnode, "reg")); 1320 if (int_val != NULL) { 1321 int_val ++; /* second integer in array */ 1322 pci_bus = ((*int_val) & 0x7f0000); 1323 } 1324 1325 /* get portid */ 1326 int_val = (int *)get_prop_val 1327 (find_prop(pnode, "portid")); 1328 if (int_val == NULL) 1329 continue; 1330 1331 portid = *int_val; 1332 1333 /* 1334 * If this is a new portid and it is PCI bus B, 1335 * we skip onto the PCI bus A. (PCI-A and PCI-B share 1336 * the same portid) 1337 */ 1338 if ((portid != prev_portid) && (pci_bus == 0x700000)) { 1339 prev_portid = portid; 1340 /* status */ 1341 status_b = (char *)get_prop_val 1342 (find_prop(pnode, "status")); 1343 #ifdef DEBUG 1344 b_notes = pci_bus; 1345 #endif 1346 continue; /* skip to the next schizo */ 1347 } 1348 1349 /* 1350 * This must be side A of the same Schizo. 1351 * Gather all its props and display them. 1352 */ 1353 #ifdef DEBUG 1354 a_notes = pci_bus; 1355 #endif 1356 1357 prev_portid = portid; 1358 1359 /* get the node-id */ 1360 node_id = SG_PORTID_TO_NODEID(portid); 1361 1362 /* model */ 1363 model = (char *)get_prop_val 1364 (find_prop(pnode, "model")); 1365 1366 /* version */ 1367 value = (int *)get_prop_val 1368 (find_prop(pnode, "module-revision#")); 1369 1370 if (value) 1371 int_val = (int *)value; 1372 else 1373 int_val = (int *)get_prop_val 1374 (find_prop(pnode, "version#")); 1375 if (int_val != NULL) 1376 version = *int_val; 1377 else 1378 version = -1; 1379 1380 /* status */ 1381 status_a = (char *)get_prop_val(find_prop 1382 (pnode, "status")); 1383 1384 /* 1385 * Display the data 1386 */ 1387 /* FRU Name */ 1388 SG_SET_FRU_NAME_NODE(fru_name, node_id); 1389 SG_SET_FRU_NAME_IO_BOARD(fru_name, 1390 SG_IO_BD_PORTID_TO_BD_NUM(portid)); 1391 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1392 1393 if (mode == SG_SCHIZO_FAILED) { 1394 if ((status_a != (char *)NULL) && 1395 ((status_b != (char *)NULL))) { 1396 if ((strcmp 1397 (status_a, SG_DISABLED) == 0) && 1398 (strcmp(status_b, 1399 SG_DISABLED) == 0)) { 1400 log_printf("\tFRU Type : %s\n ", 1401 model, 0); 1402 log_printf("\tLocation : %s\n", 1403 fru_name, 0); 1404 log_printf 1405 ("\tPROM status: %s\n\n", 1406 SG_DISABLED, 0); 1407 rv = 1; 1408 } 1409 } 1410 continue; 1411 } 1412 /* 1413 * This section of code is executed when displaying 1414 * non-failed schizo devices. If the mode is set to 1415 * SG_SCHIZO_FAILED, then this section of code will 1416 * not be executed 1417 */ 1418 if ((status_a == (char *)NULL) && 1419 ((status_b == (char *)NULL))) 1420 sprintf(status, " %s ", SG_OK); 1421 else if ((status_a == (char *)NULL) && 1422 ((strcmp(status_b, SG_DISABLED) == 0))) 1423 sprintf(status, " %s", SG_DEGRADED); 1424 else if ((status_b == (char *)NULL) && 1425 ((strcmp(status_a, SG_DISABLED) == 0))) 1426 sprintf(status, " %s", SG_DEGRADED); 1427 else 1428 continue; 1429 1430 log_printf("%-12s", fru_name, 0); 1431 1432 /* model */ 1433 1434 if (model != NULL) 1435 log_printf("%-15s ", model, 0); 1436 else 1437 log_printf("%-15s ", "unknown", 0); 1438 /* portid */ 1439 log_printf("%-3d ", portid, 0); 1440 1441 /* status */ 1442 log_printf("%s", status, 0); 1443 1444 /* version */ 1445 log_printf(" %-4d ", version, 0); 1446 #ifdef DEBUG 1447 log_printf("0x%x 0x%x", a_notes, b_notes, 0); 1448 log_printf(" %d", portid, 0); 1449 #endif 1450 log_printf("\n", 0); 1451 } 1452 bnode = bnode->next; 1453 } 1454 return (rv); 1455 } 1456 1457 static void 1458 display_sgsbbc_revisions(Board_node *bdlist) 1459 { 1460 1461 Prom_node *pnode; 1462 int *int_val; 1463 int portid; 1464 char *model; 1465 char *status; 1466 int revision; 1467 int node_id; 1468 Board_node *bnode; 1469 1470 #ifdef DEBUG 1471 char *slot_name; 1472 char notes[30]; 1473 char *value; 1474 #endif 1475 1476 bnode = bdlist; 1477 while (bnode != NULL) { 1478 /* 1479 * search this board node for all sgsbbc's 1480 */ 1481 for (pnode = dev_find_node_by_type(bnode->nodes, "model", 1482 "SUNW,sgsbbc"); pnode != NULL; 1483 pnode = dev_next_node_by_type(pnode, "model", 1484 "SUNW,sgsbbc")) { 1485 1486 char fru_name[MAX_FRU_NAME_LEN] = ""; 1487 1488 /* 1489 * We need to go to this node's parent to 1490 * get a portid to tell us what board it is on 1491 */ 1492 int_val = (int *)get_prop_val 1493 (find_prop(pnode->parent, "portid")); 1494 if (int_val == NULL) 1495 continue; 1496 1497 portid = *int_val; 1498 /* get the node-id */ 1499 node_id = SG_PORTID_TO_NODEID(portid); 1500 1501 /* model */ 1502 model = (char *)get_prop_val 1503 (find_prop(pnode, "model")); 1504 1505 /* status */ 1506 status = (char *)get_prop_val(find_prop 1507 (pnode, "status")); 1508 1509 /* revision */ 1510 int_val = (int *)get_prop_val 1511 (find_prop(pnode, "revision-id")); 1512 if (int_val != NULL) 1513 revision = *int_val; 1514 else 1515 revision = -1; 1516 1517 #ifdef DEBUG 1518 value = (char *)get_prop_val( 1519 find_prop(pnode->parent, "slot-names")); 1520 if (value != NULL) { 1521 /* Skip the 4 byte bitmask */ 1522 slot_name = (char *)value + sizeof (int); 1523 } else { 1524 strcpy(slot_name, "not_found"); 1525 } 1526 (void) sprintf(notes, "[%s] portid [%d]", slot_name, 1527 portid); 1528 #endif 1529 /* 1530 * Display the data 1531 */ 1532 /* FRU Name */ 1533 SG_SET_FRU_NAME_NODE(fru_name, node_id); 1534 SG_SET_FRU_NAME_IO_BOARD(fru_name, 1535 SG_IO_BD_PORTID_TO_BD_NUM(portid)); 1536 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1537 log_printf("%-12s", fru_name, 0); 1538 1539 /* model */ 1540 if (model != NULL) 1541 log_printf("%-15s ", model, 0); 1542 else 1543 log_printf("%-15s ", "unknown", 0); 1544 /* portid */ 1545 log_printf("%-3d ", portid, 0); 1546 /* status */ 1547 if (status == (char *)NULL) 1548 log_printf(" ok ", 0); 1549 else 1550 log_printf(" fail ", 0); 1551 /* revision */ 1552 log_printf(" %-4d ", revision, 0); 1553 #ifdef DEBUG 1554 log_printf("%s", notes, 0); 1555 #endif 1556 log_printf("\n", 0); 1557 } 1558 bnode = bnode->next; 1559 } 1560 } 1561 1562 /*ARGSUSED0*/ 1563 void 1564 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats) 1565 { 1566 serengeti_display_board_info(ACTIVE); 1567 serengeti_display_board_info(INACTIVE); 1568 } 1569 1570 /* 1571 * display_failed_parts 1572 * 1573 * Display the failed parts in the system. This function looks for 1574 * the status property in all PROM nodes contained in the Sys_tree 1575 * passed in. 1576 */ 1577 int 1578 display_failed_parts(Sys_tree *tree) 1579 { 1580 int system_failed = 0; 1581 int bank_failed = 0; 1582 int schizo_failed = FALSE; 1583 int portid, nodeid, board; 1584 Board_node *bnode = tree->bd_list; 1585 Prom_node *pnode; 1586 int *coreid, *impl; 1587 print_flag = TRUE; 1588 1589 /* 1590 * go through all of the OBP nodes looking for 1591 * failed units. 1592 */ 1593 while (bnode != NULL) { 1594 1595 pnode = find_failed_node(bnode->nodes); 1596 if ((pnode != NULL) && !system_failed) { 1597 system_failed = TRUE; 1598 log_printf("\n", 0); 1599 log_printf(dgettext(TEXT_DOMAIN, 1600 "Failed Field Replaceable Units (FRU) in " 1601 "System:\n"), 0); 1602 log_printf("==========================" 1603 "====================\n", 0); 1604 } 1605 1606 while (pnode != NULL) { 1607 void *status; 1608 char *name, *type, *model; 1609 1610 char fru_name[MAX_FRU_NAME_LEN] = ""; 1611 1612 status = get_prop_val(find_prop(pnode, "status")); 1613 name = get_node_name(pnode); 1614 1615 /* sanity check of data retreived from PROM */ 1616 if ((status == NULL) || (name == NULL)) { 1617 pnode = next_failed_node(pnode); 1618 continue; 1619 } 1620 1621 type = get_node_type(pnode); 1622 portid = get_id(pnode); 1623 model = (char *)get_prop_val 1624 (find_prop(pnode, "model")); 1625 1626 /* 1627 * Determine whether FRU is CPU module, Mem Controller, 1628 * PCI card, schizo,xmits or sgsbbc. 1629 */ 1630 if ((model != NULL) && strstr(model, "sgsbbc")) { 1631 /* 1632 * sgsbbc / bootbus-controller 1633 */ 1634 portid = get_id(pnode->parent); 1635 nodeid = SG_PORTID_TO_NODEID(portid); 1636 board = SG_PORTID_TO_BOARD_NUM(portid); 1637 1638 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1639 SG_SET_FRU_NAME_IO_BOARD(fru_name, board); 1640 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1641 1642 log_printf("\tFailed Device : %s (%s)\n", model, 1643 name, 0); 1644 log_printf("\tLocation : %s\n", fru_name, 0); 1645 1646 } else if (strstr(name, "pci") && (portid == -1)) { 1647 /* 1648 * PCI Bridge if name = pci and it doesn't 1649 * have a portid. 1650 */ 1651 portid = get_id(pnode->parent); 1652 nodeid = SG_PORTID_TO_NODEID(portid); 1653 board = SG_PORTID_TO_BOARD_NUM(portid); 1654 1655 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1656 SG_SET_FRU_NAME_IO_BOARD(fru_name, board); 1657 SG_SET_FRU_NAME_MODULE(fru_name, portid % 2); 1658 1659 log_printf("\tFRU type : ", 0); 1660 log_printf("PCI Bridge Device\n", 0); 1661 log_printf("\tLocation : %s\n", fru_name, 0); 1662 1663 } else if ((type != NULL) && 1664 (strstr(type, "cpu") || 1665 strstr(type, "memory-controller"))) { 1666 /* 1667 * CPU or memory controller 1668 */ 1669 portid = get_id(pnode); 1670 /* 1671 * For cpu nodes that belong to a CMP, the 1672 * portid is stored in the parent "cmp" node. 1673 */ 1674 if (portid == -1) 1675 portid = get_id(pnode->parent); 1676 nodeid = SG_PORTID_TO_NODEID(portid); 1677 board = SG_PORTID_TO_BOARD_NUM(portid); 1678 1679 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1680 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board); 1681 SG_SET_FRU_NAME_MODULE(fru_name, portid % 4); 1682 1683 log_printf("\tFRU type : ", 0); 1684 1685 if (strstr(type, "memory-controller")) 1686 log_printf("Memory Controller on ", 0); 1687 1688 log_printf("UltraSPARC module\n", 0); 1689 1690 log_printf("\tLocation : %s\n", fru_name, 0); 1691 1692 } else { 1693 /* 1694 * It should only be a PCI card if we get to 1695 * here but lets check to be sure. 1696 */ 1697 char *parents_model, *grandparents_model; 1698 Prom_node *parent_pnode; 1699 int pci_card_found = 0; 1700 1701 if (pnode->parent != NULL) 1702 parent_pnode = pnode->parent; 1703 1704 /* 1705 * Is our parent a schizo or xmits 1706 */ 1707 parents_model = (char *)get_prop_val 1708 (find_prop(pnode->parent, "model")); 1709 if ((parents_model != NULL) && 1710 (strstr(parents_model, "SUNW,schizo") || 1711 strstr(parents_model, "SUNW,xmits"))) { 1712 portid = get_id(pnode->parent); 1713 pci_card_found = TRUE; 1714 } 1715 1716 /* 1717 * Is our grandparent a schizo xmits 1718 */ 1719 grandparents_model = (char *)get_prop_val 1720 (find_prop(parent_pnode->parent, "model")); 1721 if ((grandparents_model != NULL) && 1722 (strstr(grandparents_model, 1723 "SUNW,schizo") || 1724 strstr(grandparents_model, 1725 "SUNW,xmits"))) { 1726 portid = get_id(parent_pnode->parent); 1727 pci_card_found = TRUE; 1728 } 1729 1730 if (pci_card_found) { 1731 nodeid = SG_PORTID_TO_NODEID(portid); 1732 board = SG_PORTID_TO_BOARD_NUM(portid); 1733 1734 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1735 SG_SET_FRU_NAME_IO_BOARD(fru_name, 1736 board); 1737 SG_SET_FRU_NAME_MODULE(fru_name, 1738 portid % 2); 1739 1740 log_printf("\tFRU type :", 0); 1741 log_printf(" PCI Card\n", 0); 1742 log_printf("\tLocation : %s\n", 1743 fru_name, 0); 1744 } 1745 } 1746 log_printf("\tPROM status: %s\n\n", status, 0); 1747 1748 pnode = next_failed_node(pnode); 1749 } 1750 bnode = bnode->next; 1751 1752 } 1753 1754 bank_failed = display_us3_failed_banks(system_failed); 1755 schizo_failed = display_schizo_revisions(tree->bd_list, 1756 SG_SCHIZO_FAILED); 1757 if (system_failed || bank_failed || schizo_failed) 1758 return (1); 1759 else 1760 return (0); 1761 } 1762 1763 1764 /* 1765 * This routine displays the memory configuration for all boards in the 1766 * system. 1767 */ 1768 void 1769 display_memoryconf(Sys_tree *tree) 1770 { 1771 Board_node *bnode = tree->bd_list; 1772 1773 log_printf("========================= Memory Configuration" 1774 " ===============================\n", 0); 1775 log_printf("\n Logical Logical Logical ", 0); 1776 log_printf("\n Port Bank Bank Bank " 1777 "DIMM Interleave Interleave", 0); 1778 log_printf("\nFRU Name ID Num Size Status " 1779 "Size Factor Segment", 0); 1780 log_printf("\n------------- ---- ---- ------ ----------- " 1781 "------ ---------- ----------", 0); 1782 1783 while (bnode != NULL) { 1784 if (get_us3_mem_regs(bnode)) { 1785 log_printf(dgettext(TEXT_DOMAIN, 1786 "\nFailed to get memory information.\n"), 0); 1787 return; 1788 } 1789 bnode = bnode->next; 1790 } 1791 1792 /* Display what we have found */ 1793 display_us3_banks(); 1794 } 1795 1796 /* 1797 * This function provides Serengeti's formatting of the memory config 1798 * information that get_us3_mem_regs() and display_us3_banks() code has 1799 * gathered. It overrides the generic print_us3_memory_line() code 1800 * which prints an error message. 1801 */ 1802 void 1803 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 1804 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id) 1805 { 1806 int nodeid, board, mcid; 1807 char fru_name[MAX_FRU_NAME_LEN] = ""; 1808 1809 mcid = SG_PORTID_TO_SAFARI_ID(portid); 1810 nodeid = SG_PORTID_TO_NODEID(portid); 1811 board = SG_PORTID_TO_BOARD_NUM(portid); 1812 1813 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1814 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board); 1815 SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4); 1816 SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2); 1817 1818 log_printf("\n%-13s %2d %2d %4lldMB %11-s %4lldMB " 1819 " %2d-way %d", 1820 fru_name, mcid, 1821 (bank_id % 4), bank_size, bank_status, dimm_size, 1822 intlv, seg_id, 0); 1823 } 1824 1825 void 1826 print_us3_failed_memory_line(int portid, int bank_id, char *bank_status) 1827 { 1828 int nodeid, board, mcid; 1829 char fru_name[MAX_FRU_NAME_LEN] = ""; 1830 1831 mcid = SG_PORTID_TO_SAFARI_ID(portid); 1832 nodeid = SG_PORTID_TO_NODEID(portid); 1833 board = SG_PORTID_TO_BOARD_NUM(portid); 1834 1835 SG_SET_FRU_NAME_NODE(fru_name, nodeid); 1836 SG_SET_FRU_NAME_CPU_BOARD(fru_name, board); 1837 SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4); 1838 SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2); 1839 1840 log_printf("\tFRU type : ", 0); 1841 log_printf("Physical Memory Bank\n", 0); 1842 log_printf("\tLocation : %s (Logical Bank %2d)\n", 1843 fru_name, (bank_id %4), 0); 1844 log_printf("\tPROM status: %s\n\n", bank_status, 0); 1845 } 1846 1847 1848 /* 1849 * Find the requested board struct in the system device tree. 1850 * 1851 * This function overrides the functionality of the generic find_board() 1852 * function in libprtdiag, but since we need to pass another parameter, 1853 * we cannot simply overlay the symbol table. 1854 */ 1855 static Board_node * 1856 serengeti_find_board(Sys_tree *root, int board, int nodeid) 1857 { 1858 Board_node *bnode = root->bd_list; 1859 1860 while ((bnode != NULL) && 1861 ((board != bnode->board_num) || (nodeid != bnode->node_id))) { 1862 bnode = bnode->next; 1863 } 1864 return (bnode); 1865 } 1866 1867 1868 /* 1869 * Add a board to the system list in order (sorted by NodeID then board#). 1870 * Initialize all pointer fields to NULL. 1871 */ 1872 static Board_node * 1873 serengeti_insert_board(Sys_tree *root, int board, int nodeid) 1874 { 1875 Board_node *bnode; 1876 Board_node *temp = root->bd_list; 1877 1878 if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) { 1879 perror("malloc"); 1880 exit(1); 1881 } 1882 1883 bnode->nodes = NULL; 1884 bnode->next = NULL; 1885 bnode->board_num = board; 1886 bnode->node_id = nodeid; 1887 bnode->board_type = UNKNOWN_BOARD; 1888 1889 if (temp == NULL) 1890 root->bd_list = bnode; 1891 1892 else if ((temp->board_num > board) && (temp->node_id >= nodeid)) { 1893 bnode->next = temp; 1894 root->bd_list = bnode; 1895 1896 } else { 1897 while ((temp->next != NULL) && 1898 ((board > temp->next->board_num) || 1899 (nodeid > temp->node_id))) 1900 temp = temp->next; 1901 1902 bnode->next = temp->next; 1903 temp->next = bnode; 1904 } 1905 root->board_cnt++; 1906 1907 return (bnode); 1908 } 1909 1910 /* 1911 * We call do_devinfo() in order to use the libdevinfo device tree 1912 * instead of OBP's device tree. 1913 */ 1914 int 1915 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 1916 { 1917 1918 return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); 1919 1920 } 1921 1922 /* 1923 * return the property value for the Prop passed in depending on 1924 * which tree (OBP/DEVINFO) is being used. 1925 */ 1926 void * 1927 get_prop_val(Prop *prop) 1928 { 1929 if (prop == NULL) 1930 return (NULL); 1931 1932 /* Check which tree is being used. */ 1933 if (tree == DEVINFO_TREE) 1934 return ((void *)(prop->value.val_ptr)); 1935 else { 1936 if (prop->value.opp.holds_array) 1937 return ((void *)(prop->value.opp.oprom_array)); 1938 else 1939 return ((void *)(&prop->value.opp.oprom_node[0])); 1940 } 1941 } 1942 1943 /* 1944 * Search a Prom node and retrieve the property with the correct 1945 * name depending on which tree (OBP/DEVINFO) is being used. 1946 */ 1947 Prop * 1948 find_prop(Prom_node *pnode, char *name) 1949 { 1950 Prop *prop; 1951 1952 if (pnode == NULL) 1953 return (NULL); 1954 1955 if (pnode->props == NULL) 1956 return (NULL); 1957 1958 prop = pnode->props; 1959 1960 /* Check which tree is being used. */ 1961 if (tree == DEVINFO_TREE) { 1962 while ((prop != NULL) && 1963 (strcmp((char *)(prop->name.val_ptr), name))) 1964 prop = prop->next; 1965 } else { 1966 while ((prop != NULL) && (strcmp((char *) 1967 (prop->name.opp.oprom_array), name))) 1968 prop = prop->next; 1969 } 1970 return (prop); 1971 } 1972 1973 /* 1974 * This function searches through the properties of the node passed in 1975 * and returns a pointer to the value of the name property 1976 * depending on which tree (OBP/DEVINFO) is being used. 1977 */ 1978 char * 1979 get_node_name(Prom_node *pnode) 1980 { 1981 Prop *prop; 1982 1983 if (pnode == NULL) 1984 return (NULL); 1985 1986 prop = pnode->props; 1987 while (prop != NULL) { 1988 /* Check which tree is being used. */ 1989 if (tree == DEVINFO_TREE) { 1990 if (strcmp("name", (char *)prop->name.val_ptr) == 0) 1991 return ((char *)prop->value.val_ptr); 1992 } else { 1993 if (strcmp("name", prop->name.opp.oprom_array) == 0) 1994 return (prop->value.opp.oprom_array); 1995 } 1996 prop = prop->next; 1997 } 1998 return (NULL); 1999 } 2000 2001 /* 2002 * This function searches through the properties of the node passed in 2003 * and returns a pointer to the value of the device_type property 2004 * depending on which tree (OBP/DEVINFO) is being used. 2005 */ 2006 char * 2007 get_node_type(Prom_node *pnode) 2008 { 2009 Prop *prop; 2010 2011 if (pnode == NULL) 2012 return (NULL); 2013 2014 prop = pnode->props; 2015 while (prop != NULL) { 2016 /* Check which tree is being used. */ 2017 if (tree == DEVINFO_TREE) { 2018 if (strcmp("device_type", (char *)prop->name.val_ptr) 2019 == 0) 2020 return ((char *)prop->value.val_ptr); 2021 } else { 2022 if (strcmp("device_type", prop->name.opp.oprom_array) 2023 == 0) 2024 return (prop->value.opp.oprom_array); 2025 } 2026 prop = prop->next; 2027 } 2028 return (NULL); 2029 } 2030 2031 /* 2032 * Take a snapshot of the OBP device tree and walk this snapshot 2033 * to find all failed HW (ie. devices with a status property of 2034 * 'fail'). Call display_failed_parts() to display the failed HW. 2035 */ 2036 void 2037 get_failed_parts(void) 2038 { 2039 int system_failed = 0; 2040 Sys_tree obp_sys_tree; /* system information */ 2041 2042 /* set the the system tree fields */ 2043 obp_sys_tree.sys_mem = NULL; 2044 obp_sys_tree.boards = NULL; 2045 obp_sys_tree.bd_list = NULL; 2046 obp_sys_tree.board_cnt = 0; 2047 2048 if (promopen(O_RDONLY)) { 2049 (void) fprintf(stderr, "%s", 2050 dgettext(TEXT_DOMAIN, "openprom device " 2051 "open failed")); 2052 return; 2053 } 2054 2055 if ((is_openprom() == 0) || (next(0) == 0)) { 2056 (void) fprintf(stderr, "%s", 2057 dgettext(TEXT_DOMAIN, "openprom device " 2058 "error encountered.")); 2059 return; 2060 } 2061 2062 tree = OBP_TREE; /* Switch to the OBP tree */ 2063 2064 (void) walk(&obp_sys_tree, NULL, next(0)); 2065 2066 system_failed = display_failed_parts(&obp_sys_tree); 2067 2068 if (!system_failed) { 2069 log_printf(dgettext(TEXT_DOMAIN, 2070 "No Hardware failures found in System\n"), 0); 2071 } 2072 promclose(); 2073 tree = DEVINFO_TREE; /* Switch back to the DEVINFO tree */ 2074 } 2075 2076 /* 2077 * get_slot_name figures out the slot no. for the card. In the case of 2078 * XMITS slots 2 & 3 and slots 6 & 7 are reversed in slot_name by OBP 2079 * so we need to cater for this to correctly identify the slot no. 2080 */ 2081 static void 2082 get_slot_name(struct io_card *card, char *slot_name) 2083 { 2084 char tmp_ptr[2]; 2085 2086 if (strlen(slot_name) != 0) { 2087 if (strcmp(card->notes, XMITS_COMPATIBLE) == 0) { 2088 (void) sprintf(tmp_ptr, "%c", 2089 slot_name[strlen(slot_name) -1]); 2090 switch (tmp_ptr[0]) { 2091 case '2': 2092 (void) sprintf(card->slot_str, "%c", '3'); 2093 break; 2094 case '3': 2095 (void) sprintf(card->slot_str, "%c", '2'); 2096 break; 2097 case '6': 2098 (void) sprintf(card->slot_str, "%c", '7'); 2099 break; 2100 case '7': 2101 (void) sprintf(card->slot_str, "%c", '6'); 2102 break; 2103 default: 2104 (void) sprintf(card->slot_str, "%c", 2105 slot_name[strlen(slot_name) -1]); 2106 } 2107 } else 2108 (void) sprintf(card->slot_str, "%c", 2109 slot_name[strlen(slot_name) -1]); 2110 } else 2111 (void) sprintf(card->slot_str, "-"); 2112 } 2113