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