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, 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