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