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 (c) 1999-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <ctype.h> 33 #include <string.h> 34 #include <kvm.h> 35 #include <varargs.h> 36 #include <errno.h> 37 #include <time.h> 38 #include <dirent.h> 39 #include <fcntl.h> 40 #include <sys/param.h> 41 #include <sys/stat.h> 42 #include <sys/types.h> 43 #include <sys/utsname.h> 44 #include <sys/openpromio.h> 45 #include <sys/systeminfo.h> 46 #include <kstat.h> 47 #include <libintl.h> 48 #include <syslog.h> 49 #include <sys/dkio.h> 50 #include "pdevinfo.h" 51 #include "display.h" 52 #include "pdevinfo_sun4u.h" 53 #include "display_sun4u.h" 54 #include "libprtdiag.h" 55 56 #if !defined(TEXT_DOMAIN) 57 #define TEXT_DOMAIN "SYS_TEST" 58 #endif 59 60 Prom_node * 61 find_pci_bus(Prom_node *node, int id, int bus) 62 { 63 Prom_node *pnode; 64 65 /* find the first pci node */ 66 pnode = dev_find_node(node, "pci"); 67 68 while (pnode != NULL) { 69 int tmp_id; 70 int tmp_bus; 71 72 tmp_id = get_id(pnode); 73 tmp_bus = get_pci_bus(pnode); 74 75 if ((tmp_id == id) && 76 (tmp_bus == bus)) { 77 break; 78 } 79 80 pnode = dev_next_node(pnode, "pci"); 81 } 82 return (pnode); 83 } 84 85 /* 86 * get_pci_bus 87 * 88 * Determines the PCI bus, either A (0) or B (1). If the function cannot 89 * find the bus-ranges property, it returns -1. 90 */ 91 int 92 get_pci_bus(Prom_node *pnode) 93 { 94 int *value; 95 96 /* look up the bus-range property */ 97 if ((value = (int *)get_prop_val(find_prop(pnode, "bus-range"))) == 98 NULL) { 99 return (-1); 100 } 101 102 if (*value == 0) { 103 return (1); /* B bus has a bus-range value = 0 */ 104 } else { 105 return (0); 106 } 107 } 108 109 110 111 /* 112 * Find the PCI device number of this PCI device. If no device number can 113 * be determined, then return -1. 114 */ 115 int 116 get_pci_device(Prom_node *pnode) 117 { 118 void *value; 119 120 if ((value = get_prop_val(find_prop(pnode, "assigned-addresses"))) != 121 NULL) { 122 return (PCI_DEVICE(*(int *)value)); 123 } else { 124 return (-1); 125 } 126 } 127 128 /* 129 * Find the PCI device number of this PCI device. If no device number can 130 * be determined, then return -1. 131 */ 132 int 133 get_pci_to_pci_device(Prom_node *pnode) 134 { 135 void *value; 136 137 if ((value = get_prop_val(find_prop(pnode, "reg"))) != 138 NULL) { 139 return (PCI_DEVICE(*(int *)value)); 140 } else { 141 return (-1); 142 } 143 } 144 145 /* 146 * free_io_cards 147 * Frees the memory allocated for an io card list. 148 */ 149 void 150 free_io_cards(struct io_card *card_list) 151 { 152 /* Free the list */ 153 if (card_list != NULL) { 154 struct io_card *p, *q; 155 156 for (p = card_list, q = NULL; p != NULL; p = q) { 157 q = p->next; 158 free(p); 159 } 160 } 161 } 162 163 164 /* 165 * insert_io_card 166 * Inserts an io_card structure into the list. The list is maintained 167 * in order based on board number and slot number. Also, the storage 168 * for the "card" argument is assumed to be handled by the caller, 169 * so we won't touch it. 170 */ 171 struct io_card * 172 insert_io_card(struct io_card *list, struct io_card *card) 173 { 174 struct io_card *newcard; 175 struct io_card *p, *q; 176 177 if (card == NULL) 178 return (list); 179 180 /* Copy the card to be added into new storage */ 181 newcard = (struct io_card *)malloc(sizeof (struct io_card)); 182 if (newcard == NULL) { 183 perror("malloc"); 184 exit(2); 185 } 186 (void) memcpy(newcard, card, sizeof (struct io_card)); 187 newcard->next = NULL; 188 189 if (list == NULL) 190 return (newcard); 191 192 /* Find the proper place in the list for the new card */ 193 for (p = list, q = NULL; p != NULL; q = p, p = p->next) { 194 if (newcard->board < p->board) 195 break; 196 if ((newcard->board == p->board) && (newcard->slot < p->slot)) 197 break; 198 } 199 200 /* Insert the new card into the list */ 201 if (q == NULL) { 202 newcard->next = p; 203 return (newcard); 204 } else { 205 newcard->next = p; 206 q->next = newcard; 207 return (list); 208 } 209 } 210 211 212 char * 213 fmt_manf_id(unsigned int encoded_id, char *outbuf) 214 { 215 union manuf manuf; 216 217 /* 218 * Format the manufacturer's info. Note a small inconsistency we 219 * have to work around - Brooktree has it's part number in decimal, 220 * while Mitsubishi has it's part number in hex. 221 */ 222 manuf.encoded_id = encoded_id; 223 switch (manuf.fld.manf) { 224 case MANF_BROOKTREE: 225 (void) sprintf(outbuf, "%s %d, version %d", "Brooktree", 226 manuf.fld.partno, manuf.fld.version); 227 break; 228 229 case MANF_MITSUBISHI: 230 (void) sprintf(outbuf, "%s %x, version %d", "Mitsubishi", 231 manuf.fld.partno, manuf.fld.version); 232 break; 233 234 default: 235 (void) sprintf(outbuf, "JED code %d, Part num 0x%x, version %d", 236 manuf.fld.manf, manuf.fld.partno, manuf.fld.version); 237 } 238 return (outbuf); 239 } 240 241 242 /* 243 * Find the sbus slot number of this Sbus device. If no slot number can 244 * be determined, then return -1. 245 */ 246 int 247 get_sbus_slot(Prom_node *pnode) 248 { 249 void *value; 250 251 if ((value = get_prop_val(find_prop(pnode, "reg"))) != NULL) { 252 return (*(int *)value); 253 } else { 254 return (-1); 255 } 256 } 257 258 259 /* 260 * This routine is the generic link into displaying system IO 261 * configuration. It displays the table header, then displays 262 * all the SBus cards, then displays all fo the PCI IO cards. 263 */ 264 void 265 display_io_devices(Sys_tree *tree) 266 { 267 Board_node *bnode; 268 269 /* 270 * TRANSLATION_NOTE 271 * Following string is used as a table header. 272 * Please maintain the current alignment in 273 * translation. 274 */ 275 log_printf("\n", 0); 276 log_printf("=========================", 0); 277 log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0); 278 log_printf("=========================", 0); 279 log_printf("\n", 0); 280 log_printf("\n", 0); 281 bnode = tree->bd_list; 282 while (bnode != NULL) { 283 display_sbus(bnode); 284 display_pci(bnode); 285 display_ffb(bnode, 1); 286 bnode = bnode->next; 287 } 288 } 289 290 void 291 display_pci(Board_node *bnode) 292 { 293 #ifdef lint 294 bnode = bnode; 295 #endif 296 /* 297 * This function is intentionally empty 298 */ 299 } 300 301 302 /* 303 * Print out all the io cards in the list. Also print the column 304 * headers if told to do so. 305 */ 306 void 307 display_io_cards(struct io_card *list) 308 { 309 static int banner = 0; /* Have we printed the column headings? */ 310 struct io_card *p; 311 312 if (list == NULL) 313 return; 314 315 if (banner == 0) { 316 log_printf(" Bus Freq\n", 0); 317 log_printf("Brd Type MHz Slot " 318 "Name " 319 "Model", 0); 320 log_printf("\n", 0); 321 log_printf("--- ---- ---- ---------- " 322 "---------------------------- " 323 "--------------------", 0); 324 log_printf("\n", 0); 325 banner = 1; 326 } 327 328 for (p = list; p != NULL; p = p -> next) { 329 log_printf("%2d ", p->board, 0); 330 log_printf("%-4s ", p->bus_type, 0); 331 log_printf("%3d ", p->freq, 0); 332 /* 333 * We check to see if it's an int or 334 * a char string to display for slot. 335 */ 336 if (p->slot == PCI_SLOT_IS_STRING) 337 log_printf("%10s ", p->slot_str, 0); 338 else 339 log_printf("%10d ", p->slot, 0); 340 341 log_printf("%-28.28s", p->name, 0); 342 if (strlen(p->name) > 28) 343 log_printf("+ ", 0); 344 else 345 log_printf(" ", 0); 346 log_printf("%-19.19s", p->model, 0); 347 if (strlen(p->model) > 19) 348 log_printf("+", 0); 349 log_printf("\n", 0); 350 } 351 } 352 353 /* 354 * Display all FFBs on this board. It can either be in tabular format, 355 * or a more verbose format. 356 */ 357 void 358 display_ffb(Board_node *board, int table) 359 { 360 Prom_node *fb; 361 void *value; 362 struct io_card *card_list = NULL; 363 struct io_card card; 364 char *type; 365 char *label; 366 367 if (board == NULL) 368 return; 369 370 /* Fill in common information */ 371 card.display = 1; 372 card.board = board->board_num; 373 (void) sprintf(card.bus_type, BUS_TYPE); 374 card.freq = sys_clk; 375 376 for (fb = dev_find_node_by_type(board->nodes, "device_type", "display"); 377 fb != NULL; 378 fb = dev_next_node_by_type(fb, "device_type", "display")) { 379 value = get_prop_val(find_prop(fb, "name")); 380 if (value != NULL) { 381 if ((strcmp(FFB_NAME, value)) == 0) { 382 type = FFB_NAME; 383 label = "FFB"; 384 } else if ((strcmp(AFB_NAME, value)) == 0) { 385 type = AFB_NAME; 386 label = "AFB"; 387 } else 388 continue; 389 } else 390 continue; 391 if (table == 1) { 392 /* Print out in table format */ 393 394 /* XXX - Get the slot number (hack) */ 395 card.slot = get_id(fb); 396 397 /* Find out if it's single or double buffered */ 398 (void) sprintf(card.name, "%s", label); 399 value = get_prop_val(find_prop(fb, "board_type")); 400 if (value != NULL) 401 if ((*(int *)value) & FFB_B_BUFF) 402 (void) sprintf(card.name, 403 "%s, Double Buffered", label); 404 else 405 (void) sprintf(card.name, 406 "%s, Single Buffered", label); 407 408 /* 409 * Print model number only if board_type bit 2 410 * is not set and it is not SUNW,XXX-XXXX. 411 */ 412 card.model[0] = '\0'; 413 414 if (strcmp(type, AFB_NAME) == 0) { 415 if (((*(int *)value) & 0x4) != 0x4) { 416 value = get_prop_val(find_prop(fb, 417 "model")); 418 if ((value != NULL) && 419 (strcmp(value, 420 "SUNW,XXX-XXXX") != 0)) { 421 (void) sprintf(card.model, "%s", 422 (char *)value); 423 } 424 } 425 } else { 426 value = get_prop_val(find_prop(fb, "model")); 427 if (value != NULL) 428 (void) sprintf(card.model, "%s", 429 (char *)value); 430 } 431 432 card_list = insert_io_card(card_list, &card); 433 } else { 434 /* print in long format */ 435 char device[MAXSTRLEN]; 436 int fd = -1; 437 struct dirent *direntp; 438 DIR *dirp; 439 union strap_un strap; 440 struct ffb_sys_info fsi; 441 442 /* Find the device node using upa-portid/portid */ 443 value = get_prop_val(find_prop(fb, "upa-portid")); 444 if (value == NULL) 445 value = get_prop_val(find_prop(fb, "portid")); 446 447 if (value == NULL) 448 continue; 449 450 (void) sprintf(device, "%s@%x", type, 451 *(int *)value); 452 if ((dirp = opendir("/devices")) == NULL) 453 continue; 454 455 while ((direntp = readdir(dirp)) != NULL) { 456 if (strstr(direntp->d_name, device) != NULL) { 457 (void) sprintf(device, "/devices/%s", 458 direntp->d_name); 459 fd = open(device, O_RDWR, 0666); 460 break; 461 } 462 } 463 (void) closedir(dirp); 464 465 if (fd == -1) 466 continue; 467 468 if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0) 469 continue; 470 471 log_printf("%s Hardware Configuration:\n", label, 0); 472 log_printf("-----------------------------------\n", 0); 473 474 strap.ffb_strap_bits = fsi.ffb_strap_bits; 475 log_printf("\tBoard rev: %d\n", 476 (int)strap.fld.board_rev, 0); 477 log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0); 478 log_printf("\tDAC: %s\n", 479 fmt_manf_id(fsi.dac_version, device), 0); 480 log_printf("\t3DRAM: %s\n", 481 fmt_manf_id(fsi.fbram_version, device), 0); 482 log_printf("\n", 0); 483 } 484 485 } 486 display_io_cards(card_list); 487 free_io_cards(card_list); 488 } 489 490 491 /* 492 * Display all the SBus IO cards on this board. 493 */ 494 void 495 display_sbus(Board_node *board) 496 { 497 struct io_card card; 498 struct io_card *card_list = NULL; 499 int freq; 500 int card_num; 501 void *value; 502 Prom_node *sbus; 503 Prom_node *card_node; 504 505 if (board == NULL) 506 return; 507 508 for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL; 509 sbus = dev_next_node(sbus, SBUS_NAME)) { 510 511 /* Skip failed nodes for now */ 512 if (node_failed(sbus)) 513 continue; 514 515 /* Calculate SBus frequency in MHz */ 516 value = get_prop_val(find_prop(sbus, "clock-frequency")); 517 if (value != NULL) 518 freq = ((*(int *)value) + 500000) / 1000000; 519 else 520 freq = -1; 521 522 for (card_node = sbus->child; card_node != NULL; 523 card_node = card_node->sibling) { 524 char *model; 525 char *name; 526 char *child_name; 527 528 card_num = get_sbus_slot(card_node); 529 if (card_num == -1) 530 continue; 531 532 /* Fill in card information */ 533 card.display = 1; 534 card.freq = freq; 535 card.board = board->board_num; 536 (void) sprintf(card.bus_type, "SBus"); 537 card.slot = card_num; 538 card.status[0] = '\0'; 539 540 /* Try and get card status */ 541 value = get_prop_val(find_prop(card_node, "status")); 542 if (value != NULL) 543 (void) strncpy(card.status, (char *)value, 544 MAXSTRLEN); 545 546 /* XXX - For now, don't display failed cards */ 547 if (strstr(card.status, "fail") != NULL) 548 continue; 549 550 /* Now gather all of the node names for that card */ 551 model = (char *)get_prop_val(find_prop(card_node, 552 "model")); 553 name = get_node_name(card_node); 554 555 if (name == NULL) 556 continue; 557 558 card.name[0] = '\0'; 559 card.model[0] = '\0'; 560 561 /* Figure out how we want to display the name */ 562 child_name = get_node_name(card_node->child); 563 if ((card_node->child != NULL) && 564 (child_name != NULL)) { 565 value = get_prop_val(find_prop(card_node->child, 566 "device_type")); 567 if (value != NULL) 568 (void) sprintf(card.name, "%s/%s (%s)", 569 name, child_name, 570 (char *)value); 571 else 572 (void) sprintf(card.name, "%s/%s", name, 573 child_name); 574 } else { 575 (void) strncpy(card.name, name, MAXSTRLEN); 576 } 577 578 if (model != NULL) 579 (void) strncpy(card.model, model, MAXSTRLEN); 580 581 card_list = insert_io_card(card_list, &card); 582 } 583 } 584 585 /* We're all done gathering card info, now print it out */ 586 display_io_cards(card_list); 587 free_io_cards(card_list); 588 } 589 590 591 /* 592 * Get slot-names properties from parent node and 593 * store them in an array. 594 */ 595 int 596 populate_slot_name_arr(Prom_node *pci, int *slot_name_bits, 597 char **slot_name_arr, int num_slots) 598 { 599 int i, j, bit_mask; 600 char *value; 601 602 value = (char *)get_prop_val(find_prop(pci, "slot-names")); 603 D_PRINTF("\n populate_slot_name_arr: value = [0x%x]\n", value); 604 605 if (value != NULL) { 606 char *strings_arr[MAX_SLOTS_PER_IO_BD]; 607 bit_mask = *slot_name_bits = *(int *)value; 608 D_PRINTF("\nslot_names 1st integer = [0x%x]", *slot_name_bits); 609 610 /* array starts after first int */ 611 strings_arr[0] = value + sizeof (int); 612 613 /* 614 * break the array out into num_slots number of strings 615 */ 616 for (i = 1; i < num_slots; i++) { 617 strings_arr[i] = (char *)strings_arr[i - 1] 618 + strlen(strings_arr[i - 1]) + 1; 619 } 620 621 /* 622 * process array of slot_names to remove blanks 623 */ 624 j = 0; 625 for (i = 0; i < num_slots; i++) { 626 if ((bit_mask >> i) & 0x1) 627 slot_name_arr[i] = strings_arr[j++]; 628 else 629 slot_name_arr[i] = ""; 630 631 D_PRINTF("\nslot_name_arr[%d] = [%s]", i, 632 slot_name_arr[i]); 633 } 634 return (0); 635 } else { 636 D_PRINTF("\n populate_slot_name_arr: - psycho with no " 637 "slot-names\n"); 638 return (0); 639 } 640 } 641 642 int 643 get_card_frequency(Prom_node *pci) 644 { 645 char *value = get_prop_val(find_prop(pci, "clock-frequency")); 646 647 if (value == NULL) 648 return (-1); 649 else 650 return (int)(((*(int *)value) + 500000) / 1000000); 651 652 } 653 654 void 655 get_dev_func_num(Prom_node *card_node, int *dev_no, int *func_no) 656 { 657 658 void *value = get_prop_val(find_prop(card_node, "reg")); 659 660 if (value != NULL) { 661 int int_val = *(int *)value; 662 *dev_no = PCI_REG_TO_DEV(int_val); 663 *func_no = PCI_REG_TO_FUNC(int_val); 664 } else { 665 *dev_no = -1; 666 *func_no = -1; 667 } 668 } 669 670 void 671 get_pci_class_codes(Prom_node *card_node, int *class_code, int *subclass_code) 672 { 673 int class_code_reg = get_pci_class_code_reg(card_node); 674 675 *class_code = CLASS_REG_TO_CLASS(class_code_reg); 676 *subclass_code = CLASS_REG_TO_SUBCLASS(class_code_reg); 677 } 678 679 int 680 is_pci_bridge(Prom_node *card_node, char *name) 681 { 682 int class_code, subclass_code; 683 684 if (card_node == NULL) 685 return (FALSE); 686 687 get_pci_class_codes(card_node, &class_code, &subclass_code); 688 689 if ((strncmp(name, "pci", 3) == 0) && 690 (class_code == PCI_BRIDGE_CLASS) && 691 (subclass_code == PCI_PCI_BRIDGE_SUBCLASS)) 692 return (TRUE); 693 else 694 return (FALSE); 695 } 696 697 int 698 is_pci_bridge_other(Prom_node *card_node, char *name) 699 { 700 int class_code, subclass_code; 701 702 if (card_node == NULL) 703 return (FALSE); 704 705 get_pci_class_codes(card_node, &class_code, &subclass_code); 706 707 if ((strncmp(name, "pci", 3) == 0) && 708 (class_code == PCI_BRIDGE_CLASS) && 709 (subclass_code == PCI_SUBCLASS_OTHER)) 710 return (TRUE); 711 else 712 return (FALSE); 713 } 714 void 715 get_pci_card_model(Prom_node *card_node, char *model) 716 { 717 char *name = get_prop_val(find_prop(card_node, "name")); 718 char *value = get_prop_val(find_prop(card_node, "model")); 719 int pci_bridge = is_pci_bridge(card_node, name); 720 721 if (value == NULL) 722 model[0] = '\0'; 723 else 724 (void) sprintf(model, "%s", 725 (char *)value); 726 727 if (pci_bridge) { 728 if (strlen(model) == 0) 729 (void) sprintf(model, 730 "%s", "pci-bridge"); 731 else 732 (void) sprintf(model, 733 "%s/pci-bridge", model); 734 } 735 } 736 737 void 738 create_io_card_name(Prom_node *card_node, char *name, char *card_name) 739 { 740 char *value = get_prop_val(find_prop(card_node, "compatible")); 741 char *child_name; 742 char buf[MAXSTRLEN]; 743 744 if (value != NULL) { 745 (void) sprintf(buf, "%s-%s", name, 746 (char *)value); 747 } else 748 (void) sprintf(buf, "%s", name); 749 750 name = buf; 751 752 child_name = (char *)get_node_name(card_node->child); 753 754 if ((card_node->child != NULL) && 755 (child_name != NULL)) { 756 value = get_prop_val(find_prop(card_node->child, 757 "device_type")); 758 if (value != NULL) 759 (void) sprintf(card_name, "%s/%s (%s)", 760 name, child_name, 761 (char *)value); 762 else 763 (void) sprintf(card_name, "%s/%s", name, 764 child_name); 765 } else { 766 (void) sprintf(card_name, "%s", (char *)name); 767 } 768 } 769 770 771 /* 772 * Desktop display_psycho_pci 773 * Display all the psycho based PCI IO cards on this board. 774 */ 775 776 /* ARGSUSED */ 777 void 778 display_psycho_pci(Board_node *board) 779 { 780 struct io_card *card_list = NULL; 781 struct io_card card; 782 void *value; 783 784 Prom_node *pci, *card_node, *pci_bridge_node = NULL; 785 char *name; 786 int slot_name_bits, pci_bridge_dev_no, 787 class_code, subclass_code, 788 pci_pci_bridge; 789 char *slot_name_arr[MAX_SLOTS_PER_IO_BD]; 790 791 if (board == NULL) 792 return; 793 794 /* Initialize all the common information */ 795 card.display = 1; 796 card.board = board->board_num; 797 (void) sprintf(card.bus_type, "PCI"); 798 799 for (pci = dev_find_node_by_type(board->nodes, "model", "SUNW,psycho"); 800 pci != NULL; 801 pci = dev_next_node_by_type(pci, "model", "SUNW,psycho")) { 802 803 /* 804 * If we have reached a pci-to-pci bridge node, 805 * we are one level below the 'pci' nodes level 806 * in the device tree. To get back to that level, 807 * the search should continue with the sibling of 808 * the parent or else the remaining 'pci' cards 809 * will not show up in the output. 810 */ 811 if (find_prop(pci, "upa-portid") == NULL) { 812 if ((pci->parent->sibling != NULL) && 813 (strcmp(get_prop_val( 814 find_prop(pci->parent->sibling, 815 "name")), PCI_NAME) == 0)) 816 pci = pci->parent->sibling; 817 else { 818 pci = pci->parent->sibling; 819 continue; 820 } 821 } 822 823 D_PRINTF("\n\n------->Looking at device [%s][%d] - [%s]\n", 824 PCI_NAME, *((int *)get_prop_val(find_prop( 825 pci, "upa-portid"))), 826 get_prop_val(find_prop(pci, "model"))); 827 828 /* Skip all failed nodes for now */ 829 if (node_failed(pci)) 830 continue; 831 832 /* Fill in frequency */ 833 card.freq = get_card_frequency(pci); 834 835 /* 836 * Each PSYCHO device has a slot-names property that can be 837 * used to determine the slot-name string for each IO 838 * device under this node. We get this array now and use 839 * it later when looking at the children of this PSYCHO. 840 */ 841 if ((populate_slot_name_arr(pci, &slot_name_bits, 842 (char **)&slot_name_arr, MAX_SLOTS_PER_IO_BD)) != 0) 843 goto next_card; 844 845 /* Walk through the PSYCHO children */ 846 card_node = pci->child; 847 while (card_node != NULL) { 848 849 pci_pci_bridge = FALSE; 850 851 /* If it doesn't have a name, skip it */ 852 name = (char *)get_prop_val( 853 find_prop(card_node, "name")); 854 if (name == NULL) 855 goto next_card; 856 857 /* get dev# and func# for this card. */ 858 get_dev_func_num(card_node, &card.dev_no, 859 &card.func_no); 860 861 /* get class/subclass code for this card. */ 862 get_pci_class_codes(card_node, &class_code, 863 &subclass_code); 864 865 D_PRINTF("\nName [%s] - ", name); 866 D_PRINTF("device no [%d] - ", card.dev_no); 867 D_PRINTF("class_code [%d] subclass_code [%d] - ", 868 class_code, subclass_code); 869 870 /* 871 * Weed out PCI Bridge, subclass 'other' and 872 * ebus nodes. 873 */ 874 if (((class_code == PCI_BRIDGE_CLASS) && 875 (subclass_code == PCI_SUBCLASS_OTHER)) || 876 (strstr(name, "ebus"))) { 877 D_PRINTF("\nSkip ebus/class-other nodes [%s]", 878 name); 879 goto next_card; 880 } 881 882 /* 883 * If this is a PCI bridge, then we store it's dev_no 884 * so that it's children can use it for getting at 885 * the slot_name. 886 */ 887 if (is_pci_bridge(card_node, name)) { 888 pci_bridge_dev_no = card.dev_no; 889 pci_bridge_node = card_node; 890 pci_pci_bridge = TRUE; 891 D_PRINTF("\nPCI Bridge detected\n"); 892 } 893 894 /* 895 * If we are the child of a pci_bridge we use the 896 * dev# of the pci_bridge as an index to get 897 * the slot number. We know that we are a child of 898 * a pci-bridge if our parent is the same as the last 899 * pci_bridge node found above. 900 */ 901 if (card_node->parent == pci_bridge_node) 902 card.dev_no = pci_bridge_dev_no; 903 904 /* Get slot-names property from slot_names_arr. */ 905 get_slot_number_str(&card, (char **)slot_name_arr, 906 slot_name_bits); 907 908 if (slot_name_bits) 909 D_PRINTF("\nIO Card [%s] dev_no [%d] SlotStr " 910 "[%s] slot [%s]", name, card.dev_no, 911 slot_name_arr[card.dev_no], 912 card.slot_str); 913 914 /* XXX - Don't know how to get status for PCI cards */ 915 card.status[0] = '\0'; 916 917 /* Get the model of this card */ 918 get_pci_card_model(card_node, (char *)&card.model); 919 920 /* 921 * If we haven't figured out the frequency yet, 922 * try and get it from the card. 923 */ 924 value = get_prop_val(find_prop(pci, "clock-frequency")); 925 if (value != NULL && card.freq == -1) 926 card.freq = ((*(int *)value) + 500000) 927 / 1000000; 928 929 930 /* Figure out how we want to display the name */ 931 create_io_card_name(card_node, name, 932 (char *)&card.name); 933 934 if (card.freq != -1) 935 card_list = insert_io_card(card_list, &card); 936 937 next_card: 938 /* 939 * If we are done with the children of the pci bridge, 940 * we must continue with the remaining siblings of 941 * the pci-to-pci bridge - otherwise we move onto our 942 * own sibling. 943 */ 944 if (pci_pci_bridge) { 945 if (card_node->child != NULL) 946 card_node = card_node->child; 947 else 948 card_node = card_node->sibling; 949 } else { 950 if ((card_node->parent == pci_bridge_node) && 951 (card_node->sibling == NULL)) 952 card_node = pci_bridge_node->sibling; 953 else 954 card_node = card_node->sibling; 955 } 956 } /* end-while */ 957 } /* end-for */ 958 959 D_PRINTF("\n\n"); 960 961 display_io_cards(card_list); 962 free_io_cards(card_list); 963 } 964 965 void 966 get_slot_number_str(struct io_card *card, char **slot_name_arr, 967 int slot_name_bits) 968 { 969 if (card->dev_no != -1) { 970 char *slot; 971 /* 972 * slot_name_bits is a mask of the plug-in slots so if our 973 * dev_no does not appear in this mask we must be an 974 * on_board device so set the slot to 'On-Board' 975 */ 976 if (slot_name_bits & (1 << card->dev_no)) { 977 /* we are a plug-in card */ 978 slot = slot_name_arr[card->dev_no]; 979 if (strlen(slot) != 0) { 980 (void) sprintf(card->slot_str, "%s", 981 slot); 982 } else 983 (void) sprintf(card->slot_str, "-"); 984 } else { 985 /* this is an on-board dev. */ 986 sprintf(card->slot_str, "On-Board"); 987 } 988 989 } else { 990 (void) sprintf(card->slot_str, "%c", '-'); 991 } 992 993 /* Informs display_io_cards to print slot_str instead of slot */ 994 card->slot = PCI_SLOT_IS_STRING; 995 } 996 997 998 /* 999 * The output of a number of I/O cards are identical so we need to 1000 * differentiate between them. 1001 * 1002 * This function is called by the platform specific code and it decides 1003 * if the card needs further processing. 1004 * 1005 * It can be extended in the future if card types other than QLC have 1006 * the same problems. 1007 */ 1008 void 1009 distinguish_identical_io_cards(char *name, Prom_node *node, 1010 struct io_card *card) 1011 { 1012 if ((name == NULL) || (node == NULL)) 1013 return; 1014 1015 if (strcmp(name, "SUNW,qlc") == 0) 1016 decode_qlc_card_model_prop(node, card); 1017 } 1018 1019 1020 /* 1021 * The name/model properties for a number of the QLC FCAL PCI cards are 1022 * identical (*), so we need to distinguish them using the subsystem-id 1023 * and modify the model string to be more informative. 1024 * 1025 * (*) Currently the problem cards are: 1026 * Amber 1027 * Crystal+ 1028 */ 1029 void 1030 decode_qlc_card_model_prop(Prom_node *card_node, struct io_card *card) 1031 { 1032 void *value = NULL; 1033 1034 if (card_node == NULL) 1035 return; 1036 1037 value = get_prop_val(find_prop(card_node, "subsystem-id")); 1038 if (value != NULL) { 1039 int id = *(int *)value; 1040 1041 switch (id) { 1042 case AMBER_SUBSYSTEM_ID: 1043 (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s", 1044 AMBER_CARD_NAME); 1045 break; 1046 1047 case CRYSTAL_SUBSYSTEM_ID: 1048 (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s", 1049 CRYSTAL_CARD_NAME); 1050 break; 1051 1052 default: 1053 /* 1054 * If information has been saved into the model field 1055 * before this function was called we will keep it as 1056 * it probably will be more meaningful that the 1057 * subsystem-id, otherwise we save the subsystem-id in 1058 * the hope that it will distinguish the cards. 1059 */ 1060 if (strcmp(card->model, "") == 0) { 1061 (void) snprintf(card->model, MAX_QLC_MODEL_LEN, 1062 "0x%x", id); 1063 } 1064 break; 1065 } 1066 } 1067 } 1068