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