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