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 *
find_pci_bus(Prom_node * node,int id,int bus)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
get_pci_bus(Prom_node * pnode)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
get_pci_device(Prom_node * pnode)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
get_pci_to_pci_device(Prom_node * pnode)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
free_io_cards(struct io_card * card_list)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 *
insert_io_card(struct io_card * list,struct io_card * 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 *
fmt_manf_id(unsigned int encoded_id,char * outbuf)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
get_sbus_slot(Prom_node * pnode)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
display_io_devices(Sys_tree * tree)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
display_pci(Board_node * bnode)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
display_io_cards(struct io_card * list)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
display_ffb(Board_node * board,int table)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
display_sbus(Board_node * board)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
populate_slot_name_arr(Prom_node * pci,int * slot_name_bits,char ** slot_name_arr,int num_slots)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
get_card_frequency(Prom_node * pci)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
get_dev_func_num(Prom_node * card_node,int * dev_no,int * func_no)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
get_pci_class_codes(Prom_node * card_node,int * class_code,int * subclass_code)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
is_pci_bridge(Prom_node * card_node,char * name)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
is_pci_bridge_other(Prom_node * card_node,char * name)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
get_pci_card_model(Prom_node * card_node,char * model)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
create_io_card_name(Prom_node * card_node,char * name,char * card_name)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
display_psycho_pci(Board_node * board)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
get_slot_number_str(struct io_card * card,char ** slot_name_arr,int slot_name_bits)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
distinguish_identical_io_cards(char * name,Prom_node * node,struct io_card * card)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
decode_qlc_card_model_prop(Prom_node * card_node,struct io_card * card)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