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