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 * Starcat Platform specific functions. 26 * 27 * called when : 28 * machine_type == MTYPE_STARCAT 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <unistd.h> 36 #include <ctype.h> 37 #include <string.h> 38 #include <kvm.h> 39 #include <varargs.h> 40 #include <time.h> 41 #include <dirent.h> 42 #include <fcntl.h> 43 #include <assert.h> 44 #include <sys/param.h> 45 #include <sys/stat.h> 46 #include <sys/types.h> 47 #include <sys/utsname.h> 48 #include <sys/openpromio.h> 49 #include <libintl.h> 50 #include <syslog.h> 51 #include <sys/dkio.h> 52 #include <pdevinfo.h> 53 #include <display.h> 54 #include <pdevinfo_sun4u.h> 55 #include <display_sun4u.h> 56 #include <libprtdiag.h> 57 58 #define HZ_TO_MHZ(x) (((x) + 500000) / 1000000) 59 #define PORTID_TO_EXPANDER(p) (((p) >> 5) & 0x1f) 60 #define PORTID_TO_SLOT(p) (((p) >> 3) & 0x1) 61 #define PORTID_TO_INSTANCE(p) ((p) & 0x3) 62 #define SCHIZO_COMPATIBLE "pci108e,8001" 63 #define XMITS_COMPATIBLE "pci108e,8002" 64 #define SC_BOARD_TYPE(id) (PORTID_TO_SLOT(id) ? "IO" : "SB") 65 66 #ifndef TEXT_DOMAIN 67 #define TEXT_DOMAIN "SYS_TEST" 68 #endif /* TEXT_DOMAIN */ 69 70 #define DEFAULT_MAX_FREQ 66 /* 66 MHz */ 71 #define PCIX_MAX_FREQ 90 /* 90 MHz */ 72 73 /* 74 * these functions will overlay the symbol table of libprtdiag 75 * at runtime (Starcat systems only) 76 */ 77 78 int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag); 79 void *get_prop_val(Prop *prop); 80 Prop *find_prop(Prom_node *pnode, char *name); 81 char *get_node_name(Prom_node *pnode); 82 char *get_node_type(Prom_node *pnode); 83 void add_node(Sys_tree *, Prom_node *); 84 void display_pci(Board_node *); 85 void display_ffb(Board_node *, int); 86 void display_io_cards(struct io_card *list); 87 void display_cpu_devices(Sys_tree *tree); 88 void display_cpus(Board_node *board); 89 void display_memoryconf(Sys_tree *tree, struct grp_info *grps); 90 void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 91 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id); 92 void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 93 struct system_kstat_data *kstats); 94 95 /* Local Functions */ 96 static void starcat_disp_hw_revisions(Prom_node *root); 97 static void display_io_max_bus_speed(struct io_card *p); 98 static void display_io_slot_info(struct io_card *p); 99 100 /* The bus max freq is determined based on board level in use */ 101 int board_bus_max_freq = DEFAULT_MAX_FREQ; /* 66MHz default */ 102 103 /* 104 * display_pci 105 * Display all the PCI IO cards on this board. 106 */ 107 void 108 display_pci(Board_node *board) 109 { 110 struct io_card *card_list = NULL; 111 struct io_card card; 112 void *value; 113 Prom_node *pci; 114 Prom_node *card_node; 115 Prom_node *pci_bridge_node = NULL; 116 char *slot_name_arr[MAX_SLOTS_PER_IO_BD] = {NULL}; 117 char *slot_name = NULL; 118 int slot_name_bits; 119 int slot_name_offset = 0; 120 char *child_name; 121 char *name, *type; 122 char buf[MAXSTRLEN]; 123 int *int_val; 124 int pci_bus; 125 int pci_bridge = 0; 126 int pci_bridge_dev_no; 127 int child_dev_no; 128 int i; 129 int portid; 130 int version, *pversion; 131 132 if (board == NULL) 133 return; 134 135 /* Initialize all the common information */ 136 card.display = TRUE; 137 card.board = board->board_num; 138 card.node_id = board->node_id; 139 140 /* 141 * Search for each schizo, then find/display all nodes under 142 * each schizo node found. Since the model property "SUNW,schizo" 143 * is not supported on Starcat, we must match on the compatible 144 * property "pci108e,8001". 145 */ 146 for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE); 147 pci != NULL; 148 pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) { 149 150 /* set max freq for this board */ 151 board_bus_max_freq = DEFAULT_MAX_FREQ; 152 /* 153 * Find out if this is a PCI or cPCI IO Board. 154 * If "enum-impl" property exists in pci node => cPCI. 155 */ 156 value = get_prop_val(find_prop(pci, "enum-impl")); 157 if (value == NULL) { 158 (void) sprintf(card.bus_type, "PCI"); 159 } else { 160 (void) sprintf(card.bus_type, "cPCI"); 161 } 162 163 if (strstr((char *)get_prop_val( 164 find_prop(pci, "compatible")), XMITS_COMPATIBLE)) { 165 sprintf(card.notes, "%s", XMITS_COMPATIBLE); 166 /* 167 * With XMITS 3.X and PCI-X mode, the bus speed 168 * can be higher than 66MHZ. 169 */ 170 value = (int *)get_prop_val 171 (find_prop(pci, "module-revision#")); 172 if (value) { 173 pversion = (int *)value; 174 version = *pversion; 175 if (version >= 4) 176 board_bus_max_freq = PCIX_MAX_FREQ; 177 } 178 } else if (strstr((char *)get_prop_val( 179 find_prop(pci, "compatible")), SCHIZO_COMPATIBLE)) 180 sprintf(card.notes, "%s", SCHIZO_COMPATIBLE); 181 else 182 sprintf(card.notes, " "); 183 184 /* 185 * Get slot-names property from parent node and 186 * store the individual slot names in an array. 187 * This is more general than Starcat requires, but 188 * it is correct, according to the slot-names property. 189 */ 190 value = (char *)get_prop_val(find_prop(pci, "slot-names")); 191 if (value == NULL) { 192 /* 193 * No slot_names property. This could be an Xmits 194 * card, so check the child node for slot-names property 195 */ 196 value = (char *)get_prop_val( 197 find_prop(pci->child, "slot-names")); 198 } 199 200 if (value != NULL) { 201 /* Get the 4 byte bitmask and pointer to first name */ 202 slot_name_bits = *(int *)value; 203 if (slot_name_bits > 0) 204 slot_name_offset = slot_name_bits - 1; 205 slot_name = (char *)value + sizeof (int); 206 207 for (i = 0; i < MAX_SLOTS_PER_IO_BD; i++) { 208 if (! (slot_name_bits & (1 << i))) { 209 slot_name_arr[i] = (char *)NULL; 210 continue; 211 } 212 213 /* 214 * Save the name pointer into the array 215 * and advance it past the end of this 216 * slot name 217 */ 218 slot_name_arr[i] = slot_name; 219 slot_name += strlen(slot_name) + 1; 220 } 221 slot_name = (char *)NULL; 222 } 223 224 /* 225 * Search for Children of this node ie. Cards. 226 * Note: any of these cards can be a pci-bridge 227 * that itself has children. If we find a 228 * pci-bridge we need to handle it specially. 229 */ 230 card_node = pci->child; 231 while (card_node != NULL) { 232 pci_bridge = 0; 233 234 /* If it doesn't have a name, skip it */ 235 name = (char *)get_prop_val( 236 find_prop(card_node, "name")); 237 if (name == NULL) { 238 card_node = card_node->sibling; 239 continue; 240 } 241 242 /* 243 * get dev# and func# for this card from the 244 * 'reg' property. 245 */ 246 int_val = (int *)get_prop_val( 247 find_prop(card_node, "reg")); 248 if (int_val != NULL) { 249 card.dev_no = (((*int_val) & 0xF800) >> 11); 250 card.func_no = (((*int_val) & 0x700) >> 8); 251 } else { 252 card.dev_no = -1; 253 card.func_no = -1; 254 } 255 256 /* 257 * If this is a pci-bridge, then store it's dev# 258 * as its children nodes need this to get their slot#. 259 * We set the pci_bridge flag so that we know we are 260 * looking at a pci-bridge node. This flag gets reset 261 * every time we enter this while loop. 262 */ 263 264 /* 265 * Check for a PCI-PCI Bridge for PCI and cPCI 266 * IO Boards using the name and type properties. 267 */ 268 type = (char *)get_prop_val( 269 find_prop(card_node, "device_type")); 270 if ((type != NULL) && 271 (strncmp(name, "pci", 3) == 0) && 272 (strcmp(type, "pci") == 0)) { 273 pci_bridge_dev_no = card.dev_no; 274 pci_bridge_node = card_node; 275 pci_bridge = TRUE; 276 } 277 278 /* 279 * Get slot-names property from slot_names_arr. 280 * If we are the child of a pci_bridge we use the 281 * dev# of the pci_bridge as an index to get 282 * the slot number. We know that we are a child of 283 * a pci-bridge if our parent is the same as the last 284 * pci_bridge node found above. 285 */ 286 if (card.dev_no != -1) { 287 /* 288 * We compare this card's parent node with the 289 * pci_bridge_node to see if it's a child. 290 */ 291 if (card_node->parent == pci_bridge_node) { 292 /* use dev_no of pci_bridge */ 293 child_dev_no = pci_bridge_dev_no - 1; 294 } else { 295 /* use card's own dev_no */ 296 child_dev_no = card.dev_no - 1; 297 } 298 299 if (child_dev_no < MAX_SLOTS_PER_IO_BD && 300 child_dev_no >= 0 && 301 slot_name_arr 302 [child_dev_no + slot_name_offset] != NULL) { 303 304 slot_name = slot_name_arr[ 305 child_dev_no + slot_name_offset]; 306 } else 307 slot_name = (char *)NULL; 308 309 if (slot_name != NULL && slot_name[0] != '\0') { 310 (void) sprintf(card.slot_str, "%s", 311 slot_name); 312 } else { 313 (void) sprintf(card.slot_str, "-"); 314 } 315 } else { 316 (void) sprintf(card.slot_str, "%c", '-'); 317 } 318 319 /* 320 * Get the portid of the schizo that this card 321 * lives under. 322 */ 323 portid = -1; 324 value = get_prop_val(find_prop(pci, "portid")); 325 if (value != NULL) { 326 portid = *(int *)value; 327 } 328 card.schizo_portid = portid; 329 330 #ifdef DEBUG 331 (void) sprintf(card.notes, "%s portid [%d]" 332 " dev_no [%d] slot_name[%s] name_bits[%#x]", 333 card.notes, portid, card.dev_no, 334 ((slot_name != NULL) ? slot_name : "NULL"), 335 slot_name_bits); 336 #endif /* DEBUG */ 337 338 /* 339 * Find out whether this is PCI bus A or B 340 * using the 'reg' property. 341 */ 342 int_val = (int *)get_prop_val 343 (find_prop(pci, "reg")); 344 345 if (int_val != NULL) { 346 int_val ++; /* skip over first integer */ 347 pci_bus = ((*int_val) & 0x7f0000); 348 if (pci_bus == 0x600000) 349 card.pci_bus = 'A'; 350 else if (pci_bus == 0x700000) 351 card.pci_bus = 'B'; 352 else 353 card.pci_bus = '-'; 354 } else { 355 card.pci_bus = '-'; 356 } 357 358 359 /* 360 * Check for failed status. 361 */ 362 if (node_failed(card_node)) 363 strcpy(card.status, "fail"); 364 else 365 strcpy(card.status, "ok"); 366 367 /* Get the model of this card */ 368 value = get_prop_val(find_prop(card_node, "model")); 369 if (value == NULL) 370 card.model[0] = '\0'; 371 else { 372 (void) sprintf(card.model, "%s", (char *)value); 373 /* 374 * If we wish to exclude onboard devices 375 * (such as SBBC) then this is the place 376 * and here is how to do it: 377 * 378 * if (strcmp(card.model, "SUNW,sbbc") == 0) { 379 * card_node = card_node->sibling; 380 * continue; 381 * } 382 */ 383 } 384 385 /* 386 * The card may have a "clock-frequency" but we 387 * are not interested in that. Instead we get the 388 * "clock-frequency" of the PCI Bus that the card 389 * resides on. PCI-A can operate at 33Mhz or 66Mhz 390 * depending on what card is plugged into the Bus. 391 * PCI-B always operates at 33Mhz. 392 * 393 */ 394 int_val = get_prop_val(find_prop(pci, 395 "clock-frequency")); 396 if (int_val != NULL) { 397 card.freq = HZ_TO_MHZ(*int_val); 398 } else { 399 card.freq = -1; 400 } 401 402 /* 403 * Figure out how we want to display the name 404 */ 405 value = get_prop_val(find_prop(card_node, 406 "compatible")); 407 if (value != NULL) { 408 /* use 'name'-'compatible' */ 409 (void) sprintf(buf, "%s-%s", name, 410 (char *)value); 411 } else { 412 /* just use 'name' */ 413 (void) sprintf(buf, "%s", name); 414 } 415 name = buf; 416 417 /* 418 * If this node has children, add the device_type 419 * of the child to the name value of this card. 420 */ 421 child_name = (char *)get_node_name(card_node->child); 422 if ((card_node->child != NULL) && 423 (child_name != NULL)) { 424 value = get_prop_val(find_prop(card_node->child, 425 "device_type")); 426 if (value != NULL) { 427 /* add device_type of child to name */ 428 (void) sprintf(card.name, "%s/%s (%s)", 429 name, child_name, 430 (char *)value); 431 } else { 432 /* just add child's name */ 433 (void) sprintf(card.name, "%s/%s", 434 name, child_name); 435 } 436 } else { 437 /* childless, just the card's name */ 438 (void) sprintf(card.name, "%s", (char *)name); 439 } 440 441 /* 442 * If this is a pci-bridge, then add the word 443 * 'pci-bridge' to its model. 444 */ 445 if (pci_bridge) { 446 if (card.model[0] == '\0') 447 (void) sprintf(card.model, 448 "%s", "pci-bridge"); 449 else 450 (void) strcat(card.model, 451 "/pci-bridge"); 452 } 453 454 /* insert this card in the list to be displayed later */ 455 card_list = insert_io_card(card_list, &card); 456 457 /* 458 * If we are dealing with a pci-bridge, we need to move 459 * down to the children of this bridge, if there are 460 * any, otherwise its siblings. 461 * 462 * If not a bridge, we are either dealing with a regular 463 * card (in which case we move onto the sibling of this 464 * card) or we are dealing with a child of a pci-bridge 465 * (in which case we move onto the child's siblings or 466 * if there are no more siblings for this child, we 467 * move onto the parent's siblings). I hope you're 468 * getting all this, there will be an exam later. 469 */ 470 if (pci_bridge) { 471 if (card_node->child != NULL) 472 card_node = card_node->child; 473 else 474 card_node = card_node->sibling; 475 } else { 476 /* 477 * If our parent is a pci-bridge but there 478 * are no more of its children to process we 479 * move back up to our parent's sibling, 480 * otherwise we move onto our own sibling. 481 */ 482 if ((card_node->parent == pci_bridge_node) && 483 (card_node->sibling == NULL)) 484 card_node = 485 pci_bridge_node->sibling; 486 else 487 card_node = card_node->sibling; 488 } 489 490 } /* end while (card_node ...) loop */ 491 492 } /* end for (pci ...) loop */ 493 494 display_io_cards(card_list); 495 free_io_cards(card_list); 496 } 497 498 /* 499 * display_ffb 500 * 501 * There are no FFB's on a Starcat, however in the generic library, 502 * the display_ffb() function is implemented so we have to define an 503 * empty function here. 504 */ 505 /*ARGSUSED0*/ 506 void 507 display_ffb(Board_node *board, int table) 508 { 509 } 510 511 /* 512 * add_node 513 * 514 * This function adds a board node to the board structure where that 515 * that node's physical component lives. 516 */ 517 void 518 add_node(Sys_tree *root, Prom_node *pnode) 519 { 520 int portid = -1; 521 int nodeid = -1; 522 void *value; 523 Board_node *bnode; 524 Prom_node *p; 525 char *type; 526 527 /* Get the board number of this board from the portid prop */ 528 if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) { 529 if (type = get_node_type(pnode)) 530 if (strcmp(type, "cpu") == 0) 531 value = get_prop_val(find_prop(pnode->parent, 532 "portid")); 533 } 534 if (value != NULL) { 535 portid = *(int *)value; 536 nodeid = PORTID_TO_EXPANDER(portid); 537 } 538 539 /* find the board node with the same board number */ 540 if ((bnode = find_board(root, portid)) == NULL) { 541 bnode = insert_board(root, portid); 542 bnode->board_type = UNKNOWN_BOARD; 543 bnode->node_id = nodeid; 544 } 545 546 /* now attach this prom node to the board list */ 547 /* Insert this node at the end of the list */ 548 pnode->sibling = NULL; 549 if (bnode->nodes == NULL) 550 bnode->nodes = pnode; 551 else { 552 p = bnode->nodes; 553 while (p->sibling != NULL) 554 p = p->sibling; 555 p->sibling = pnode; 556 } 557 } 558 559 560 561 /* 562 * Print out all the io cards in the list. Also print the column 563 * headers if told to do so. 564 */ 565 void 566 display_io_cards(struct io_card *list) 567 { 568 char *hdrfmt = "%-10.10s %-4.4s %-4.4s %-4.4s %-4.4s %-4.4s" 569 " %-4.4s %-5.5s %-32.32s %-22.22s" 570 #ifdef DEBUG 571 " %-22.22s" 572 #endif /* DEBUG */ 573 "\n"; 574 575 static int banner = FALSE; /* Have we printed the column headings? */ 576 struct io_card *p; 577 578 if (list == NULL) 579 return; 580 581 (void) textdomain(TEXT_DOMAIN); 582 583 if (banner == FALSE) { 584 log_printf(hdrfmt, 585 "", "", "", "", 586 gettext("Bus"), 587 gettext("Max"), 588 "", "", "", "", 589 #ifdef DEBUG 590 "", 591 #endif /* DEBUG */ 592 0); 593 594 log_printf(hdrfmt, 595 "", 596 gettext("IO"), 597 gettext("Port"), 598 gettext("Bus"), 599 gettext("Freq"), 600 gettext("Bus"), 601 gettext("Dev,"), 602 "", "", "", 603 #ifdef DEBUG 604 "", 605 #endif /* DEBUG */ 606 0); 607 608 log_printf(hdrfmt, 609 gettext("Slot ID"), 610 gettext("Type"), 611 gettext(" ID"), 612 gettext("Side"), 613 gettext("MHz"), 614 gettext("Freq"), 615 gettext("Func"), 616 gettext("State"), 617 gettext("Name"), 618 gettext("Model"), 619 #ifdef DEBUG 620 gettext("Notes"), 621 #endif /* DEBUG */ 622 0); 623 624 log_printf(hdrfmt, 625 "----------", "----", "----", "----", "----", "----", 626 "----", "-----", "--------------------------------", 627 "----------------------", 628 #ifdef DEBUG 629 "----------------------", 630 #endif /* DEBUG */ 631 0); 632 633 banner = TRUE; 634 } 635 636 for (p = list; p != NULL; p = p -> next) { 637 638 display_io_slot_info(p); 639 640 display_io_max_bus_speed(p); 641 642 log_printf("\n", 0); 643 } 644 } 645 646 647 static void 648 display_io_slot_info(struct io_card *p) 649 { 650 /* 651 * Onboard devices are distinguished by Slot IDs that 652 * indicate only the I/O board. Plug-in cards indicate 653 * their leaf and Schizo. 654 */ 655 656 if (p->slot_str[0] == '-') { 657 log_printf("/%-2s%02d ", 658 SC_BOARD_TYPE(p->board), 659 PORTID_TO_EXPANDER(p->board), 0); 660 } else { 661 char c; 662 if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) { 663 log_printf("/%-2s%02d/%s ", 664 SC_BOARD_TYPE(p->board), 665 PORTID_TO_EXPANDER(p->board), 666 p->slot_str, 0); 667 } else { 668 if (p->pci_bus == 'A') 669 c = '3'; 670 else if (p->pci_bus == 'B') { 671 c = '5'; 672 } else 673 c = '-'; 674 log_printf("/%-2s%02d/C%cV%1d ", 675 SC_BOARD_TYPE(p->board), 676 PORTID_TO_EXPANDER(p->board), c, 677 PORTID_TO_INSTANCE(p->schizo_portid), 678 0); 679 } 680 } 681 log_printf("%-4.4s ", gettext(p->bus_type), 0); 682 log_printf("%3d ", p->schizo_portid, 0); 683 log_printf(" %c ", p->pci_bus, 0); 684 log_printf(" %3d ", p->freq, 0); 685 } 686 687 #define BUS_SPEED_PRINT(speed) log_printf(" %d ", speed, 0) 688 689 static void 690 display_io_max_bus_speed(struct io_card *p) 691 { 692 int speed = board_bus_max_freq; 693 694 switch (p->pci_bus) { 695 case 'A': 696 BUS_SPEED_PRINT(speed); 697 break; 698 case 'B': 699 if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) { 700 if (PORTID_TO_INSTANCE(p->schizo_portid) == 0) 701 BUS_SPEED_PRINT(33); 702 else 703 BUS_SPEED_PRINT(speed); 704 } else 705 BUS_SPEED_PRINT(33); 706 break; 707 default: 708 log_printf(" - ", 0); 709 break; 710 } 711 712 log_printf("%-1d,%-1d ", p->dev_no, p->func_no, 0); 713 log_printf("%-5.5s ", gettext(p->status), 0); 714 log_printf("%-32.32s%c ", p->name, 715 ((strlen(p->name) > 32) ? '+' : ' '), 0); 716 log_printf("%-22.22s%c", p->model, 717 ((strlen(p->model) > 22) ? '+' : ' '), 0); 718 #ifdef DEBUG 719 log_printf(" %s", p->notes, 0); 720 #endif /* DEBUG */ 721 } 722 723 void 724 display_cpu_devices(Sys_tree *tree) 725 { 726 Board_node *bnode; 727 char *hdrfmt = "%-8.8s %-7.7s %-4.4s %-4.4s %-7.7s %-4.4s\n"; 728 729 (void) textdomain(TEXT_DOMAIN); 730 731 /* 732 * Display the table header for CPUs . Then display the CPU 733 * frequency, cache size, and processor revision of all cpus. 734 */ 735 log_printf("\n", 0); 736 log_printf("=========================", 0); 737 log_printf(gettext(" CPUs "), 0); 738 log_printf("=========================", 0); 739 log_printf("\n\n", 0); 740 741 log_printf(hdrfmt, 742 "", 743 gettext("CPU "), 744 gettext("Run"), 745 gettext(" E$"), 746 gettext(" CPU"), 747 gettext("CPU"), 0); 748 749 log_printf(hdrfmt, 750 gettext("Slot ID"), 751 gettext("ID "), 752 gettext("MHz"), 753 gettext(" MB"), 754 gettext("Impl."), 755 gettext("Mask"), 0); 756 757 log_printf(hdrfmt, 758 "--------", "-------", "----", "----", "-------", "----", 0); 759 760 /* Now display all of the cpus on each board */ 761 bnode = tree->bd_list; 762 while (bnode != NULL) { 763 display_cpus(bnode); 764 bnode = bnode->next; 765 } 766 767 log_printf("\n", 0); 768 } 769 770 /* 771 * Display the CPUs present on this board. 772 */ 773 void 774 display_cpus(Board_node *board) 775 { 776 Prom_node *cpu; 777 uint_t freq; /* CPU clock frequency */ 778 int ecache_size; /* External cache size */ 779 int *impl; 780 int *mask; 781 int decoded_mask; 782 int *cpuid; 783 int *coreid; 784 int cpuid_prev = -1; 785 int ecache_size_prev = 0; 786 787 (void) textdomain(TEXT_DOMAIN); 788 /* 789 * display the CPUs' operating frequency, cache size, impl. field 790 * and mask revision. 791 */ 792 for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL; 793 cpu = dev_next_type(cpu, "cpu")) { 794 795 freq = HZ_TO_MHZ(get_cpu_freq(cpu)); 796 ecache_size = get_ecache_size(cpu); 797 impl = (int *)get_prop_val(find_prop(cpu, "implementation#")); 798 mask = (int *)get_prop_val(find_prop(cpu, "mask#")); 799 cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid")); 800 if (cpuid == NULL) 801 cpuid = &board->board_num; 802 803 /* Do not display a failed CPU node */ 804 if ((freq == 0) || (impl == 0) || (node_failed(cpu))) 805 continue; 806 807 if (CPU_IMPL_IS_CMP(*impl)) { 808 coreid = (int *)get_prop_val(find_prop(cpu, 809 "reg")); 810 if (coreid == NULL) { 811 continue; 812 } 813 814 /* 815 * The assumption is made that 2 cores will always be 816 * listed together in the device tree. If either core 817 * is "bad" then the FRU will not be listed. 818 */ 819 if (cpuid_prev == -1) { 820 cpuid_prev = *cpuid; 821 ecache_size_prev = ecache_size; 822 continue; 823 } else { 824 /* 825 * Jaguar has a split E$, so the size for both 826 * cores must be added together to get the total 827 * size for the entire chip. 828 * 829 * Panther E$ (L3) is logically shared, so the 830 * total size is equal to the core size. 831 */ 832 if (IS_JAGUAR(*impl)) { 833 ecache_size += ecache_size_prev; 834 } 835 836 ecache_size_prev = 0; 837 } 838 } 839 840 /* 841 * Print out cpu data. 842 * 843 * Slot ID 844 */ 845 log_printf("/%-2s%02d/P%1d ", 846 SC_BOARD_TYPE(*cpuid), 847 PORTID_TO_EXPANDER(*cpuid), 848 PORTID_TO_INSTANCE(*cpuid), 0); 849 850 /* CPU ID */ 851 if (CPU_IMPL_IS_CMP(*impl)) { 852 log_printf("%3d,%3d ", cpuid_prev, 853 *cpuid, 0); 854 cpuid_prev = -1; 855 } else 856 log_printf("%3d ", *cpuid, 0); 857 858 /* Running frequency */ 859 log_printf("%4u ", freq, 0); 860 861 /* Ecache size */ 862 if (ecache_size == 0) 863 log_printf("%-4.4s ", gettext("N/A"), 0); 864 else 865 log_printf("%4.1f ", 866 (float)ecache_size / (float)(1<<20), 867 0); 868 869 /* Implementation */ 870 switch (*impl) { 871 case CHEETAH_IMPL: 872 log_printf("%-7.7s ", 873 gettext("US-III"), 0); 874 break; 875 case CHEETAH_PLUS_IMPL: 876 log_printf("%-7.7s ", 877 gettext("US-III+"), 0); 878 break; 879 case JAGUAR_IMPL: 880 log_printf("%-7.7s ", 881 gettext("US-IV"), 0); 882 break; 883 case PANTHER_IMPL: 884 log_printf("%-7.7s ", 885 gettext("US-IV+"), 0); 886 break; 887 default: 888 log_printf("%-7x ", *impl, 0); 889 break; 890 } 891 892 /* CPU Mask */ 893 if (mask == NULL) { 894 log_printf("%-4.4s", gettext("N/A"), 0); 895 } else { 896 if (IS_CHEETAH(*impl)) 897 decoded_mask = REMAP_CHEETAH_MASK(*mask); 898 else 899 decoded_mask = *mask; 900 901 log_printf("%d.%d", 902 (decoded_mask >> 4) & 0xf, 903 decoded_mask & 0xf, 0); 904 } 905 906 log_printf("\n", 0); 907 } 908 } 909 910 911 /*ARGSUSED1*/ 912 void 913 display_memoryconf(Sys_tree *tree, struct grp_info *grps) 914 { 915 Board_node *bnode = tree->bd_list; 916 char *hdrfmt = "\n%-11.11s %-4.4s %-7.7s %-7.7s %-8.8s %-6.6s" 917 " %-10.10s %-10.10s"; 918 919 (void) textdomain(TEXT_DOMAIN); 920 921 log_printf("=========================", 0); 922 log_printf(gettext(" Memory Configuration "), 0); 923 log_printf("=========================", 0); 924 log_printf("\n", 0); 925 926 log_printf(hdrfmt, 927 "", "", 928 gettext("Logical"), 929 gettext("Logical"), 930 gettext("Logical"), 931 "", "", "", 0); 932 933 log_printf(hdrfmt, 934 "", 935 gettext("Port"), 936 gettext("Bank"), 937 gettext("Bank"), 938 gettext("Bank"), 939 gettext(" DIMM"), 940 gettext("Interleave"), 941 gettext("Interleave"), 0); 942 943 log_printf(hdrfmt, 944 gettext("Slot ID"), 945 gettext(" ID"), 946 gettext("Number"), 947 gettext("Size"), 948 gettext("Status"), 949 gettext(" Size"), 950 gettext("Factor"), 951 gettext("Segment"), 0); 952 953 log_printf(hdrfmt, 954 "-----------", "----", "-------", "-------", "--------", 955 "------", "----------", "----------", 0); 956 957 while (bnode != NULL) { 958 if (get_us3_mem_regs(bnode)) { 959 log_printf( 960 gettext( 961 "\nFailed to get memory information.\n"), 962 0); 963 return; 964 } 965 bnode = bnode->next; 966 } 967 968 /* Display what we have found */ 969 display_us3_banks(); 970 } 971 972 973 /* 974 * This function provides Starcat's formatting of the memory config 975 * information that get_us3_mem_regs() and display_us3_banks() code has 976 * gathered. It overrides the generic print_us3_memory_line() code 977 * which prints an error message. 978 */ 979 void 980 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size, 981 char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id) 982 { 983 (void) textdomain(TEXT_DOMAIN); 984 985 /* Slot ID */ 986 log_printf("\n/%-2s%02d/P%1d/B%1d ", 987 SC_BOARD_TYPE(portid), PORTID_TO_EXPANDER(portid), 988 PORTID_TO_INSTANCE(portid), (bank_id & 0x1), 0); 989 990 /* Port ID */ 991 log_printf("%3d ", portid, 0); 992 993 /* Logical Bank Number */ 994 log_printf(" %1d ", (bank_id & 0x3), 0); 995 996 /* Logical Bank Size */ 997 log_printf("%4lldMB ", bank_size, 0); 998 999 /* Logical Bank Status */ 1000 log_printf("%-8.8s ", gettext(bank_status), 0); 1001 1002 /* DIMM Size */ 1003 log_printf("%4lldMB ", dimm_size, 0); 1004 1005 /* Interleave Factor */ 1006 log_printf(" %2d-%-3.3s ", intlv, gettext("way"), 0); 1007 1008 /* Interleave Segment */ 1009 log_printf(" %3d", seg_id, 0); 1010 } 1011 1012 /*ARGSUSED2*/ 1013 void 1014 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree, 1015 struct system_kstat_data *kstats) 1016 { 1017 if (flag) { 1018 /* 1019 * display time of latest powerfail. Not all systems 1020 * have this capability. For those that do not, this 1021 * is just a no-op. 1022 */ 1023 disp_powerfail(root); 1024 1025 (void) textdomain(TEXT_DOMAIN); 1026 1027 /* Print the header */ 1028 log_printf("\n", 0); 1029 log_printf("=========================", 0); 1030 log_printf(gettext(" Diagnostic Information "), 0); 1031 log_printf("=========================", 0); 1032 log_printf("\n\n", 0); 1033 log_printf(gettext("For diagnostic information,"), 0); 1034 log_printf("\n", 0); 1035 log_printf(gettext( 1036 "see /var/opt/SUNWSMS/adm/[A-R]/messages on the SC."), 1037 0); 1038 log_printf("\n", 0); 1039 1040 /* Print the PROM revisions here */ 1041 starcat_disp_hw_revisions(root); 1042 } 1043 } 1044 1045 /* 1046 * local functions - functions that are only needed inside this library 1047 */ 1048 1049 static void 1050 starcat_disp_hw_revisions(Prom_node *root) 1051 { 1052 Prom_node *pnode; 1053 char *version; 1054 1055 (void) textdomain(TEXT_DOMAIN); 1056 1057 /* Print the header */ 1058 log_printf("\n", 0); 1059 log_printf("=========================", 0); 1060 log_printf(gettext(" Hardware Revisions "), 0); 1061 log_printf("=========================", 0); 1062 log_printf("\n\n", 0); 1063 1064 /* Display Prom revision header */ 1065 log_printf(gettext("OpenBoot firmware revision:"), 0); 1066 log_printf("\n---------------------------\n", 0); 1067 1068 /* 1069 * Display OBP version info 1070 */ 1071 pnode = dev_find_node(root, "openprom"); 1072 if (pnode != NULL) { 1073 version = (char *)get_prop_val(find_prop(pnode, "version")); 1074 log_printf("%s\n\n", version, 0); 1075 } 1076 } 1077 1078 /* 1079 * We call do_devinfo() in order to use the libdevinfo device tree 1080 * instead of OBP's device tree. 1081 */ 1082 int 1083 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag) 1084 { 1085 1086 return (do_devinfo(syserrlog, pgname, log_flag, prt_flag)); 1087 1088 } 1089 1090 /* 1091 * return the property value for the Prop 1092 * passed in. (When using libdevinfo) 1093 */ 1094 void * 1095 get_prop_val(Prop *prop) 1096 { 1097 if (prop == NULL) 1098 return (NULL); 1099 1100 return ((void *)(prop->value.val_ptr)); 1101 } 1102 1103 /* 1104 * Search a Prom node and retrieve the property with the correct 1105 * name. (When using libdevinfo) 1106 */ 1107 Prop * 1108 find_prop(Prom_node *pnode, char *name) 1109 { 1110 Prop *prop; 1111 1112 if (pnode == NULL) 1113 return (NULL); 1114 1115 for (prop = pnode->props; prop != NULL; prop = prop->next) { 1116 if (prop->name.val_ptr != NULL && 1117 strcmp((char *)(prop->name.val_ptr), name) == 0) 1118 break; 1119 } 1120 1121 return (prop); 1122 } 1123 1124 /* 1125 * This function searches through the properties of the node passed in 1126 * and returns a pointer to the value of the name property. 1127 * (When using libdevinfo) 1128 */ 1129 char * 1130 get_node_name(Prom_node *pnode) 1131 { 1132 Prop *prop; 1133 1134 if (pnode == NULL) { 1135 return (NULL); 1136 } 1137 1138 prop = pnode->props; 1139 while (prop != NULL) { 1140 if (strcmp("name", (char *)prop->name.val_ptr) == 0) 1141 return (prop->value.val_ptr); 1142 prop = prop->next; 1143 } 1144 return (NULL); 1145 } 1146 1147 /* 1148 * This function searches through the properties of the node passed in 1149 * and returns a pointer to the value of the device_type property. 1150 * (When using libdevinfo) 1151 */ 1152 char * 1153 get_node_type(Prom_node *pnode) 1154 { 1155 Prop *prop; 1156 1157 if (pnode == NULL) { 1158 return (NULL); 1159 } 1160 1161 prop = pnode->props; 1162 while (prop != NULL) { 1163 if (strcmp("device_type", (char *)prop->name.val_ptr) == 0) 1164 return (prop->value.val_ptr); 1165 prop = prop->next; 1166 } 1167 return (NULL); 1168 } 1169