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