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