103831d35Sstevel /*
203831d35Sstevel * CDDL HEADER START
303831d35Sstevel *
403831d35Sstevel * The contents of this file are subject to the terms of the
503831d35Sstevel * Common Development and Distribution License, Version 1.0 only
603831d35Sstevel * (the "License"). You may not use this file except in compliance
703831d35Sstevel * with the License.
803831d35Sstevel *
903831d35Sstevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1003831d35Sstevel * or http://www.opensolaris.org/os/licensing.
1103831d35Sstevel * See the License for the specific language governing permissions
1203831d35Sstevel * and limitations under the License.
1303831d35Sstevel *
1403831d35Sstevel * When distributing Covered Code, include this CDDL HEADER in each
1503831d35Sstevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1603831d35Sstevel * If applicable, add the following below this CDDL HEADER, with the
1703831d35Sstevel * fields enclosed by brackets "[]" replaced with your own identifying
1803831d35Sstevel * information: Portions Copyright [yyyy] [name of copyright owner]
1903831d35Sstevel *
2003831d35Sstevel * CDDL HEADER END
2103831d35Sstevel */
2203831d35Sstevel /*
2303831d35Sstevel * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
2403831d35Sstevel * All rights reserved.
2503831d35Sstevel */
2603831d35Sstevel
2703831d35Sstevel #include <stdio.h>
2803831d35Sstevel #include <stdlib.h>
2903831d35Sstevel #include <unistd.h>
3003831d35Sstevel #include <ctype.h>
3103831d35Sstevel #include <string.h>
3203831d35Sstevel #include <kvm.h>
3303831d35Sstevel #include <varargs.h>
3403831d35Sstevel #include <errno.h>
3503831d35Sstevel #include <time.h>
3603831d35Sstevel #include <dirent.h>
3703831d35Sstevel #include <fcntl.h>
3803831d35Sstevel #include <sys/param.h>
3903831d35Sstevel #include <sys/stat.h>
4003831d35Sstevel #include <sys/types.h>
4103831d35Sstevel #include <sys/utsname.h>
4203831d35Sstevel #include <sys/openpromio.h>
4303831d35Sstevel #include <sys/systeminfo.h>
4403831d35Sstevel #include <kstat.h>
4503831d35Sstevel #include <libintl.h>
4603831d35Sstevel #include <syslog.h>
4703831d35Sstevel #include <sys/dkio.h>
4803831d35Sstevel #include "pdevinfo.h"
4903831d35Sstevel #include "display.h"
5003831d35Sstevel #include "pdevinfo_sun4u.h"
5103831d35Sstevel #include "display_sun4u.h"
5203831d35Sstevel #include "libprtdiag.h"
5303831d35Sstevel
5403831d35Sstevel #if !defined(TEXT_DOMAIN)
5503831d35Sstevel #define TEXT_DOMAIN "SYS_TEST"
5603831d35Sstevel #endif
5703831d35Sstevel
5803831d35Sstevel Prom_node *
find_pci_bus(Prom_node * node,int id,int bus)5903831d35Sstevel find_pci_bus(Prom_node *node, int id, int bus)
6003831d35Sstevel {
6103831d35Sstevel Prom_node *pnode;
6203831d35Sstevel
6303831d35Sstevel /* find the first pci node */
6403831d35Sstevel pnode = dev_find_node(node, "pci");
6503831d35Sstevel
6603831d35Sstevel while (pnode != NULL) {
6703831d35Sstevel int tmp_id;
6803831d35Sstevel int tmp_bus;
6903831d35Sstevel
7003831d35Sstevel tmp_id = get_id(pnode);
7103831d35Sstevel tmp_bus = get_pci_bus(pnode);
7203831d35Sstevel
7303831d35Sstevel if ((tmp_id == id) &&
7403831d35Sstevel (tmp_bus == bus)) {
7503831d35Sstevel break;
7603831d35Sstevel }
7703831d35Sstevel
7803831d35Sstevel pnode = dev_next_node(pnode, "pci");
7903831d35Sstevel }
8003831d35Sstevel return (pnode);
8103831d35Sstevel }
8203831d35Sstevel
8303831d35Sstevel /*
8403831d35Sstevel * get_pci_bus
8503831d35Sstevel *
8603831d35Sstevel * Determines the PCI bus, either A (0) or B (1). If the function cannot
8703831d35Sstevel * find the bus-ranges property, it returns -1.
8803831d35Sstevel */
8903831d35Sstevel int
get_pci_bus(Prom_node * pnode)9003831d35Sstevel get_pci_bus(Prom_node *pnode)
9103831d35Sstevel {
9203831d35Sstevel int *value;
9303831d35Sstevel
9403831d35Sstevel /* look up the bus-range property */
9503831d35Sstevel if ((value = (int *)get_prop_val(find_prop(pnode, "bus-range"))) ==
9603831d35Sstevel NULL) {
9703831d35Sstevel return (-1);
9803831d35Sstevel }
9903831d35Sstevel
10003831d35Sstevel if (*value == 0) {
10103831d35Sstevel return (1); /* B bus has a bus-range value = 0 */
10203831d35Sstevel } else {
10303831d35Sstevel return (0);
10403831d35Sstevel }
10503831d35Sstevel }
10603831d35Sstevel
10703831d35Sstevel
10803831d35Sstevel
10903831d35Sstevel /*
11003831d35Sstevel * Find the PCI device number of this PCI device. If no device number can
11103831d35Sstevel * be determined, then return -1.
11203831d35Sstevel */
11303831d35Sstevel int
get_pci_device(Prom_node * pnode)11403831d35Sstevel get_pci_device(Prom_node *pnode)
11503831d35Sstevel {
11603831d35Sstevel void *value;
11703831d35Sstevel
118*6fb59094SToomas Soome value = get_prop_val(find_prop(pnode, "assigned-addresses"));
119*6fb59094SToomas Soome if (value != NULL) {
12003831d35Sstevel return (PCI_DEVICE(*(int *)value));
12103831d35Sstevel } else {
12203831d35Sstevel return (-1);
12303831d35Sstevel }
12403831d35Sstevel }
12503831d35Sstevel
12603831d35Sstevel /*
12703831d35Sstevel * Find the PCI device number of this PCI device. If no device number can
12803831d35Sstevel * be determined, then return -1.
12903831d35Sstevel */
13003831d35Sstevel int
get_pci_to_pci_device(Prom_node * pnode)13103831d35Sstevel get_pci_to_pci_device(Prom_node *pnode)
13203831d35Sstevel {
13303831d35Sstevel void *value;
13403831d35Sstevel
135*6fb59094SToomas Soome value = get_prop_val(find_prop(pnode, "reg"));
136*6fb59094SToomas Soome if (value != NULL) {
13703831d35Sstevel return (PCI_DEVICE(*(int *)value));
13803831d35Sstevel } else {
13903831d35Sstevel return (-1);
14003831d35Sstevel }
14103831d35Sstevel }
14203831d35Sstevel
14303831d35Sstevel /*
14403831d35Sstevel * free_io_cards
14503831d35Sstevel * Frees the memory allocated for an io card list.
14603831d35Sstevel */
14703831d35Sstevel void
free_io_cards(struct io_card * card_list)14803831d35Sstevel free_io_cards(struct io_card *card_list)
14903831d35Sstevel {
15003831d35Sstevel /* Free the list */
15103831d35Sstevel if (card_list != NULL) {
15203831d35Sstevel struct io_card *p, *q;
15303831d35Sstevel
15403831d35Sstevel for (p = card_list, q = NULL; p != NULL; p = q) {
15503831d35Sstevel q = p->next;
15603831d35Sstevel free(p);
15703831d35Sstevel }
15803831d35Sstevel }
15903831d35Sstevel }
16003831d35Sstevel
16103831d35Sstevel
16203831d35Sstevel /*
16303831d35Sstevel * insert_io_card
16403831d35Sstevel * Inserts an io_card structure into the list. The list is maintained
16503831d35Sstevel * in order based on board number and slot number. Also, the storage
16603831d35Sstevel * for the "card" argument is assumed to be handled by the caller,
16703831d35Sstevel * so we won't touch it.
16803831d35Sstevel */
16903831d35Sstevel struct io_card *
insert_io_card(struct io_card * list,struct io_card * card)17003831d35Sstevel insert_io_card(struct io_card *list, struct io_card *card)
17103831d35Sstevel {
17203831d35Sstevel struct io_card *newcard;
17303831d35Sstevel struct io_card *p, *q;
17403831d35Sstevel
17503831d35Sstevel if (card == NULL)
17603831d35Sstevel return (list);
17703831d35Sstevel
17803831d35Sstevel /* Copy the card to be added into new storage */
17903831d35Sstevel newcard = (struct io_card *)malloc(sizeof (struct io_card));
18003831d35Sstevel if (newcard == NULL) {
18103831d35Sstevel perror("malloc");
18203831d35Sstevel exit(2);
18303831d35Sstevel }
18403831d35Sstevel (void) memcpy(newcard, card, sizeof (struct io_card));
18503831d35Sstevel newcard->next = NULL;
18603831d35Sstevel
18703831d35Sstevel if (list == NULL)
188*6fb59094SToomas Soome return (newcard);
18903831d35Sstevel
19003831d35Sstevel /* Find the proper place in the list for the new card */
19103831d35Sstevel for (p = list, q = NULL; p != NULL; q = p, p = p->next) {
19203831d35Sstevel if (newcard->board < p->board)
19303831d35Sstevel break;
19403831d35Sstevel if ((newcard->board == p->board) && (newcard->slot < p->slot))
19503831d35Sstevel break;
19603831d35Sstevel }
19703831d35Sstevel
19803831d35Sstevel /* Insert the new card into the list */
19903831d35Sstevel if (q == NULL) {
20003831d35Sstevel newcard->next = p;
20103831d35Sstevel return (newcard);
20203831d35Sstevel } else {
20303831d35Sstevel newcard->next = p;
20403831d35Sstevel q->next = newcard;
20503831d35Sstevel return (list);
20603831d35Sstevel }
20703831d35Sstevel }
20803831d35Sstevel
20903831d35Sstevel
21003831d35Sstevel char *
fmt_manf_id(unsigned int encoded_id,char * outbuf)21103831d35Sstevel fmt_manf_id(unsigned int encoded_id, char *outbuf)
21203831d35Sstevel {
21303831d35Sstevel union manuf manuf;
21403831d35Sstevel
21503831d35Sstevel /*
21603831d35Sstevel * Format the manufacturer's info. Note a small inconsistency we
21703831d35Sstevel * have to work around - Brooktree has it's part number in decimal,
21803831d35Sstevel * while Mitsubishi has it's part number in hex.
21903831d35Sstevel */
22003831d35Sstevel manuf.encoded_id = encoded_id;
22103831d35Sstevel switch (manuf.fld.manf) {
22203831d35Sstevel case MANF_BROOKTREE:
22303831d35Sstevel (void) sprintf(outbuf, "%s %d, version %d", "Brooktree",
224*6fb59094SToomas Soome manuf.fld.partno, manuf.fld.version);
22503831d35Sstevel break;
22603831d35Sstevel
22703831d35Sstevel case MANF_MITSUBISHI:
22803831d35Sstevel (void) sprintf(outbuf, "%s %x, version %d", "Mitsubishi",
229*6fb59094SToomas Soome manuf.fld.partno, manuf.fld.version);
23003831d35Sstevel break;
23103831d35Sstevel
23203831d35Sstevel default:
23303831d35Sstevel (void) sprintf(outbuf, "JED code %d, Part num 0x%x, version %d",
234*6fb59094SToomas Soome manuf.fld.manf, manuf.fld.partno, manuf.fld.version);
23503831d35Sstevel }
23603831d35Sstevel return (outbuf);
23703831d35Sstevel }
23803831d35Sstevel
23903831d35Sstevel
24003831d35Sstevel /*
24103831d35Sstevel * Find the sbus slot number of this Sbus device. If no slot number can
24203831d35Sstevel * be determined, then return -1.
24303831d35Sstevel */
24403831d35Sstevel int
get_sbus_slot(Prom_node * pnode)24503831d35Sstevel get_sbus_slot(Prom_node *pnode)
24603831d35Sstevel {
24703831d35Sstevel void *value;
24803831d35Sstevel
24903831d35Sstevel if ((value = get_prop_val(find_prop(pnode, "reg"))) != NULL) {
25003831d35Sstevel return (*(int *)value);
25103831d35Sstevel } else {
25203831d35Sstevel return (-1);
25303831d35Sstevel }
25403831d35Sstevel }
25503831d35Sstevel
25603831d35Sstevel
25703831d35Sstevel /*
25803831d35Sstevel * This routine is the generic link into displaying system IO
25903831d35Sstevel * configuration. It displays the table header, then displays
26003831d35Sstevel * all the SBus cards, then displays all fo the PCI IO cards.
26103831d35Sstevel */
26203831d35Sstevel void
display_io_devices(Sys_tree * tree)26303831d35Sstevel display_io_devices(Sys_tree *tree)
26403831d35Sstevel {
26503831d35Sstevel Board_node *bnode;
26603831d35Sstevel
26703831d35Sstevel /*
26803831d35Sstevel * TRANSLATION_NOTE
26903831d35Sstevel * Following string is used as a table header.
27003831d35Sstevel * Please maintain the current alignment in
27103831d35Sstevel * translation.
27203831d35Sstevel */
27303831d35Sstevel log_printf("\n", 0);
27403831d35Sstevel log_printf("=========================", 0);
27503831d35Sstevel log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0);
27603831d35Sstevel log_printf("=========================", 0);
27703831d35Sstevel log_printf("\n", 0);
27803831d35Sstevel log_printf("\n", 0);
27903831d35Sstevel bnode = tree->bd_list;
28003831d35Sstevel while (bnode != NULL) {
28103831d35Sstevel display_sbus(bnode);
28203831d35Sstevel display_pci(bnode);
28303831d35Sstevel display_ffb(bnode, 1);
28403831d35Sstevel bnode = bnode->next;
28503831d35Sstevel }
28603831d35Sstevel }
28703831d35Sstevel
28803831d35Sstevel void
display_pci(Board_node * bnode)28903831d35Sstevel display_pci(Board_node *bnode)
29003831d35Sstevel {
29103831d35Sstevel #ifdef lint
29203831d35Sstevel bnode = bnode;
29303831d35Sstevel #endif
29403831d35Sstevel /*
29503831d35Sstevel * This function is intentionally empty
29603831d35Sstevel */
29703831d35Sstevel }
29803831d35Sstevel
29903831d35Sstevel
30003831d35Sstevel /*
30103831d35Sstevel * Print out all the io cards in the list. Also print the column
30203831d35Sstevel * headers if told to do so.
30303831d35Sstevel */
30403831d35Sstevel void
display_io_cards(struct io_card * list)30503831d35Sstevel display_io_cards(struct io_card *list)
30603831d35Sstevel {
30703831d35Sstevel static int banner = 0; /* Have we printed the column headings? */
30803831d35Sstevel struct io_card *p;
30903831d35Sstevel
31003831d35Sstevel if (list == NULL)
31103831d35Sstevel return;
31203831d35Sstevel
31303831d35Sstevel if (banner == 0) {
31403831d35Sstevel log_printf(" Bus Freq\n", 0);
31503831d35Sstevel log_printf("Brd Type MHz Slot "
316*6fb59094SToomas Soome "Name "
317*6fb59094SToomas Soome "Model", 0);
31803831d35Sstevel log_printf("\n", 0);
31903831d35Sstevel log_printf("--- ---- ---- ---------- "
320*6fb59094SToomas Soome "---------------------------- "
321*6fb59094SToomas Soome "--------------------", 0);
32203831d35Sstevel log_printf("\n", 0);
32303831d35Sstevel banner = 1;
32403831d35Sstevel }
32503831d35Sstevel
32603831d35Sstevel for (p = list; p != NULL; p = p -> next) {
32703831d35Sstevel log_printf("%2d ", p->board, 0);
32803831d35Sstevel log_printf("%-4s ", p->bus_type, 0);
32903831d35Sstevel log_printf("%3d ", p->freq, 0);
33003831d35Sstevel /*
33103831d35Sstevel * We check to see if it's an int or
33203831d35Sstevel * a char string to display for slot.
33303831d35Sstevel */
33403831d35Sstevel if (p->slot == PCI_SLOT_IS_STRING)
33503831d35Sstevel log_printf("%10s ", p->slot_str, 0);
33603831d35Sstevel else
33703831d35Sstevel log_printf("%10d ", p->slot, 0);
33803831d35Sstevel
33903831d35Sstevel log_printf("%-28.28s", p->name, 0);
34003831d35Sstevel if (strlen(p->name) > 28)
34103831d35Sstevel log_printf("+ ", 0);
34203831d35Sstevel else
34303831d35Sstevel log_printf(" ", 0);
34403831d35Sstevel log_printf("%-19.19s", p->model, 0);
34503831d35Sstevel if (strlen(p->model) > 19)
34603831d35Sstevel log_printf("+", 0);
34703831d35Sstevel log_printf("\n", 0);
34803831d35Sstevel }
34903831d35Sstevel }
35003831d35Sstevel
35103831d35Sstevel /*
35203831d35Sstevel * Display all FFBs on this board. It can either be in tabular format,
35303831d35Sstevel * or a more verbose format.
35403831d35Sstevel */
35503831d35Sstevel void
display_ffb(Board_node * board,int table)35603831d35Sstevel display_ffb(Board_node *board, int table)
35703831d35Sstevel {
35803831d35Sstevel Prom_node *fb;
35903831d35Sstevel void *value;
36003831d35Sstevel struct io_card *card_list = NULL;
36103831d35Sstevel struct io_card card;
36203831d35Sstevel char *type;
36303831d35Sstevel char *label;
36403831d35Sstevel
36503831d35Sstevel if (board == NULL)
36603831d35Sstevel return;
36703831d35Sstevel
36803831d35Sstevel /* Fill in common information */
36903831d35Sstevel card.display = 1;
37003831d35Sstevel card.board = board->board_num;
37103831d35Sstevel (void) sprintf(card.bus_type, BUS_TYPE);
37203831d35Sstevel card.freq = sys_clk;
37303831d35Sstevel
37403831d35Sstevel for (fb = dev_find_node_by_type(board->nodes, "device_type", "display");
37503831d35Sstevel fb != NULL;
37603831d35Sstevel fb = dev_next_node_by_type(fb, "device_type", "display")) {
37703831d35Sstevel value = get_prop_val(find_prop(fb, "name"));
37803831d35Sstevel if (value != NULL) {
37903831d35Sstevel if ((strcmp(FFB_NAME, value)) == 0) {
38003831d35Sstevel type = FFB_NAME;
38103831d35Sstevel label = "FFB";
38203831d35Sstevel } else if ((strcmp(AFB_NAME, value)) == 0) {
38303831d35Sstevel type = AFB_NAME;
38403831d35Sstevel label = "AFB";
38503831d35Sstevel } else
38603831d35Sstevel continue;
38703831d35Sstevel } else
38803831d35Sstevel continue;
38903831d35Sstevel if (table == 1) {
39003831d35Sstevel /* Print out in table format */
39103831d35Sstevel
39203831d35Sstevel /* XXX - Get the slot number (hack) */
39303831d35Sstevel card.slot = get_id(fb);
39403831d35Sstevel
39503831d35Sstevel /* Find out if it's single or double buffered */
39603831d35Sstevel (void) sprintf(card.name, "%s", label);
39703831d35Sstevel value = get_prop_val(find_prop(fb, "board_type"));
39803831d35Sstevel if (value != NULL)
39903831d35Sstevel if ((*(int *)value) & FFB_B_BUFF)
40003831d35Sstevel (void) sprintf(card.name,
401*6fb59094SToomas Soome "%s, Double Buffered", label);
40203831d35Sstevel else
40303831d35Sstevel (void) sprintf(card.name,
404*6fb59094SToomas Soome "%s, Single Buffered", label);
40503831d35Sstevel
40603831d35Sstevel /*
40703831d35Sstevel * Print model number only if board_type bit 2
40803831d35Sstevel * is not set and it is not SUNW,XXX-XXXX.
40903831d35Sstevel */
41003831d35Sstevel card.model[0] = '\0';
41103831d35Sstevel
41203831d35Sstevel if (strcmp(type, AFB_NAME) == 0) {
41303831d35Sstevel if (((*(int *)value) & 0x4) != 0x4) {
41403831d35Sstevel value = get_prop_val(find_prop(fb,
415*6fb59094SToomas Soome "model"));
41603831d35Sstevel if ((value != NULL) &&
41703831d35Sstevel (strcmp(value,
41803831d35Sstevel "SUNW,XXX-XXXX") != 0)) {
41903831d35Sstevel (void) sprintf(card.model, "%s",
42003831d35Sstevel (char *)value);
42103831d35Sstevel }
42203831d35Sstevel }
42303831d35Sstevel } else {
42403831d35Sstevel value = get_prop_val(find_prop(fb, "model"));
42503831d35Sstevel if (value != NULL)
42603831d35Sstevel (void) sprintf(card.model, "%s",
42703831d35Sstevel (char *)value);
42803831d35Sstevel }
42903831d35Sstevel
43003831d35Sstevel card_list = insert_io_card(card_list, &card);
43103831d35Sstevel } else {
43203831d35Sstevel /* print in long format */
43303831d35Sstevel char device[MAXSTRLEN];
43403831d35Sstevel int fd = -1;
43503831d35Sstevel struct dirent *direntp;
43603831d35Sstevel DIR *dirp;
43703831d35Sstevel union strap_un strap;
43803831d35Sstevel struct ffb_sys_info fsi;
43903831d35Sstevel
44003831d35Sstevel /* Find the device node using upa-portid/portid */
44103831d35Sstevel value = get_prop_val(find_prop(fb, "upa-portid"));
44203831d35Sstevel if (value == NULL)
44303831d35Sstevel value = get_prop_val(find_prop(fb, "portid"));
44403831d35Sstevel
44503831d35Sstevel if (value == NULL)
446*6fb59094SToomas Soome continue;
44703831d35Sstevel
44803831d35Sstevel (void) sprintf(device, "%s@%x", type,
449*6fb59094SToomas Soome *(int *)value);
45003831d35Sstevel if ((dirp = opendir("/devices")) == NULL)
45103831d35Sstevel continue;
45203831d35Sstevel
45303831d35Sstevel while ((direntp = readdir(dirp)) != NULL) {
45403831d35Sstevel if (strstr(direntp->d_name, device) != NULL) {
45503831d35Sstevel (void) sprintf(device, "/devices/%s",
456*6fb59094SToomas Soome direntp->d_name);
45703831d35Sstevel fd = open(device, O_RDWR, 0666);
45803831d35Sstevel break;
45903831d35Sstevel }
46003831d35Sstevel }
46103831d35Sstevel (void) closedir(dirp);
46203831d35Sstevel
46303831d35Sstevel if (fd == -1)
46403831d35Sstevel continue;
46503831d35Sstevel
46603831d35Sstevel if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
46703831d35Sstevel continue;
46803831d35Sstevel
46903831d35Sstevel log_printf("%s Hardware Configuration:\n", label, 0);
47003831d35Sstevel log_printf("-----------------------------------\n", 0);
47103831d35Sstevel
47203831d35Sstevel strap.ffb_strap_bits = fsi.ffb_strap_bits;
47303831d35Sstevel log_printf("\tBoard rev: %d\n",
474*6fb59094SToomas Soome (int)strap.fld.board_rev, 0);
47503831d35Sstevel log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
47603831d35Sstevel log_printf("\tDAC: %s\n",
477*6fb59094SToomas Soome fmt_manf_id(fsi.dac_version, device), 0);
47803831d35Sstevel log_printf("\t3DRAM: %s\n",
479*6fb59094SToomas Soome fmt_manf_id(fsi.fbram_version, device), 0);
48003831d35Sstevel log_printf("\n", 0);
48103831d35Sstevel }
48203831d35Sstevel
48303831d35Sstevel }
48403831d35Sstevel display_io_cards(card_list);
48503831d35Sstevel free_io_cards(card_list);
48603831d35Sstevel }
48703831d35Sstevel
48803831d35Sstevel
48903831d35Sstevel /*
49003831d35Sstevel * Display all the SBus IO cards on this board.
49103831d35Sstevel */
49203831d35Sstevel void
display_sbus(Board_node * board)49303831d35Sstevel display_sbus(Board_node *board)
49403831d35Sstevel {
49503831d35Sstevel struct io_card card;
49603831d35Sstevel struct io_card *card_list = NULL;
49703831d35Sstevel int freq;
49803831d35Sstevel int card_num;
49903831d35Sstevel void *value;
50003831d35Sstevel Prom_node *sbus;
50103831d35Sstevel Prom_node *card_node;
50203831d35Sstevel
50303831d35Sstevel if (board == NULL)
50403831d35Sstevel return;
50503831d35Sstevel
50603831d35Sstevel for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL;
50703831d35Sstevel sbus = dev_next_node(sbus, SBUS_NAME)) {
50803831d35Sstevel
50903831d35Sstevel /* Skip failed nodes for now */
51003831d35Sstevel if (node_failed(sbus))
51103831d35Sstevel continue;
51203831d35Sstevel
51303831d35Sstevel /* Calculate SBus frequency in MHz */
51403831d35Sstevel value = get_prop_val(find_prop(sbus, "clock-frequency"));
51503831d35Sstevel if (value != NULL)
51603831d35Sstevel freq = ((*(int *)value) + 500000) / 1000000;
51703831d35Sstevel else
51803831d35Sstevel freq = -1;
51903831d35Sstevel
52003831d35Sstevel for (card_node = sbus->child; card_node != NULL;
52103831d35Sstevel card_node = card_node->sibling) {
52203831d35Sstevel char *model;
52303831d35Sstevel char *name;
52403831d35Sstevel char *child_name;
52503831d35Sstevel
52603831d35Sstevel card_num = get_sbus_slot(card_node);
52703831d35Sstevel if (card_num == -1)
52803831d35Sstevel continue;
52903831d35Sstevel
53003831d35Sstevel /* Fill in card information */
53103831d35Sstevel card.display = 1;
53203831d35Sstevel card.freq = freq;
53303831d35Sstevel card.board = board->board_num;
53403831d35Sstevel (void) sprintf(card.bus_type, "SBus");
53503831d35Sstevel card.slot = card_num;
53603831d35Sstevel card.status[0] = '\0';
53703831d35Sstevel
53803831d35Sstevel /* Try and get card status */
53903831d35Sstevel value = get_prop_val(find_prop(card_node, "status"));
54003831d35Sstevel if (value != NULL)
54103831d35Sstevel (void) strncpy(card.status, (char *)value,
542*6fb59094SToomas Soome MAXSTRLEN);
54303831d35Sstevel
54403831d35Sstevel /* XXX - For now, don't display failed cards */
54503831d35Sstevel if (strstr(card.status, "fail") != NULL)
54603831d35Sstevel continue;
54703831d35Sstevel
54803831d35Sstevel /* Now gather all of the node names for that card */
54903831d35Sstevel model = (char *)get_prop_val(find_prop(card_node,
550*6fb59094SToomas Soome "model"));
55103831d35Sstevel name = get_node_name(card_node);
55203831d35Sstevel
55303831d35Sstevel if (name == NULL)
55403831d35Sstevel continue;
55503831d35Sstevel
55603831d35Sstevel card.name[0] = '\0';
55703831d35Sstevel card.model[0] = '\0';
55803831d35Sstevel
55903831d35Sstevel /* Figure out how we want to display the name */
56003831d35Sstevel child_name = get_node_name(card_node->child);
56103831d35Sstevel if ((card_node->child != NULL) &&
56203831d35Sstevel (child_name != NULL)) {
56303831d35Sstevel value = get_prop_val(find_prop(card_node->child,
564*6fb59094SToomas Soome "device_type"));
56503831d35Sstevel if (value != NULL)
56603831d35Sstevel (void) sprintf(card.name, "%s/%s (%s)",
567*6fb59094SToomas Soome name, child_name,
568*6fb59094SToomas Soome (char *)value);
56903831d35Sstevel else
57003831d35Sstevel (void) sprintf(card.name, "%s/%s", name,
571*6fb59094SToomas Soome child_name);
57203831d35Sstevel } else {
57303831d35Sstevel (void) strncpy(card.name, name, MAXSTRLEN);
57403831d35Sstevel }
57503831d35Sstevel
57603831d35Sstevel if (model != NULL)
57703831d35Sstevel (void) strncpy(card.model, model, MAXSTRLEN);
57803831d35Sstevel
57903831d35Sstevel card_list = insert_io_card(card_list, &card);
58003831d35Sstevel }
58103831d35Sstevel }
58203831d35Sstevel
58303831d35Sstevel /* We're all done gathering card info, now print it out */
58403831d35Sstevel display_io_cards(card_list);
58503831d35Sstevel free_io_cards(card_list);
58603831d35Sstevel }
58703831d35Sstevel
58803831d35Sstevel
58903831d35Sstevel /*
59003831d35Sstevel * Get slot-names properties from parent node and
59103831d35Sstevel * store them in an array.
59203831d35Sstevel */
59303831d35Sstevel int
populate_slot_name_arr(Prom_node * pci,int * slot_name_bits,char ** slot_name_arr,int num_slots)59403831d35Sstevel populate_slot_name_arr(Prom_node *pci, int *slot_name_bits,
595*6fb59094SToomas Soome char **slot_name_arr, int num_slots)
59603831d35Sstevel {
59703831d35Sstevel int i, j, bit_mask;
59803831d35Sstevel char *value;
59903831d35Sstevel
60003831d35Sstevel value = (char *)get_prop_val(find_prop(pci, "slot-names"));
60103831d35Sstevel D_PRINTF("\n populate_slot_name_arr: value = [0x%x]\n", value);
60203831d35Sstevel
60303831d35Sstevel if (value != NULL) {
60403831d35Sstevel char *strings_arr[MAX_SLOTS_PER_IO_BD];
60503831d35Sstevel bit_mask = *slot_name_bits = *(int *)value;
60603831d35Sstevel D_PRINTF("\nslot_names 1st integer = [0x%x]", *slot_name_bits);
60703831d35Sstevel
60803831d35Sstevel /* array starts after first int */
60903831d35Sstevel strings_arr[0] = value + sizeof (int);
61003831d35Sstevel
61103831d35Sstevel /*
61203831d35Sstevel * break the array out into num_slots number of strings
61303831d35Sstevel */
61403831d35Sstevel for (i = 1; i < num_slots; i++) {
61503831d35Sstevel strings_arr[i] = (char *)strings_arr[i - 1]
61603831d35Sstevel + strlen(strings_arr[i - 1]) + 1;
61703831d35Sstevel }
61803831d35Sstevel
61903831d35Sstevel /*
62003831d35Sstevel * process array of slot_names to remove blanks
62103831d35Sstevel */
62203831d35Sstevel j = 0;
62303831d35Sstevel for (i = 0; i < num_slots; i++) {
62403831d35Sstevel if ((bit_mask >> i) & 0x1)
62503831d35Sstevel slot_name_arr[i] = strings_arr[j++];
62603831d35Sstevel else
62703831d35Sstevel slot_name_arr[i] = "";
62803831d35Sstevel
62903831d35Sstevel D_PRINTF("\nslot_name_arr[%d] = [%s]", i,
630*6fb59094SToomas Soome slot_name_arr[i]);
63103831d35Sstevel }
63203831d35Sstevel return (0);
63303831d35Sstevel } else {
63403831d35Sstevel D_PRINTF("\n populate_slot_name_arr: - psycho with no "
63503831d35Sstevel "slot-names\n");
63603831d35Sstevel return (0);
63703831d35Sstevel }
63803831d35Sstevel }
63903831d35Sstevel
64003831d35Sstevel int
get_card_frequency(Prom_node * pci)64103831d35Sstevel get_card_frequency(Prom_node *pci)
64203831d35Sstevel {
64303831d35Sstevel char *value = get_prop_val(find_prop(pci, "clock-frequency"));
64403831d35Sstevel
64503831d35Sstevel if (value == NULL)
64603831d35Sstevel return (-1);
64703831d35Sstevel else
64803831d35Sstevel return (int)(((*(int *)value) + 500000) / 1000000);
64903831d35Sstevel
65003831d35Sstevel }
65103831d35Sstevel
65203831d35Sstevel void
get_dev_func_num(Prom_node * card_node,int * dev_no,int * func_no)65303831d35Sstevel get_dev_func_num(Prom_node *card_node, int *dev_no, int *func_no)
65403831d35Sstevel {
65503831d35Sstevel
65603831d35Sstevel void *value = get_prop_val(find_prop(card_node, "reg"));
65703831d35Sstevel
65803831d35Sstevel if (value != NULL) {
65903831d35Sstevel int int_val = *(int *)value;
66003831d35Sstevel *dev_no = PCI_REG_TO_DEV(int_val);
66103831d35Sstevel *func_no = PCI_REG_TO_FUNC(int_val);
66203831d35Sstevel } else {
66303831d35Sstevel *dev_no = -1;
66403831d35Sstevel *func_no = -1;
66503831d35Sstevel }
66603831d35Sstevel }
66703831d35Sstevel
66803831d35Sstevel void
get_pci_class_codes(Prom_node * card_node,int * class_code,int * subclass_code)66903831d35Sstevel get_pci_class_codes(Prom_node *card_node, int *class_code, int *subclass_code)
67003831d35Sstevel {
67103831d35Sstevel int class_code_reg = get_pci_class_code_reg(card_node);
67203831d35Sstevel
67303831d35Sstevel *class_code = CLASS_REG_TO_CLASS(class_code_reg);
67403831d35Sstevel *subclass_code = CLASS_REG_TO_SUBCLASS(class_code_reg);
67503831d35Sstevel }
67603831d35Sstevel
67703831d35Sstevel int
is_pci_bridge(Prom_node * card_node,char * name)67803831d35Sstevel is_pci_bridge(Prom_node *card_node, char *name)
67903831d35Sstevel {
68003831d35Sstevel int class_code, subclass_code;
68103831d35Sstevel
68203831d35Sstevel if (card_node == NULL)
68303831d35Sstevel return (FALSE);
68403831d35Sstevel
68503831d35Sstevel get_pci_class_codes(card_node, &class_code, &subclass_code);
68603831d35Sstevel
68703831d35Sstevel if ((strncmp(name, "pci", 3) == 0) &&
68803831d35Sstevel (class_code == PCI_BRIDGE_CLASS) &&
68903831d35Sstevel (subclass_code == PCI_PCI_BRIDGE_SUBCLASS))
69003831d35Sstevel return (TRUE);
69103831d35Sstevel else
69203831d35Sstevel return (FALSE);
69303831d35Sstevel }
69403831d35Sstevel
69503831d35Sstevel int
is_pci_bridge_other(Prom_node * card_node,char * name)69603831d35Sstevel is_pci_bridge_other(Prom_node *card_node, char *name)
69703831d35Sstevel {
69803831d35Sstevel int class_code, subclass_code;
69903831d35Sstevel
70003831d35Sstevel if (card_node == NULL)
70103831d35Sstevel return (FALSE);
70203831d35Sstevel
70303831d35Sstevel get_pci_class_codes(card_node, &class_code, &subclass_code);
70403831d35Sstevel
70503831d35Sstevel if ((strncmp(name, "pci", 3) == 0) &&
70603831d35Sstevel (class_code == PCI_BRIDGE_CLASS) &&
70703831d35Sstevel (subclass_code == PCI_SUBCLASS_OTHER))
70803831d35Sstevel return (TRUE);
70903831d35Sstevel else
71003831d35Sstevel return (FALSE);
71103831d35Sstevel }
71203831d35Sstevel void
get_pci_card_model(Prom_node * card_node,char * model)71303831d35Sstevel get_pci_card_model(Prom_node *card_node, char *model)
71403831d35Sstevel {
71503831d35Sstevel char *name = get_prop_val(find_prop(card_node, "name"));
71603831d35Sstevel char *value = get_prop_val(find_prop(card_node, "model"));
717*6fb59094SToomas Soome int pci_bridge = is_pci_bridge(card_node, name);
71803831d35Sstevel
71903831d35Sstevel if (value == NULL)
72003831d35Sstevel model[0] = '\0';
72103831d35Sstevel else
722*6fb59094SToomas Soome (void) sprintf(model, "%s", value);
72303831d35Sstevel
72403831d35Sstevel if (pci_bridge) {
72503831d35Sstevel if (strlen(model) == 0)
726*6fb59094SToomas Soome (void) sprintf(model, "%s", "pci-bridge");
72703831d35Sstevel else
728*6fb59094SToomas Soome (void) sprintf(model, "%s/pci-bridge", model);
72903831d35Sstevel }
73003831d35Sstevel }
73103831d35Sstevel
73203831d35Sstevel void
create_io_card_name(Prom_node * card_node,char * name,char * card_name)73303831d35Sstevel create_io_card_name(Prom_node *card_node, char *name, char *card_name)
73403831d35Sstevel {
73503831d35Sstevel char *value = get_prop_val(find_prop(card_node, "compatible"));
73603831d35Sstevel char *child_name;
73703831d35Sstevel char buf[MAXSTRLEN];
73803831d35Sstevel
73903831d35Sstevel if (value != NULL) {
740*6fb59094SToomas Soome (void) sprintf(buf, "%s-%s", name, value);
74103831d35Sstevel } else
74203831d35Sstevel (void) sprintf(buf, "%s", name);
74303831d35Sstevel
74403831d35Sstevel name = buf;
74503831d35Sstevel
74603831d35Sstevel child_name = (char *)get_node_name(card_node->child);
74703831d35Sstevel
74803831d35Sstevel if ((card_node->child != NULL) &&
74903831d35Sstevel (child_name != NULL)) {
75003831d35Sstevel value = get_prop_val(find_prop(card_node->child,
751*6fb59094SToomas Soome "device_type"));
75203831d35Sstevel if (value != NULL)
75303831d35Sstevel (void) sprintf(card_name, "%s/%s (%s)",
754*6fb59094SToomas Soome name, child_name, value);
75503831d35Sstevel else
75603831d35Sstevel (void) sprintf(card_name, "%s/%s", name,
757*6fb59094SToomas Soome child_name);
75803831d35Sstevel } else {
759*6fb59094SToomas Soome (void) sprintf(card_name, "%s", name);
76003831d35Sstevel }
76103831d35Sstevel }
76203831d35Sstevel
76303831d35Sstevel
76403831d35Sstevel /*
76503831d35Sstevel * Desktop display_psycho_pci
76603831d35Sstevel * Display all the psycho based PCI IO cards on this board.
76703831d35Sstevel */
76803831d35Sstevel
76903831d35Sstevel /* ARGSUSED */
77003831d35Sstevel void
display_psycho_pci(Board_node * board)77103831d35Sstevel display_psycho_pci(Board_node *board)
77203831d35Sstevel {
77303831d35Sstevel struct io_card *card_list = NULL;
77403831d35Sstevel struct io_card card;
77503831d35Sstevel void *value;
77603831d35Sstevel
77703831d35Sstevel Prom_node *pci, *card_node, *pci_bridge_node = NULL;
77803831d35Sstevel char *name;
779*6fb59094SToomas Soome int slot_name_bits, pci_bridge_dev_no, class_code,
780*6fb59094SToomas Soome subclass_code, pci_pci_bridge;
78103831d35Sstevel char *slot_name_arr[MAX_SLOTS_PER_IO_BD];
78203831d35Sstevel
78303831d35Sstevel if (board == NULL)
78403831d35Sstevel return;
78503831d35Sstevel
78603831d35Sstevel /* Initialize all the common information */
78703831d35Sstevel card.display = 1;
78803831d35Sstevel card.board = board->board_num;
78903831d35Sstevel (void) sprintf(card.bus_type, "PCI");
79003831d35Sstevel
79103831d35Sstevel for (pci = dev_find_node_by_type(board->nodes, "model", "SUNW,psycho");
79203831d35Sstevel pci != NULL;
79303831d35Sstevel pci = dev_next_node_by_type(pci, "model", "SUNW,psycho")) {
79403831d35Sstevel
79503831d35Sstevel /*
79603831d35Sstevel * If we have reached a pci-to-pci bridge node,
79703831d35Sstevel * we are one level below the 'pci' nodes level
79803831d35Sstevel * in the device tree. To get back to that level,
79903831d35Sstevel * the search should continue with the sibling of
80003831d35Sstevel * the parent or else the remaining 'pci' cards
80103831d35Sstevel * will not show up in the output.
80203831d35Sstevel */
80303831d35Sstevel if (find_prop(pci, "upa-portid") == NULL) {
80403831d35Sstevel if ((pci->parent->sibling != NULL) &&
805*6fb59094SToomas Soome (strcmp(get_prop_val(
806*6fb59094SToomas Soome find_prop(pci->parent->sibling,
807*6fb59094SToomas Soome "name")), PCI_NAME) == 0)) {
80803831d35Sstevel pci = pci->parent->sibling;
809*6fb59094SToomas Soome } else {
81003831d35Sstevel pci = pci->parent->sibling;
81103831d35Sstevel continue;
81203831d35Sstevel }
81303831d35Sstevel }
81403831d35Sstevel
81503831d35Sstevel D_PRINTF("\n\n------->Looking at device [%s][%d] - [%s]\n",
81603831d35Sstevel PCI_NAME, *((int *)get_prop_val(find_prop(
817*6fb59094SToomas Soome pci, "upa-portid"))),
818*6fb59094SToomas Soome get_prop_val(find_prop(pci, "model")));
81903831d35Sstevel
82003831d35Sstevel /* Skip all failed nodes for now */
82103831d35Sstevel if (node_failed(pci))
82203831d35Sstevel continue;
82303831d35Sstevel
82403831d35Sstevel /* Fill in frequency */
82503831d35Sstevel card.freq = get_card_frequency(pci);
82603831d35Sstevel
82703831d35Sstevel /*
82803831d35Sstevel * Each PSYCHO device has a slot-names property that can be
82903831d35Sstevel * used to determine the slot-name string for each IO
83003831d35Sstevel * device under this node. We get this array now and use
83103831d35Sstevel * it later when looking at the children of this PSYCHO.
83203831d35Sstevel */
83303831d35Sstevel if ((populate_slot_name_arr(pci, &slot_name_bits,
83403831d35Sstevel (char **)&slot_name_arr, MAX_SLOTS_PER_IO_BD)) != 0)
83503831d35Sstevel goto next_card;
83603831d35Sstevel
83703831d35Sstevel /* Walk through the PSYCHO children */
83803831d35Sstevel card_node = pci->child;
83903831d35Sstevel while (card_node != NULL) {
84003831d35Sstevel
84103831d35Sstevel pci_pci_bridge = FALSE;
84203831d35Sstevel
84303831d35Sstevel /* If it doesn't have a name, skip it */
84403831d35Sstevel name = (char *)get_prop_val(
845*6fb59094SToomas Soome find_prop(card_node, "name"));
84603831d35Sstevel if (name == NULL)
84703831d35Sstevel goto next_card;
84803831d35Sstevel
84903831d35Sstevel /* get dev# and func# for this card. */
85003831d35Sstevel get_dev_func_num(card_node, &card.dev_no,
85103831d35Sstevel &card.func_no);
85203831d35Sstevel
85303831d35Sstevel /* get class/subclass code for this card. */
85403831d35Sstevel get_pci_class_codes(card_node, &class_code,
85503831d35Sstevel &subclass_code);
85603831d35Sstevel
85703831d35Sstevel D_PRINTF("\nName [%s] - ", name);
85803831d35Sstevel D_PRINTF("device no [%d] - ", card.dev_no);
85903831d35Sstevel D_PRINTF("class_code [%d] subclass_code [%d] - ",
86003831d35Sstevel class_code, subclass_code);
86103831d35Sstevel
86203831d35Sstevel /*
86303831d35Sstevel * Weed out PCI Bridge, subclass 'other' and
86403831d35Sstevel * ebus nodes.
86503831d35Sstevel */
86603831d35Sstevel if (((class_code == PCI_BRIDGE_CLASS) &&
86703831d35Sstevel (subclass_code == PCI_SUBCLASS_OTHER)) ||
86803831d35Sstevel (strstr(name, "ebus"))) {
86903831d35Sstevel D_PRINTF("\nSkip ebus/class-other nodes [%s]",
87003831d35Sstevel name);
87103831d35Sstevel goto next_card;
87203831d35Sstevel }
87303831d35Sstevel
87403831d35Sstevel /*
87503831d35Sstevel * If this is a PCI bridge, then we store it's dev_no
87603831d35Sstevel * so that it's children can use it for getting at
87703831d35Sstevel * the slot_name.
87803831d35Sstevel */
87903831d35Sstevel if (is_pci_bridge(card_node, name)) {
88003831d35Sstevel pci_bridge_dev_no = card.dev_no;
88103831d35Sstevel pci_bridge_node = card_node;
88203831d35Sstevel pci_pci_bridge = TRUE;
88303831d35Sstevel D_PRINTF("\nPCI Bridge detected\n");
88403831d35Sstevel }
88503831d35Sstevel
88603831d35Sstevel /*
88703831d35Sstevel * If we are the child of a pci_bridge we use the
88803831d35Sstevel * dev# of the pci_bridge as an index to get
88903831d35Sstevel * the slot number. We know that we are a child of
89003831d35Sstevel * a pci-bridge if our parent is the same as the last
89103831d35Sstevel * pci_bridge node found above.
89203831d35Sstevel */
89303831d35Sstevel if (card_node->parent == pci_bridge_node)
89403831d35Sstevel card.dev_no = pci_bridge_dev_no;
89503831d35Sstevel
89603831d35Sstevel /* Get slot-names property from slot_names_arr. */
89703831d35Sstevel get_slot_number_str(&card, (char **)slot_name_arr,
89803831d35Sstevel slot_name_bits);
89903831d35Sstevel
900*6fb59094SToomas Soome if (slot_name_bits) {
90103831d35Sstevel D_PRINTF("\nIO Card [%s] dev_no [%d] SlotStr "
90203831d35Sstevel "[%s] slot [%s]", name, card.dev_no,
90303831d35Sstevel slot_name_arr[card.dev_no],
90403831d35Sstevel card.slot_str);
905*6fb59094SToomas Soome }
90603831d35Sstevel
90703831d35Sstevel /* XXX - Don't know how to get status for PCI cards */
90803831d35Sstevel card.status[0] = '\0';
90903831d35Sstevel
91003831d35Sstevel /* Get the model of this card */
91103831d35Sstevel get_pci_card_model(card_node, (char *)&card.model);
91203831d35Sstevel
91303831d35Sstevel /*
91403831d35Sstevel * If we haven't figured out the frequency yet,
91503831d35Sstevel * try and get it from the card.
91603831d35Sstevel */
91703831d35Sstevel value = get_prop_val(find_prop(pci, "clock-frequency"));
91803831d35Sstevel if (value != NULL && card.freq == -1)
91903831d35Sstevel card.freq = ((*(int *)value) + 500000)
920*6fb59094SToomas Soome / 1000000;
92103831d35Sstevel
92203831d35Sstevel
92303831d35Sstevel /* Figure out how we want to display the name */
92403831d35Sstevel create_io_card_name(card_node, name,
925*6fb59094SToomas Soome (char *)&card.name);
92603831d35Sstevel
92703831d35Sstevel if (card.freq != -1)
92803831d35Sstevel card_list = insert_io_card(card_list, &card);
92903831d35Sstevel
93003831d35Sstevel next_card:
93103831d35Sstevel /*
93203831d35Sstevel * If we are done with the children of the pci bridge,
93303831d35Sstevel * we must continue with the remaining siblings of
93403831d35Sstevel * the pci-to-pci bridge - otherwise we move onto our
93503831d35Sstevel * own sibling.
93603831d35Sstevel */
93703831d35Sstevel if (pci_pci_bridge) {
93803831d35Sstevel if (card_node->child != NULL)
93903831d35Sstevel card_node = card_node->child;
94003831d35Sstevel else
94103831d35Sstevel card_node = card_node->sibling;
94203831d35Sstevel } else {
94303831d35Sstevel if ((card_node->parent == pci_bridge_node) &&
94403831d35Sstevel (card_node->sibling == NULL))
94503831d35Sstevel card_node = pci_bridge_node->sibling;
94603831d35Sstevel else
94703831d35Sstevel card_node = card_node->sibling;
94803831d35Sstevel }
94903831d35Sstevel } /* end-while */
95003831d35Sstevel } /* end-for */
95103831d35Sstevel
95203831d35Sstevel D_PRINTF("\n\n");
95303831d35Sstevel
95403831d35Sstevel display_io_cards(card_list);
95503831d35Sstevel free_io_cards(card_list);
95603831d35Sstevel }
95703831d35Sstevel
95803831d35Sstevel void
get_slot_number_str(struct io_card * card,char ** slot_name_arr,int slot_name_bits)95903831d35Sstevel get_slot_number_str(struct io_card *card, char **slot_name_arr,
960*6fb59094SToomas Soome int slot_name_bits)
96103831d35Sstevel {
96203831d35Sstevel if (card->dev_no != -1) {
96303831d35Sstevel char *slot;
96403831d35Sstevel /*
96503831d35Sstevel * slot_name_bits is a mask of the plug-in slots so if our
96603831d35Sstevel * dev_no does not appear in this mask we must be an
96703831d35Sstevel * on_board device so set the slot to 'On-Board'
96803831d35Sstevel */
96903831d35Sstevel if (slot_name_bits & (1 << card->dev_no)) {
97003831d35Sstevel /* we are a plug-in card */
97103831d35Sstevel slot = slot_name_arr[card->dev_no];
97203831d35Sstevel if (strlen(slot) != 0) {
97303831d35Sstevel (void) sprintf(card->slot_str, "%s",
97403831d35Sstevel slot);
97503831d35Sstevel } else
97603831d35Sstevel (void) sprintf(card->slot_str, "-");
97703831d35Sstevel } else {
97803831d35Sstevel /* this is an on-board dev. */
979*6fb59094SToomas Soome (void) sprintf(card->slot_str, "On-Board");
98003831d35Sstevel }
98103831d35Sstevel
98203831d35Sstevel } else {
98303831d35Sstevel (void) sprintf(card->slot_str, "%c", '-');
98403831d35Sstevel }
98503831d35Sstevel
98603831d35Sstevel /* Informs display_io_cards to print slot_str instead of slot */
98703831d35Sstevel card->slot = PCI_SLOT_IS_STRING;
98803831d35Sstevel }
98903831d35Sstevel
99003831d35Sstevel
99103831d35Sstevel /*
99203831d35Sstevel * The output of a number of I/O cards are identical so we need to
99303831d35Sstevel * differentiate between them.
99403831d35Sstevel *
99503831d35Sstevel * This function is called by the platform specific code and it decides
99603831d35Sstevel * if the card needs further processing.
99703831d35Sstevel *
99803831d35Sstevel * It can be extended in the future if card types other than QLC have
99903831d35Sstevel * the same problems.
100003831d35Sstevel */
100103831d35Sstevel void
distinguish_identical_io_cards(char * name,Prom_node * node,struct io_card * card)100203831d35Sstevel distinguish_identical_io_cards(char *name, Prom_node *node,
1003*6fb59094SToomas Soome struct io_card *card)
100403831d35Sstevel {
100503831d35Sstevel if ((name == NULL) || (node == NULL))
100603831d35Sstevel return;
100703831d35Sstevel
100803831d35Sstevel if (strcmp(name, "SUNW,qlc") == 0)
100903831d35Sstevel decode_qlc_card_model_prop(node, card);
101003831d35Sstevel }
101103831d35Sstevel
101203831d35Sstevel
101303831d35Sstevel /*
101403831d35Sstevel * The name/model properties for a number of the QLC FCAL PCI cards are
101503831d35Sstevel * identical (*), so we need to distinguish them using the subsystem-id
101603831d35Sstevel * and modify the model string to be more informative.
101703831d35Sstevel *
101803831d35Sstevel * (*) Currently the problem cards are:
101903831d35Sstevel * Amber
102003831d35Sstevel * Crystal+
102103831d35Sstevel */
102203831d35Sstevel void
decode_qlc_card_model_prop(Prom_node * card_node,struct io_card * card)102303831d35Sstevel decode_qlc_card_model_prop(Prom_node *card_node, struct io_card *card)
102403831d35Sstevel {
102503831d35Sstevel void *value = NULL;
102603831d35Sstevel
102703831d35Sstevel if (card_node == NULL)
102803831d35Sstevel return;
102903831d35Sstevel
103003831d35Sstevel value = get_prop_val(find_prop(card_node, "subsystem-id"));
103103831d35Sstevel if (value != NULL) {
103203831d35Sstevel int id = *(int *)value;
103303831d35Sstevel
103403831d35Sstevel switch (id) {
103503831d35Sstevel case AMBER_SUBSYSTEM_ID:
103603831d35Sstevel (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
1037*6fb59094SToomas Soome AMBER_CARD_NAME);
103803831d35Sstevel break;
103903831d35Sstevel
104003831d35Sstevel case CRYSTAL_SUBSYSTEM_ID:
104103831d35Sstevel (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
1042*6fb59094SToomas Soome CRYSTAL_CARD_NAME);
104303831d35Sstevel break;
104403831d35Sstevel
104503831d35Sstevel default:
104603831d35Sstevel /*
104703831d35Sstevel * If information has been saved into the model field
104803831d35Sstevel * before this function was called we will keep it as
104903831d35Sstevel * it probably will be more meaningful that the
105003831d35Sstevel * subsystem-id, otherwise we save the subsystem-id in
105103831d35Sstevel * the hope that it will distinguish the cards.
105203831d35Sstevel */
105303831d35Sstevel if (strcmp(card->model, "") == 0) {
105403831d35Sstevel (void) snprintf(card->model, MAX_QLC_MODEL_LEN,
1055*6fb59094SToomas Soome "0x%x", id);
105603831d35Sstevel }
105703831d35Sstevel break;
105803831d35Sstevel }
105903831d35Sstevel }
106003831d35Sstevel }
1061