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