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