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