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