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