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 2000, 2003 Sun Microsystems, Inc.  All rights reserved.
24*03831d35Sstevel  * Use is subject to license terms.
25*03831d35Sstevel  *
26*03831d35Sstevel  * Daktari Platform specific functions.
27*03831d35Sstevel  */
28*03831d35Sstevel 
29*03831d35Sstevel #include <libdevinfo.h>
30*03831d35Sstevel #include <alloca.h>
31*03831d35Sstevel #include <inttypes.h>
32*03831d35Sstevel #include <libprtdiag.h>
33*03831d35Sstevel #include <sys/mc.h>
34*03831d35Sstevel 
35*03831d35Sstevel #define	EXIT_MSG(msg, err) \
36*03831d35Sstevel 	{ printf("\n%s failed with %d\n", msg, err); exit(err); }
37*03831d35Sstevel 
38*03831d35Sstevel /* we only need the 5 LSB of the portid to calculate the board number */
39*03831d35Sstevel #define	DAK_SAFARI_ID_MASK		0x1F	/* 5 bits */
40*03831d35Sstevel #define	DAK_NODE_MASK			0x1F	/* 5 bits */
41*03831d35Sstevel #define	DAK_PORTID_NODE_SHIFT		5
42*03831d35Sstevel #define	DAK_MIN_CPU_SAFARI_ID		0	/* 0x00 */
43*03831d35Sstevel #define	DAK_MAX_CPU_SAFARI_ID		23	/* 0x17 */
44*03831d35Sstevel #define	DAK_MIN_IO_SAFARI_ID		24	/* 0x18 */
45*03831d35Sstevel #define	DAK_MAX_IO_SAFARI_ID		31	/* 0x1F */
46*03831d35Sstevel #define	NUM_MBANKS_PER_MC		4
47*03831d35Sstevel 
48*03831d35Sstevel #define	DAK_CLK_FREQ_TO_MHZ(x)	(((x) + 500000) / 1000000)
49*03831d35Sstevel 
50*03831d35Sstevel /*
51*03831d35Sstevel  * DAK_PORTID_IS_CPU_TYPE
52*03831d35Sstevel  *
53*03831d35Sstevel  * If the portid associated with a CPU board is passed in, TRUE is returned,
54*03831d35Sstevel  * otherwise FALSE.
55*03831d35Sstevel  */
56*03831d35Sstevel #define	DAK_PORTID_IS_CPU_TYPE(portid) \
57*03831d35Sstevel 	(((((portid) & DAK_SAFARI_ID_MASK) >= DAK_MIN_CPU_SAFARI_ID) && \
58*03831d35Sstevel 	(((portid) & DAK_SAFARI_ID_MASK) <= DAK_MAX_CPU_SAFARI_ID)) ? \
59*03831d35Sstevel 								TRUE: FALSE)
60*03831d35Sstevel /*
61*03831d35Sstevel  * DAK_CPU_BD_PORTID_TO_BD_NUM
62*03831d35Sstevel  *
63*03831d35Sstevel  * If the portid associated with a CPU board is passed in, the board number
64*03831d35Sstevel  * associated with this portid is returned, otherwise -1.
65*03831d35Sstevel  */
66*03831d35Sstevel #define	DAK_CPU_BD_PORTID_TO_BD_NUM(portid) \
67*03831d35Sstevel 	((DAK_PORTID_IS_CPU_TYPE(portid)) ? \
68*03831d35Sstevel 		(((portid) & DAK_SAFARI_ID_MASK) / 4) : (-1))
69*03831d35Sstevel 
70*03831d35Sstevel /*
71*03831d35Sstevel  * DAK_PORTID_IS_IO_TYPE
72*03831d35Sstevel  *
73*03831d35Sstevel  * If the portid associated with an IO board is passed in, TRUE is returned,
74*03831d35Sstevel  * otherwise FALSE.
75*03831d35Sstevel  */
76*03831d35Sstevel #define	DAK_PORTID_IS_IO_TYPE(portid) \
77*03831d35Sstevel 	(((((portid) & DAK_SAFARI_ID_MASK) >= DAK_MIN_IO_SAFARI_ID) && \
78*03831d35Sstevel 	(((portid) & DAK_SAFARI_ID_MASK) <= DAK_MAX_IO_SAFARI_ID)) ? \
79*03831d35Sstevel 								TRUE: FALSE)
80*03831d35Sstevel 
81*03831d35Sstevel /*
82*03831d35Sstevel  * DAK_IO_BD_PORTID_TO_BD_NUM
83*03831d35Sstevel  *
84*03831d35Sstevel  * If the portid associated with an IO board is passed in, the board number
85*03831d35Sstevel  * associated with this portid is returned, otherwise -1.
86*03831d35Sstevel  */
87*03831d35Sstevel #define	DAK_IO_BD_PORTID_TO_BD_NUM(portid) \
88*03831d35Sstevel 	(DAK_PORTID_IS_IO_TYPE(portid) ? \
89*03831d35Sstevel 		(((((portid) & DAK_SAFARI_ID_MASK) - 24) / 2) + 6) : (-1))
90*03831d35Sstevel 
91*03831d35Sstevel /*
92*03831d35Sstevel  * DAK_PORTID_TO_BOARD_NUM
93*03831d35Sstevel  *
94*03831d35Sstevel  * If a valid portid is passed in, this macro returns the board number
95*03831d35Sstevel  * associated with it, otherwise it returns -1.
96*03831d35Sstevel  */
97*03831d35Sstevel 
98*03831d35Sstevel #define	DAK_PORTID_TO_BOARD_NUM(portid) \
99*03831d35Sstevel 	((DAK_PORTID_IS_CPU_TYPE(portid)) ? \
100*03831d35Sstevel 		(DAK_CPU_BD_PORTID_TO_BD_NUM(portid)) : \
101*03831d35Sstevel 	((DAK_PORTID_IS_IO_TYPE(portid)) ? \
102*03831d35Sstevel 		DAK_IO_BD_PORTID_TO_BD_NUM(portid) : (-1)))
103*03831d35Sstevel 
104*03831d35Sstevel 
105*03831d35Sstevel /* Local Functions */
106*03831d35Sstevel char	*get_node_name(Prom_node *pnode);
107*03831d35Sstevel char	*get_node_type(Prom_node *pnode);
108*03831d35Sstevel void	 add_node(Sys_tree *root, Prom_node *pnode);
109*03831d35Sstevel Prop	*find_prop(Prom_node *pnode, char *name);
110*03831d35Sstevel int	 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
111*03831d35Sstevel void	*get_prop_val(Prop *prop);
112*03831d35Sstevel char    *get_node_type(Prom_node *pnode);
113*03831d35Sstevel int	 get_us3_mem_regs(Board_node *bnode);
114*03831d35Sstevel 
115*03831d35Sstevel void	 fill_pci_card_list(Prom_node *pci_instance,
116*03831d35Sstevel 			    Prom_node *pci_card_node,
117*03831d35Sstevel 			    struct io_card *pci_card,
118*03831d35Sstevel 			    struct io_card **pci_card_list,
119*03831d35Sstevel 			    char **pci_slot_name_arr);
120*03831d35Sstevel 
121*03831d35Sstevel static Prom_node	*next_pci_card(Prom_node *curr_card, int *is_bridge,
122*03831d35Sstevel 				int is_pcidev, Prom_node *curr_bridge,
123*03831d35Sstevel 				Prom_node * parent_bridge, Prom_node *pci);
124*03831d35Sstevel 
125*03831d35Sstevel static	Prom_node *dev_next_node_by_compat(Prom_node *root, char *compat);
126*03831d35Sstevel static	Prom_node *dev_find_node_by_compat(Prom_node *root, char *compat);
127*03831d35Sstevel static Board_node *daktari_insert_board(Sys_tree *root, int board);
128*03831d35Sstevel static Board_node *daktari_find_board(Sys_tree *root, int board);
129*03831d35Sstevel 
130*03831d35Sstevel static    int32_t find_child_device(picl_nodehdl_t, char *, picl_nodehdl_t *);
131*03831d35Sstevel static    int32_t fill_device_from_id(picl_nodehdl_t, char *, picl_nodehdl_t *);
132*03831d35Sstevel static    int32_t fill_device_array_from_id(picl_nodehdl_t, char *, int32_t *,
133*03831d35Sstevel 				picl_nodehdl_t **);
134*03831d35Sstevel 
135*03831d35Sstevel /* Overlaying routines */
136*03831d35Sstevel 
137*03831d35Sstevel /*
138*03831d35Sstevel  * This function searches through the properties of the node passed in
139*03831d35Sstevel  * and returns a pointer to the value of the name property.
140*03831d35Sstevel  */
141*03831d35Sstevel char *
get_node_name(Prom_node * pnode)142*03831d35Sstevel get_node_name(Prom_node *pnode)
143*03831d35Sstevel {
144*03831d35Sstevel 	Prop *prop;
145*03831d35Sstevel 
146*03831d35Sstevel 	if (pnode == NULL)
147*03831d35Sstevel 	    return (NULL);
148*03831d35Sstevel 
149*03831d35Sstevel 	prop = pnode->props;
150*03831d35Sstevel 	while (prop != NULL) {
151*03831d35Sstevel 		if (strcmp("name", (char *)prop->name.val_ptr) == 0)
152*03831d35Sstevel 			return (prop->value.val_ptr);
153*03831d35Sstevel 		prop = prop->next;
154*03831d35Sstevel 	}
155*03831d35Sstevel 	return (NULL);
156*03831d35Sstevel }
157*03831d35Sstevel 
158*03831d35Sstevel /*
159*03831d35Sstevel  * This function searches through the properties of the node passed in
160*03831d35Sstevel  * and returns a pointer to the value of the name property.
161*03831d35Sstevel  */
162*03831d35Sstevel char *
get_node_type(Prom_node * pnode)163*03831d35Sstevel get_node_type(Prom_node *pnode)
164*03831d35Sstevel {
165*03831d35Sstevel 	Prop	*prop;
166*03831d35Sstevel 
167*03831d35Sstevel 	if (pnode == NULL) {
168*03831d35Sstevel 		return (NULL);
169*03831d35Sstevel 	}
170*03831d35Sstevel 
171*03831d35Sstevel 	prop = pnode->props;
172*03831d35Sstevel 	while (prop != NULL) {
173*03831d35Sstevel 		if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
174*03831d35Sstevel 			return (prop->value.val_ptr);
175*03831d35Sstevel 		prop = prop->next;
176*03831d35Sstevel 	}
177*03831d35Sstevel 	return (NULL);
178*03831d35Sstevel }
179*03831d35Sstevel 
180*03831d35Sstevel /*
181*03831d35Sstevel  * add_node
182*03831d35Sstevel  *
183*03831d35Sstevel  * This function adds a board node to the board structure where that
184*03831d35Sstevel  * that node's physical component lives.
185*03831d35Sstevel  */
186*03831d35Sstevel void
add_node(Sys_tree * root,Prom_node * pnode)187*03831d35Sstevel add_node(Sys_tree *root, Prom_node *pnode)
188*03831d35Sstevel {
189*03831d35Sstevel 	int		board	= -1;
190*03831d35Sstevel 	int		portid	= -1;
191*03831d35Sstevel 
192*03831d35Sstevel 	void		*value	= NULL;
193*03831d35Sstevel 	Board_node	*bnode	= NULL;
194*03831d35Sstevel 	Prom_node	*p	= NULL;
195*03831d35Sstevel 
196*03831d35Sstevel 	/* Get the board number of this board from the portid prop */
197*03831d35Sstevel 	value = get_prop_val(find_prop(pnode, "portid"));
198*03831d35Sstevel 	if (value != NULL) {
199*03831d35Sstevel 		portid = *(int *)value;
200*03831d35Sstevel 	}
201*03831d35Sstevel 	board	= DAK_PORTID_TO_BOARD_NUM(portid);
202*03831d35Sstevel 	/*	board = DAK_GETSLOT(portid); */
203*03831d35Sstevel 	/* find the board node with the same board number */
204*03831d35Sstevel 	if ((bnode = daktari_find_board(root, board)) == NULL) {
205*03831d35Sstevel 		bnode = daktari_insert_board(root, board);
206*03831d35Sstevel 	}
207*03831d35Sstevel 
208*03831d35Sstevel 	/* now attach this prom node to the board list */
209*03831d35Sstevel 	/* Insert this node at the end of the list */
210*03831d35Sstevel 	pnode->sibling = NULL;
211*03831d35Sstevel 	if (bnode->nodes == NULL)
212*03831d35Sstevel 		bnode->nodes = pnode;
213*03831d35Sstevel 	else {
214*03831d35Sstevel 		p = bnode->nodes;
215*03831d35Sstevel 		while (p->sibling != NULL)
216*03831d35Sstevel 			p = p->sibling;
217*03831d35Sstevel 		p->sibling = pnode;
218*03831d35Sstevel 	}
219*03831d35Sstevel }
220*03831d35Sstevel 
221*03831d35Sstevel /*
222*03831d35Sstevel  * Search a Prom node and retrieve the property with the correct
223*03831d35Sstevel  * name.
224*03831d35Sstevel  */
225*03831d35Sstevel Prop *
find_prop(Prom_node * pnode,char * name)226*03831d35Sstevel find_prop(Prom_node *pnode, char *name)
227*03831d35Sstevel {
228*03831d35Sstevel 	Prop	*prop;
229*03831d35Sstevel 
230*03831d35Sstevel 	if (pnode  == NULL)
231*03831d35Sstevel 	    return (NULL);
232*03831d35Sstevel 
233*03831d35Sstevel 	if (pnode->props == NULL)
234*03831d35Sstevel 	    return (NULL);
235*03831d35Sstevel 
236*03831d35Sstevel 	prop = pnode->props;
237*03831d35Sstevel 
238*03831d35Sstevel 	if (prop == NULL)
239*03831d35Sstevel 	    return (NULL);
240*03831d35Sstevel 
241*03831d35Sstevel 	if (prop->name.val_ptr == NULL)
242*03831d35Sstevel 	    return (NULL);
243*03831d35Sstevel 
244*03831d35Sstevel 	while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) {
245*03831d35Sstevel 		prop = prop->next;
246*03831d35Sstevel 	}
247*03831d35Sstevel 	return (prop);
248*03831d35Sstevel }
249*03831d35Sstevel 
250*03831d35Sstevel int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)251*03831d35Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
252*03831d35Sstevel {
253*03831d35Sstevel 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
254*03831d35Sstevel }
255*03831d35Sstevel 
256*03831d35Sstevel 
257*03831d35Sstevel /*
258*03831d35Sstevel  * return the property value for the Prop
259*03831d35Sstevel  * passed in.
260*03831d35Sstevel  */
261*03831d35Sstevel void *
get_prop_val(Prop * prop)262*03831d35Sstevel get_prop_val(Prop *prop)
263*03831d35Sstevel {
264*03831d35Sstevel 	if (prop == NULL)
265*03831d35Sstevel 	    return (NULL);
266*03831d35Sstevel 
267*03831d35Sstevel 	return ((void *)(prop->value.val_ptr));
268*03831d35Sstevel }
269*03831d35Sstevel 
270*03831d35Sstevel /* Local Routines */
271*03831d35Sstevel 
272*03831d35Sstevel /*
273*03831d35Sstevel  * Start from the current node and return the next node besides
274*03831d35Sstevel  * the current one which has the requested model property.
275*03831d35Sstevel  */
276*03831d35Sstevel static Prom_node *
dev_next_node_by_compat(Prom_node * root,char * compat)277*03831d35Sstevel dev_next_node_by_compat(Prom_node *root, char *compat)
278*03831d35Sstevel {
279*03831d35Sstevel 	Prom_node *node;
280*03831d35Sstevel 
281*03831d35Sstevel 	if (root == NULL)
282*03831d35Sstevel 	    return (NULL);
283*03831d35Sstevel 
284*03831d35Sstevel 	/* look at your children first */
285*03831d35Sstevel 	if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
286*03831d35Sstevel 	    return (node);
287*03831d35Sstevel 
288*03831d35Sstevel 	/* now look at your siblings */
289*03831d35Sstevel 	if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
290*03831d35Sstevel 	    return (node);
291*03831d35Sstevel 
292*03831d35Sstevel 	return (NULL);  /* not found */
293*03831d35Sstevel }
294*03831d35Sstevel 
295*03831d35Sstevel /*
296*03831d35Sstevel  * Do a depth-first walk of a device tree and
297*03831d35Sstevel  * return the first node with the matching model.
298*03831d35Sstevel  */
299*03831d35Sstevel static Prom_node *
dev_find_node_by_compat(Prom_node * root,char * compat)300*03831d35Sstevel dev_find_node_by_compat(Prom_node *root, char *compat)
301*03831d35Sstevel {
302*03831d35Sstevel 	Prom_node	*node;
303*03831d35Sstevel 	char		*compatible;
304*03831d35Sstevel 	char		*name;
305*03831d35Sstevel 
306*03831d35Sstevel 	if (root == NULL)
307*03831d35Sstevel 		return (NULL);
308*03831d35Sstevel 
309*03831d35Sstevel 	if (compat == NULL)
310*03831d35Sstevel 		return (NULL);
311*03831d35Sstevel 
312*03831d35Sstevel 	name = get_node_name(root);
313*03831d35Sstevel 	if (name == NULL)
314*03831d35Sstevel 		name = "";
315*03831d35Sstevel 
316*03831d35Sstevel 	compatible = (char *)get_prop_val(find_prop(root, "compatible"));
317*03831d35Sstevel 
318*03831d35Sstevel 	if (compatible == NULL)
319*03831d35Sstevel 	    return (NULL);
320*03831d35Sstevel 
321*03831d35Sstevel 	if ((strcmp(name, "pci") == 0) && (compatible != NULL) &&
322*03831d35Sstevel 	    (strcmp(compatible, compat) == 0)) {
323*03831d35Sstevel 		return (root); /* found a match */
324*03831d35Sstevel 	}
325*03831d35Sstevel 
326*03831d35Sstevel 	/* look at your children first */
327*03831d35Sstevel 	if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
328*03831d35Sstevel 	    return (node);
329*03831d35Sstevel 
330*03831d35Sstevel 	/* now look at your siblings */
331*03831d35Sstevel 	if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
332*03831d35Sstevel 	    return (node);
333*03831d35Sstevel 
334*03831d35Sstevel 	return (NULL);  /* not found */
335*03831d35Sstevel }
336*03831d35Sstevel 
337*03831d35Sstevel 
338*03831d35Sstevel /*
339*03831d35Sstevel  * Add a board to the system list in order (sorted by board#).
340*03831d35Sstevel  * Initialize all pointer fields to NULL.
341*03831d35Sstevel  */
342*03831d35Sstevel static Board_node *
daktari_insert_board(Sys_tree * root,int board)343*03831d35Sstevel daktari_insert_board(Sys_tree *root, int board)
344*03831d35Sstevel {
345*03831d35Sstevel 	Board_node	*bnode;
346*03831d35Sstevel 	Board_node	*temp = root->bd_list;
347*03831d35Sstevel 
348*03831d35Sstevel 	if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
349*03831d35Sstevel 		perror("malloc");
350*03831d35Sstevel 		exit(1);
351*03831d35Sstevel 	}
352*03831d35Sstevel 
353*03831d35Sstevel 	bnode->nodes		= NULL;
354*03831d35Sstevel 	bnode->next		= NULL;
355*03831d35Sstevel 	bnode->board_num	= board;
356*03831d35Sstevel 	bnode->board_type	= UNKNOWN_BOARD;
357*03831d35Sstevel 
358*03831d35Sstevel 	if (temp == NULL)
359*03831d35Sstevel 	    root->bd_list = bnode;
360*03831d35Sstevel 
361*03831d35Sstevel 	else if (temp->board_num > board) {
362*03831d35Sstevel 		bnode->next = temp;
363*03831d35Sstevel 		root->bd_list = bnode;
364*03831d35Sstevel 
365*03831d35Sstevel 	} else {
366*03831d35Sstevel 		while ((temp->next != NULL) && (board > temp->next->board_num))
367*03831d35Sstevel 			temp = temp->next;
368*03831d35Sstevel 
369*03831d35Sstevel 		bnode->next = temp->next;
370*03831d35Sstevel 		temp->next = bnode;
371*03831d35Sstevel 	}
372*03831d35Sstevel 	root->board_cnt++;
373*03831d35Sstevel 
374*03831d35Sstevel 	return (bnode);
375*03831d35Sstevel }
376*03831d35Sstevel 
377*03831d35Sstevel /*
378*03831d35Sstevel  * Find the requested board struct in the system device tree.
379*03831d35Sstevel  *
380*03831d35Sstevel  * This function overrides the functionality of the generic find_board()
381*03831d35Sstevel  * function in libprtdiag, but since we need to pass another parameter,
382*03831d35Sstevel  * we cannot simply overlay the symbol table.
383*03831d35Sstevel  */
384*03831d35Sstevel static Board_node *
daktari_find_board(Sys_tree * root,int board)385*03831d35Sstevel daktari_find_board(Sys_tree *root, int board)
386*03831d35Sstevel {
387*03831d35Sstevel 	Board_node *bnode = root->bd_list;
388*03831d35Sstevel 
389*03831d35Sstevel 	while ((bnode != NULL) && (board != bnode->board_num)) {
390*03831d35Sstevel 		bnode = bnode->next;
391*03831d35Sstevel 	}
392*03831d35Sstevel 	return (bnode);
393*03831d35Sstevel }
394*03831d35Sstevel 
395*03831d35Sstevel 
396*03831d35Sstevel int32_t
find_child_device(picl_nodehdl_t parent,char * child_name,picl_nodehdl_t * child)397*03831d35Sstevel find_child_device(picl_nodehdl_t parent, char *child_name,
398*03831d35Sstevel 		picl_nodehdl_t *child)
399*03831d35Sstevel {
400*03831d35Sstevel 	int32_t		err;
401*03831d35Sstevel 	char		name[PICL_PROPNAMELEN_MAX];
402*03831d35Sstevel 
403*03831d35Sstevel 	err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child),
404*03831d35Sstevel 		sizeof (picl_nodehdl_t));
405*03831d35Sstevel 	switch (err) {
406*03831d35Sstevel 	case PICL_SUCCESS:
407*03831d35Sstevel 		break;
408*03831d35Sstevel 	case PICL_PROPNOTFOUND:
409*03831d35Sstevel 		err = PICL_INVALIDHANDLE;
410*03831d35Sstevel 		return (err);
411*03831d35Sstevel 	default:
412*03831d35Sstevel #ifdef WORKFILE_DEBUG
413*03831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
414*03831d35Sstevel 			"Failed picl_get_propval_by_name with %s\n"),
415*03831d35Sstevel 			picl_strerror(err));
416*03831d35Sstevel #endif
417*03831d35Sstevel 		return (err);
418*03831d35Sstevel 	}
419*03831d35Sstevel 
420*03831d35Sstevel 	err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name,
421*03831d35Sstevel 		PICL_PROPNAMELEN_MAX);
422*03831d35Sstevel 
423*03831d35Sstevel #ifdef WORKFILE_DEBUG
424*03831d35Sstevel 	if (err != PICL_SUCCESS) {
425*03831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
426*03831d35Sstevel 			"failed the get name for root\n"), 0);
427*03831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN, "%s\n"),
428*03831d35Sstevel 			picl_strerror(err), 0);
429*03831d35Sstevel 	}
430*03831d35Sstevel #endif
431*03831d35Sstevel 
432*03831d35Sstevel 	if (strcmp(name, child_name) == 0)
433*03831d35Sstevel 		return (err);
434*03831d35Sstevel 
435*03831d35Sstevel 	while (err != PICL_PROPNOTFOUND) {
436*03831d35Sstevel 		err = picl_get_propval_by_name(*child, PICL_PROP_PEER,
437*03831d35Sstevel 			&(*child), sizeof (picl_nodehdl_t));
438*03831d35Sstevel 		switch (err) {
439*03831d35Sstevel 		case PICL_SUCCESS:
440*03831d35Sstevel 			err = picl_get_propval_by_name(*child, PICL_PROP_NAME,
441*03831d35Sstevel 				name, PICL_PROPNAMELEN_MAX);
442*03831d35Sstevel 			if (strcmp(name, child_name) == 0)
443*03831d35Sstevel 				return (err);
444*03831d35Sstevel 			break;
445*03831d35Sstevel 		case PICL_PROPNOTFOUND:
446*03831d35Sstevel 			break;
447*03831d35Sstevel 		default:
448*03831d35Sstevel #ifdef WORKFILE_DEBUG
449*03831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
450*03831d35Sstevel 				"Failed picl_get_propval_by_name with %s\n"),
451*03831d35Sstevel 				picl_strerror(err), 0);
452*03831d35Sstevel #endif
453*03831d35Sstevel 			return (err);
454*03831d35Sstevel 		}
455*03831d35Sstevel 	}
456*03831d35Sstevel 	err = PICL_INVALIDHANDLE;
457*03831d35Sstevel 	return (err);
458*03831d35Sstevel }
459*03831d35Sstevel 
460*03831d35Sstevel int32_t
fill_device_from_id(picl_nodehdl_t device_id,char * assoc_id,picl_nodehdl_t * device)461*03831d35Sstevel fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id,
462*03831d35Sstevel 		picl_nodehdl_t *device)
463*03831d35Sstevel {
464*03831d35Sstevel 	int32_t err;
465*03831d35Sstevel 	picl_prophdl_t tbl_hdl;
466*03831d35Sstevel 	picl_prophdl_t reference_property;
467*03831d35Sstevel 
468*03831d35Sstevel 	err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
469*03831d35Sstevel 		sizeof (picl_prophdl_t));
470*03831d35Sstevel 	if (err != PICL_SUCCESS) {
471*03831d35Sstevel #ifdef WORKFILE_DEBUG
472*03831d35Sstevel 		if (err != PICL_INVALIDHANDLE) {
473*03831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
474*03831d35Sstevel 				"fill_device_from_id failure in "
475*03831d35Sstevel 				"picl_get_propval_by_name err is %s\n"),
476*03831d35Sstevel 					picl_strerror(err), 0);
477*03831d35Sstevel 		}
478*03831d35Sstevel #endif
479*03831d35Sstevel 		return (err);
480*03831d35Sstevel 	}
481*03831d35Sstevel 
482*03831d35Sstevel 	err = picl_get_next_by_row(tbl_hdl, &reference_property);
483*03831d35Sstevel 	if (err != PICL_SUCCESS) {
484*03831d35Sstevel #ifdef WORKFILE_DEBUG
485*03831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
486*03831d35Sstevel 			"fill_device_from_id failure in picl_get_next_by_row"
487*03831d35Sstevel 			" err is %s\n"), picl_strerror(err), 0);
488*03831d35Sstevel #endif
489*03831d35Sstevel 		return (err);
490*03831d35Sstevel 	}
491*03831d35Sstevel 
492*03831d35Sstevel 	/* get node associated with reference property */
493*03831d35Sstevel 	err = picl_get_propval(reference_property, &(*device),
494*03831d35Sstevel 		sizeof (picl_nodehdl_t));
495*03831d35Sstevel 
496*03831d35Sstevel #ifdef WORKFILE_DEBUG
497*03831d35Sstevel 	if (err != 0) {
498*03831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
499*03831d35Sstevel 			"fill_device_from_id failure in picl_get_propval"
500*03831d35Sstevel 			" err is %s\n"), picl_strerror(err), 0);
501*03831d35Sstevel 	}
502*03831d35Sstevel #endif
503*03831d35Sstevel 	return (err);
504*03831d35Sstevel }
505*03831d35Sstevel 
506*03831d35Sstevel int32_t
fill_device_array_from_id(picl_nodehdl_t device_id,char * assoc_id,int32_t * number_of_devices,picl_nodehdl_t * device_array[])507*03831d35Sstevel fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id,
508*03831d35Sstevel 	int32_t *number_of_devices, picl_nodehdl_t *device_array[])
509*03831d35Sstevel {
510*03831d35Sstevel 	int32_t			err;
511*03831d35Sstevel 	int			i;
512*03831d35Sstevel 	picl_prophdl_t		tbl_hdl;
513*03831d35Sstevel 	picl_prophdl_t		entry;
514*03831d35Sstevel 	int			devs = 0;
515*03831d35Sstevel 	err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
516*03831d35Sstevel 		sizeof (picl_prophdl_t));
517*03831d35Sstevel 	if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
518*03831d35Sstevel #ifdef WORKFILE_DEBUG
519*03831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
520*03831d35Sstevel 			"fill_device_array_from_id failure in "
521*03831d35Sstevel 			"picl_get_propval_by_name err is %s\n"),
522*03831d35Sstevel 				picl_strerror(err), 0);
523*03831d35Sstevel #endif
524*03831d35Sstevel 		return (err);
525*03831d35Sstevel 	}
526*03831d35Sstevel 
527*03831d35Sstevel 	entry = tbl_hdl;
528*03831d35Sstevel 	while (picl_get_next_by_row(entry, &entry) == 0)
529*03831d35Sstevel 		++devs;
530*03831d35Sstevel 
531*03831d35Sstevel 	*device_array = calloc((devs), sizeof (picl_nodehdl_t));
532*03831d35Sstevel 	if (*device_array == NULL) {
533*03831d35Sstevel #ifdef WORKFILE_DEBUG
534*03831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
535*03831d35Sstevel 			"fill_device_array_from_id failure getting memory"
536*03831d35Sstevel 			" for array\n"), 0);
537*03831d35Sstevel #endif
538*03831d35Sstevel 		return (PICL_FAILURE);
539*03831d35Sstevel 	}
540*03831d35Sstevel 
541*03831d35Sstevel 	entry = tbl_hdl;
542*03831d35Sstevel 	for (i = 0; i < (devs); i++) {
543*03831d35Sstevel 		err = picl_get_next_by_row(entry, &entry);
544*03831d35Sstevel 		if (err != 0) {
545*03831d35Sstevel #ifdef WORKFILE_DEBUG
546*03831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
547*03831d35Sstevel 				"fill_device_array_from_id failure in "
548*03831d35Sstevel 				"picl_get_next_by_row err is %s\n"),
549*03831d35Sstevel 					picl_strerror(err), 0);
550*03831d35Sstevel #endif
551*03831d35Sstevel 			return (err);
552*03831d35Sstevel 		}
553*03831d35Sstevel 
554*03831d35Sstevel 		/* get node associated with reference property */
555*03831d35Sstevel 		err = picl_get_propval(entry, &((*device_array)[i]),
556*03831d35Sstevel 			sizeof (picl_nodehdl_t));
557*03831d35Sstevel 		if (err != 0) {
558*03831d35Sstevel #ifdef WORKFILE_DEBUG
559*03831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
560*03831d35Sstevel 				"fill_device_array_from_id failure in "
561*03831d35Sstevel 				"picl_get_propval err is %s\n"),
562*03831d35Sstevel 					picl_strerror(err), 0);
563*03831d35Sstevel #endif
564*03831d35Sstevel 			return (err);
565*03831d35Sstevel 		}
566*03831d35Sstevel 	}
567*03831d35Sstevel 	*number_of_devices = devs;
568*03831d35Sstevel 	return (err);
569*03831d35Sstevel }
570*03831d35Sstevel 
571*03831d35Sstevel /*
572*03831d35Sstevel  * This function provides formatting of the memory config
573*03831d35Sstevel  * information that get_us3_mem_regs() and display_us3_banks() code has
574*03831d35Sstevel  * gathered. It overrides the generic print_us3_memory_line() code
575*03831d35Sstevel  * which prints an error message.
576*03831d35Sstevel  */
577*03831d35Sstevel void
print_us3_memory_line(int portid,int bank_id,uint64_t bank_size,char * bank_status,uint64_t dimm_size,uint32_t intlv,int seg_id)578*03831d35Sstevel print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
579*03831d35Sstevel 	char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
580*03831d35Sstevel {
581*03831d35Sstevel 	int		mcid;
582*03831d35Sstevel 	mcid = portid;
583*03831d35Sstevel 
584*03831d35Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
585*03831d35Sstevel 		"\n  %-1c   %2d    %2d      %4lldMB   %11-s  %4lldMB "
586*03831d35Sstevel 		"   %2d-way        %d"),
587*03831d35Sstevel 			'A' + DAK_GETSLOT(portid), mcid, (bank_id % 4),
588*03831d35Sstevel 			bank_size, bank_status, dimm_size, intlv, seg_id, 0);
589*03831d35Sstevel }
590*03831d35Sstevel 
591*03831d35Sstevel 
592*03831d35Sstevel /*
593*03831d35Sstevel  * Fills in the i/o card list to be displayed later in display_pci();
594*03831d35Sstevel  */
595*03831d35Sstevel void
fill_pci_card_list(Prom_node * pci_instance,Prom_node * pci_card_node,struct io_card * pci_card,struct io_card ** pci_card_list,char ** slot_name_arr)596*03831d35Sstevel fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node,
597*03831d35Sstevel 			struct io_card *pci_card,
598*03831d35Sstevel 			struct io_card **pci_card_list, char **slot_name_arr)
599*03831d35Sstevel {
600*03831d35Sstevel 	Prom_node	*pci_bridge_node;
601*03831d35Sstevel 	Prom_node	*pci_parent_bridge;
602*03831d35Sstevel 	int		*int_val;
603*03831d35Sstevel 	int		pci_bridge = FALSE;
604*03831d35Sstevel 	int		pci_bridge_dev_no = -1;
605*03831d35Sstevel 	int		portid;
606*03831d35Sstevel 	int		pci_bus;
607*03831d35Sstevel 	char		buf[MAXSTRLEN];
608*03831d35Sstevel 	char		*slot_name = NULL;	/* info in "slot-names" prop */
609*03831d35Sstevel 	char		*child_name;
610*03831d35Sstevel 	char		*name;
611*03831d35Sstevel 	char		*type;
612*03831d35Sstevel 	void		*value;
613*03831d35Sstevel 
614*03831d35Sstevel 	while (pci_card_node != NULL) {
615*03831d35Sstevel 		int is_pci = FALSE;
616*03831d35Sstevel 		type = NULL;
617*03831d35Sstevel 		name = NULL;
618*03831d35Sstevel 		/* If it doesn't have a name, skip it */
619*03831d35Sstevel 		name = (char *)get_prop_val(
620*03831d35Sstevel 				find_prop(pci_card_node, "name"));
621*03831d35Sstevel 		if (name == NULL) {
622*03831d35Sstevel 			pci_card_node = pci_card_node->sibling;
623*03831d35Sstevel 			continue;
624*03831d35Sstevel 		}
625*03831d35Sstevel 
626*03831d35Sstevel 		/*
627*03831d35Sstevel 		 * Get the portid of the schizo that this card
628*03831d35Sstevel 		 * lives under.
629*03831d35Sstevel 		 */
630*03831d35Sstevel 		portid = -1;
631*03831d35Sstevel 		value = get_prop_val(find_prop(pci_instance, "portid"));
632*03831d35Sstevel 		if (value != NULL) {
633*03831d35Sstevel 			portid = *(int *)value;
634*03831d35Sstevel 		}
635*03831d35Sstevel 		pci_card->schizo_portid = portid;
636*03831d35Sstevel 		/*
637*03831d35Sstevel 		 * Find out whether this is PCI bus A or B
638*03831d35Sstevel 		 * using the 'reg' property.
639*03831d35Sstevel 		 */
640*03831d35Sstevel 		int_val = (int *)get_prop_val(find_prop(pci_instance, "reg"));
641*03831d35Sstevel 
642*03831d35Sstevel 		if (int_val != NULL) {
643*03831d35Sstevel 			int_val++; /* skip over first integer */
644*03831d35Sstevel 			pci_bus = ((*int_val) & 0x7f0000);
645*03831d35Sstevel 			if (pci_bus == 0x600000)
646*03831d35Sstevel 				pci_card->pci_bus = 'A';
647*03831d35Sstevel 			else if (pci_bus == 0x700000)
648*03831d35Sstevel 				pci_card->pci_bus = 'B';
649*03831d35Sstevel 			else
650*03831d35Sstevel 				pci_card->pci_bus = '-';
651*03831d35Sstevel 		} else {
652*03831d35Sstevel 			pci_card->pci_bus = '-';
653*03831d35Sstevel 		}
654*03831d35Sstevel 
655*03831d35Sstevel 		if ((pci_card->schizo_portid == 8) &&
656*03831d35Sstevel 		    (pci_card->pci_bus == 'A')) {
657*03831d35Sstevel 			pci_card_node = pci_card_node->sibling;
658*03831d35Sstevel 			continue;
659*03831d35Sstevel 		}
660*03831d35Sstevel 
661*03831d35Sstevel 		/*
662*03831d35Sstevel 		 * get dev# and func# for this card from the
663*03831d35Sstevel 		 * 'reg' property.
664*03831d35Sstevel 		 */
665*03831d35Sstevel 		int_val = (int *)get_prop_val(
666*03831d35Sstevel 			find_prop(pci_card_node, "reg"));
667*03831d35Sstevel 		if (int_val != NULL) {
668*03831d35Sstevel 			pci_card->dev_no = (((*int_val) & 0xF800) >> 11);
669*03831d35Sstevel 			pci_card->func_no = (((*int_val) & 0x700) >> 8);
670*03831d35Sstevel 		} else {
671*03831d35Sstevel 			pci_card->dev_no = -1;
672*03831d35Sstevel 			pci_card->func_no = -1;
673*03831d35Sstevel 		}
674*03831d35Sstevel 
675*03831d35Sstevel 		type = (char *)get_prop_val(
676*03831d35Sstevel 				find_prop(pci_card_node, "device_type"));
677*03831d35Sstevel 		/*
678*03831d35Sstevel 		 * If this is a pci-bridge, then store its dev#
679*03831d35Sstevel 		 * as its children nodes need this to get their slot#.
680*03831d35Sstevel 		 * We set the pci_bridge flag so that we know we are
681*03831d35Sstevel 		 * looking at a pci-bridge node. This flag gets reset
682*03831d35Sstevel 		 * every time we enter this while loop.
683*03831d35Sstevel 		 */
684*03831d35Sstevel 
685*03831d35Sstevel 		/*
686*03831d35Sstevel 		 * Check for a PCI-PCI Bridge for PCI and cPCI
687*03831d35Sstevel 		 * IO Boards using the name and type properties.
688*03831d35Sstevel 		 */
689*03831d35Sstevel 		if ((type != NULL) && (strncmp(name, "pci", 3) == 0) &&
690*03831d35Sstevel 		    (strcmp(type, "pci") == 0)) {
691*03831d35Sstevel 			pci_bridge_node = pci_card_node;
692*03831d35Sstevel 			is_pci = TRUE;
693*03831d35Sstevel 			if (!pci_bridge) {
694*03831d35Sstevel 				pci_bridge_dev_no = pci_card->dev_no;
695*03831d35Sstevel 				pci_parent_bridge = pci_bridge_node;
696*03831d35Sstevel 				pci_bridge = TRUE;
697*03831d35Sstevel 			}
698*03831d35Sstevel 		}
699*03831d35Sstevel 		if ((pci_card->pci_bus == 'B') && (pci_card->dev_no == 1) &&
700*03831d35Sstevel 		    (!pci_bridge)) {
701*03831d35Sstevel 			pci_card_node = pci_card_node->sibling;
702*03831d35Sstevel 			continue;
703*03831d35Sstevel 		}
704*03831d35Sstevel 
705*03831d35Sstevel 		/*
706*03831d35Sstevel 		 * Get slot-names property from slot_names_arr.
707*03831d35Sstevel 		 * If we are the child of a pci_bridge we use the
708*03831d35Sstevel 		 * dev# of the pci_bridge as an index to get
709*03831d35Sstevel 		 * the slot number. We know that we are a child of
710*03831d35Sstevel 		 * a pci-bridge if our parent is the same as the last
711*03831d35Sstevel 		 * pci_bridge node found above.
712*03831d35Sstevel 		 */
713*03831d35Sstevel 		if (pci_card->dev_no != -1) {
714*03831d35Sstevel 			/*
715*03831d35Sstevel 			 * We compare this cards parent node with the
716*03831d35Sstevel 			 * pci_bridge_node to see if it's a child.
717*03831d35Sstevel 			 */
718*03831d35Sstevel 			if (pci_card_node->parent != pci_instance &&
719*03831d35Sstevel 			    pci_bridge) {
720*03831d35Sstevel 				/* use dev_no of pci_bridge */
721*03831d35Sstevel 				if (pci_card->pci_bus == 'B') {
722*03831d35Sstevel 					slot_name =
723*03831d35Sstevel 					    slot_name_arr[pci_bridge_dev_no -2];
724*03831d35Sstevel 				} else {
725*03831d35Sstevel 					slot_name =
726*03831d35Sstevel 					    slot_name_arr[pci_bridge_dev_no -1];
727*03831d35Sstevel 				}
728*03831d35Sstevel 			} else {
729*03831d35Sstevel 				if (pci_card->pci_bus == 'B') {
730*03831d35Sstevel 				slot_name =
731*03831d35Sstevel 					slot_name_arr[pci_card->dev_no-2];
732*03831d35Sstevel 				} else {
733*03831d35Sstevel 				slot_name =
734*03831d35Sstevel 					slot_name_arr[pci_card->dev_no-1];
735*03831d35Sstevel 				}
736*03831d35Sstevel 			}
737*03831d35Sstevel 
738*03831d35Sstevel 			if (slot_name != NULL &&
739*03831d35Sstevel 			    strlen(slot_name) != 0) {
740*03831d35Sstevel 				/* Slot num is last char in string */
741*03831d35Sstevel 				(void) snprintf(pci_card->slot_str, MAXSTRLEN,
742*03831d35Sstevel 				    "%c", slot_name[strlen(slot_name) - 1]);
743*03831d35Sstevel 			} else {
744*03831d35Sstevel 				(void) snprintf(pci_card->slot_str, MAXSTRLEN,
745*03831d35Sstevel 				    "-");
746*03831d35Sstevel 			}
747*03831d35Sstevel 
748*03831d35Sstevel 		} else {
749*03831d35Sstevel 			(void) snprintf(pci_card->slot_str, MAXSTRLEN,
750*03831d35Sstevel 			    "%c", '-');
751*03831d35Sstevel 		}
752*03831d35Sstevel 
753*03831d35Sstevel 		/*
754*03831d35Sstevel 		 * Check for failed status.
755*03831d35Sstevel 		 */
756*03831d35Sstevel 		if (node_failed(pci_card_node))
757*03831d35Sstevel 			strcpy(pci_card->status, "fail");
758*03831d35Sstevel 		else
759*03831d35Sstevel 			strcpy(pci_card->status, "ok");
760*03831d35Sstevel 
761*03831d35Sstevel 		/* Get the model of this pci_card */
762*03831d35Sstevel 		value = get_prop_val(find_prop(pci_card_node, "model"));
763*03831d35Sstevel 		if (value == NULL)
764*03831d35Sstevel 			pci_card->model[0] = '\0';
765*03831d35Sstevel 		else {
766*03831d35Sstevel 			(void) snprintf(pci_card->model, MAXSTRLEN, "%s",
767*03831d35Sstevel 				(char *)value);
768*03831d35Sstevel 		}
769*03831d35Sstevel 		/*
770*03831d35Sstevel 		 * The card may have a "clock-frequency" but we
771*03831d35Sstevel 		 * are not interested in that. Instead we get the
772*03831d35Sstevel 		 * "clock-frequency" of the PCI Bus that the card
773*03831d35Sstevel 		 * resides on. PCI-A can operate at 33Mhz or 66Mhz
774*03831d35Sstevel 		 * depending on what card is plugged into the Bus.
775*03831d35Sstevel 		 * PCI-B always operates at 33Mhz.
776*03831d35Sstevel 		 */
777*03831d35Sstevel 		int_val = get_prop_val(find_prop(pci_instance,
778*03831d35Sstevel 			"clock-frequency"));
779*03831d35Sstevel 		if (int_val != NULL) {
780*03831d35Sstevel 			pci_card->freq = DAK_CLK_FREQ_TO_MHZ(*int_val);
781*03831d35Sstevel 		} else {
782*03831d35Sstevel 			pci_card->freq = -1;
783*03831d35Sstevel 		}
784*03831d35Sstevel 
785*03831d35Sstevel 		/*
786*03831d35Sstevel 		 * Figure out how we want to display the name
787*03831d35Sstevel 		 */
788*03831d35Sstevel 		value = get_prop_val(find_prop(pci_card_node,
789*03831d35Sstevel 					"compatible"));
790*03831d35Sstevel 		if (value != NULL) {
791*03831d35Sstevel 			/* use 'name'-'compatible' */
792*03831d35Sstevel 			(void) snprintf(buf, MAXSTRLEN, "%s-%s", name,
793*03831d35Sstevel 				(char *)value);
794*03831d35Sstevel 		} else {
795*03831d35Sstevel 			/* just use 'name' */
796*03831d35Sstevel 			(void) snprintf(buf, MAXSTRLEN, "%s", name);
797*03831d35Sstevel 		}
798*03831d35Sstevel 		name = buf;
799*03831d35Sstevel 
800*03831d35Sstevel 		/*
801*03831d35Sstevel 		 * If this node has children, add the device_type
802*03831d35Sstevel 		 * of the child to the name value of this pci_card->
803*03831d35Sstevel 		 */
804*03831d35Sstevel 		child_name = (char *)get_node_name(pci_card_node->child);
805*03831d35Sstevel 		if ((pci_card_node->child != NULL) &&
806*03831d35Sstevel 			(child_name != NULL)) {
807*03831d35Sstevel 			value = get_prop_val(find_prop(pci_card_node->child,
808*03831d35Sstevel 				"device_type"));
809*03831d35Sstevel 			if (value != NULL) {
810*03831d35Sstevel 				/* add device_type of child to name */
811*03831d35Sstevel 				(void) snprintf(pci_card->name, MAXSTRLEN,
812*03831d35Sstevel 				    "%s/%s (%s)", name, child_name,
813*03831d35Sstevel 					(char *)value);
814*03831d35Sstevel 			} else {
815*03831d35Sstevel 				/* just add childs name */
816*03831d35Sstevel 				(void) snprintf(pci_card->name, MAXSTRLEN,
817*03831d35Sstevel 				    "%s/%s", name, child_name);
818*03831d35Sstevel 			}
819*03831d35Sstevel 		} else {
820*03831d35Sstevel 			(void) snprintf(pci_card->name, MAXSTRLEN, "%s",
821*03831d35Sstevel 			    (char *)name);
822*03831d35Sstevel 		}
823*03831d35Sstevel 
824*03831d35Sstevel 		/*
825*03831d35Sstevel 		 * If this is a pci-bridge, then add the word
826*03831d35Sstevel 		 * 'pci-bridge' to its model.  If we can't find
827*03831d35Sstevel 		 * a model, then we just describe what the device
828*03831d35Sstevel 		 * is based on some properties.
829*03831d35Sstevel 		 */
830*03831d35Sstevel 		if (pci_bridge) {
831*03831d35Sstevel 			if (strlen(pci_card->model) == 0) {
832*03831d35Sstevel 			    if (pci_card_node->parent == pci_bridge_node)
833*03831d35Sstevel 				(void) snprintf(pci_card->model, MAXSTRLEN,
834*03831d35Sstevel 				    "%s", "device on pci-bridge");
835*03831d35Sstevel 			    else if (pci_card_node->parent
836*03831d35Sstevel 					== pci_parent_bridge)
837*03831d35Sstevel 				(void) snprintf(pci_card->model, MAXSTRLEN,
838*03831d35Sstevel 					"%s", "pci-bridge/pci-bridge");
839*03831d35Sstevel 			    else
840*03831d35Sstevel 				(void) snprintf(pci_card->model, MAXSTRLEN,
841*03831d35Sstevel 				    "%s", "PCI-BRIDGE");
842*03831d35Sstevel 			}
843*03831d35Sstevel 			else
844*03831d35Sstevel 				(void) snprintf(pci_card->model, MAXSTRLEN,
845*03831d35Sstevel 				    "%s/pci-bridge", pci_card->model);
846*03831d35Sstevel 		}
847*03831d35Sstevel 		/* insert this pci_card in the list to be displayed later */
848*03831d35Sstevel 
849*03831d35Sstevel 		*pci_card_list = insert_io_card(*pci_card_list, pci_card);
850*03831d35Sstevel 
851*03831d35Sstevel 		/*
852*03831d35Sstevel 		 * If we are dealing with a pci-bridge, we need to move
853*03831d35Sstevel 		 * down to the children of this bridge if there are any.
854*03831d35Sstevel 		 *
855*03831d35Sstevel 		 * If we are not, we are either dealing with a regular
856*03831d35Sstevel 		 * card (in which case we move onto the sibling of this
857*03831d35Sstevel 		 * card) or we are dealing with a child of a pci-bridge
858*03831d35Sstevel 		 * (in which case we move onto the child's siblings or
859*03831d35Sstevel 		 * if there are no more siblings for this child, we
860*03831d35Sstevel 		 * move onto the parents siblings).
861*03831d35Sstevel 		 */
862*03831d35Sstevel 		pci_card_node = next_pci_card(pci_card_node, &pci_bridge,
863*03831d35Sstevel 			is_pci, pci_bridge_node,
864*03831d35Sstevel 			pci_parent_bridge, pci_instance);
865*03831d35Sstevel 	} /* end-while */
866*03831d35Sstevel }
867*03831d35Sstevel 
868*03831d35Sstevel 
869*03831d35Sstevel /*
870*03831d35Sstevel  * Helper function for fill_pci_card_list().  Indicates which
871*03831d35Sstevel  * card node to go to next.
872*03831d35Sstevel  * Parameters:
873*03831d35Sstevel  * -----------
874*03831d35Sstevel  * Prom_node * curr_card: pointer to the current card node
875*03831d35Sstevel  *
876*03831d35Sstevel  * int * is_bridge: indicates whether or not the card (is | is on)
877*03831d35Sstevel  *                  a pci bridge
878*03831d35Sstevel  *
879*03831d35Sstevel  * int is_pcidev: indicates whether or not the current card
880*03831d35Sstevel  *                is a pci bridge
881*03831d35Sstevel  *
882*03831d35Sstevel  * Prom_node * curr_bridge: pointer to the current pci bridge.  Eg:
883*03831d35Sstevel  *                          curr_card->parent.
884*03831d35Sstevel  *
885*03831d35Sstevel  * Prom_node * parent_bridge: pointer to the first pci bridge encountered.
886*03831d35Sstevel  *			      we could have nested pci bridges, this would
887*03831d35Sstevel  *			      be the first one.
888*03831d35Sstevel  *
889*03831d35Sstevel  * Prom_node * pci: pointer to the pci instance that we are attached to.
890*03831d35Sstevel  *		    This would be parent_bridge->parent, or
891*03831d35Sstevel  *		    curr_node->parent, if curr_node is not on a pci bridge.
892*03831d35Sstevel  */
893*03831d35Sstevel static Prom_node *
next_pci_card(Prom_node * curr_card,int * is_bridge,int is_pcidev,Prom_node * curr_bridge,Prom_node * parent_bridge,Prom_node * pci)894*03831d35Sstevel next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev,
895*03831d35Sstevel 		Prom_node *curr_bridge, Prom_node *parent_bridge,
896*03831d35Sstevel 		Prom_node *pci)
897*03831d35Sstevel {
898*03831d35Sstevel 	Prom_node * curr_node = curr_card;
899*03831d35Sstevel 	if (*is_bridge) {
900*03831d35Sstevel 		/*
901*03831d35Sstevel 		 * is_pcidev is used to prevent us from following the
902*03831d35Sstevel 		 * children of something like a scsi device.
903*03831d35Sstevel 		 */
904*03831d35Sstevel 		if (curr_node->child != NULL && is_pcidev) {
905*03831d35Sstevel 			curr_node = curr_node->child;
906*03831d35Sstevel 		} else {
907*03831d35Sstevel 			curr_node = curr_node->sibling;
908*03831d35Sstevel 			if (curr_node == NULL) {
909*03831d35Sstevel 				curr_node = curr_bridge->sibling;
910*03831d35Sstevel 
911*03831d35Sstevel 				while (curr_node == NULL &&
912*03831d35Sstevel 					curr_bridge != parent_bridge &&
913*03831d35Sstevel 					curr_bridge != NULL) {
914*03831d35Sstevel 					curr_node =
915*03831d35Sstevel 						curr_bridge->parent->sibling;
916*03831d35Sstevel 					curr_bridge = curr_bridge->parent;
917*03831d35Sstevel 					if (curr_node != NULL &&
918*03831d35Sstevel 					    curr_node->parent == pci) {
919*03831d35Sstevel 						break;
920*03831d35Sstevel 					}
921*03831d35Sstevel 				}
922*03831d35Sstevel 
923*03831d35Sstevel 				if (curr_bridge == NULL ||
924*03831d35Sstevel 				    curr_node == NULL ||
925*03831d35Sstevel 				    curr_node->parent == pci ||
926*03831d35Sstevel 				    curr_bridge == parent_bridge ||
927*03831d35Sstevel 				    curr_node == parent_bridge) {
928*03831d35Sstevel 					*is_bridge = FALSE;
929*03831d35Sstevel 				}
930*03831d35Sstevel 			}
931*03831d35Sstevel 		}
932*03831d35Sstevel 
933*03831d35Sstevel 	} else {
934*03831d35Sstevel 		curr_node = curr_node->sibling;
935*03831d35Sstevel 	}
936*03831d35Sstevel 	return (curr_node);
937*03831d35Sstevel }
938