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