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