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 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * Serengeti Platform specific functions.
     26  *
     27  */
     28 
     29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <unistd.h>
     34 #include <kstat.h>
     35 #include <string.h>
     36 #include <assert.h>
     37 #include <alloca.h>
     38 #include <libintl.h>
     39 #include <fcntl.h>
     40 #include <varargs.h>
     41 
     42 #include <sys/openpromio.h>
     43 #include <sys/sysmacros.h>
     44 
     45 #include <sys/serengeti.h>
     46 #include <sys/sgfrutypes.h>
     47 
     48 #include <pdevinfo.h>
     49 #include <display.h>
     50 #include <pdevinfo_sun4u.h>
     51 #include <display_sun4u.h>
     52 #include <libprtdiag.h>
     53 
     54 #include <config_admin.h>
     55 
     56 #if !defined(TEXT_DOMAIN)
     57 #define	TEXT_DOMAIN	"SYS_TEST"
     58 #endif
     59 
     60 #define	SCHIZO_COMPATIBLE	"pci108e,8001"
     61 #define	XMITS_COMPATIBLE	"pci108e,8002"
     62 
     63 #define	ACTIVE		0
     64 #define	INACTIVE	1
     65 #define	DISPLAY_INFO	40
     66 
     67 #define	EVNT2STR(e)	((e) == CFGA_STAT_NONE ? "none" : \
     68 			    (e) == CFGA_STAT_EMPTY ? "empty" : \
     69 			    (e) == CFGA_STAT_DISCONNECTED ? "disconnected" : \
     70 			    (e) == CFGA_STAT_CONNECTED ? "connected" : \
     71 			    (e) == CFGA_STAT_UNCONFIGURED ? "unconfigured" : \
     72 			    (e) == CFGA_STAT_CONFIGURED ? "configured" : \
     73 			    "unknown")
     74 
     75 #define	COND2STR(c)	((c) == CFGA_COND_UNKNOWN ? "unknown" : \
     76 			    (c) == CFGA_COND_OK ? "ok" : \
     77 			    (c) == CFGA_COND_FAILING ? "failing" : \
     78 			    (c) == CFGA_COND_FAILED ? "failed" : \
     79 			    (c) == CFGA_COND_UNUSABLE ? "unusable" : \
     80 			    "???")
     81 
     82 #define	SG_CLK_FREQ_TO_MHZ(x)	(((x) + 500000) / 1000000)
     83 
     84 #define	MAX_STATUS_LEN		8
     85 #define	SG_FAIL			"fail"
     86 #define	SG_DISABLED		"disabled"
     87 #define	SG_DEGRADED		"degraded"
     88 #define	SG_OK			"ok"
     89 
     90 #define	SG_SCHIZO_FAILED	1
     91 #define	SG_SCHIZO_GOOD		0
     92 
     93 #define	DEFAULT_MAX_FREQ	66	/* 66 MHz */
     94 #define	PCIX_MAX_FREQ		100	/* 100 MHz */
     95 
     96 #define	CFG_CPU	"::cpu"
     97 
     98 #define	CFG_SET_FRU_NAME_NODE(str, num) \
     99 { \
    100 	char tmp_str[MAX_FRU_NAME_LEN]; \
    101 	sprintf(tmp_str, "/N%d", num); \
    102 	strncat(str, tmp_str, sizeof (tmp_str)); \
    103 }
    104 
    105 #define	CFG_SET_FRU_NAME_CPU_BOARD(str, num) \
    106 { \
    107 	char tmp_str[MAX_FRU_NAME_LEN]; \
    108 	sprintf(tmp_str, ".%s%d", SG_HPU_TYPE_CPU_BOARD_ID, num); \
    109 	strncat(str, tmp_str, sizeof (tmp_str)); \
    110 }
    111 
    112 #define	CFG_SET_FRU_NAME_MODULE(str, num) \
    113 { \
    114 	char tmp_str[MAX_FRU_NAME_LEN]; \
    115 	sprintf(tmp_str, "%s%d", CFG_CPU, num); \
    116 	strncat(str, tmp_str, sizeof (tmp_str)); \
    117 }
    118 
    119 extern	int	print_flag;
    120 
    121 /*
    122  * these functions will overlay the symbol table of libprtdiag
    123  * at runtime (Serengeti systems only)
    124  */
    125 int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
    126 void	*get_prop_val(Prop *prop);
    127 Prop	*find_prop(Prom_node *pnode, char *name);
    128 char	*get_node_name(Prom_node *pnode);
    129 char	*get_node_type(Prom_node *pnode);
    130 void	add_node(Sys_tree *, Prom_node *);
    131 void 	display_pci(Board_node *);
    132 void 	display_ffb(Board_node *, int);
    133 void	display_io_cards(struct io_card *list);
    134 void	display_cpu_devices(Sys_tree *tree);
    135 void	display_cpus(Board_node *board);
    136 void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
    137 		struct system_kstat_data *kstats);
    138 void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
    139 void	get_failed_parts(void);
    140 int	display_failed_parts(Sys_tree *tree);
    141 void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
    142 void	print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
    143 	    char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
    144 
    145 /* Local Functions */
    146 static void	serengeti_display_hw_revisions(Prom_node *root,
    147 							Board_node *bnode);
    148 static Board_node *serengeti_find_board(Sys_tree *root, int board, int nodeid);
    149 static Board_node *serengeti_insert_board(Sys_tree *root, int board, int nid);
    150 static int	display_schizo_revisions(Board_node *bdlist, int mode);
    151 static void	display_sgsbbc_revisions(Board_node *bdlist);
    152 static void	serengeti_display_board_info(int state);
    153 static void	serengeti_display_board_info_header(int state);
    154 static boolean_t cpu_node_configured(char *const node);
    155 static void display_io_max_bus_speed(struct io_card *p);
    156 static void display_io_slot_info(struct io_card *p);
    157 static void get_slot_name(struct io_card *card, char *slot_name);
    158 
    159 /* The bus max freq is determined based on board level in use */
    160 int	board_bus_max_freq = DEFAULT_MAX_FREQ;	/* 66MHz default */
    161 
    162 /*
    163  * Serengeti now uses both the devinfo tree and the OBP tree for it's
    164  * prtdiag. The devinfo tree is used for getting the HW config of the
    165  * system and the OBP device tree is used for listing the failed HW
    166  * in the system. This is because devinfo currently does not include
    167  * any PROM nodes with a status of 'fail' so we need to go to OBP to
    168  * get a list of failed HW. We use the tree flag to allow the same code
    169  * to walk both trees.
    170  *
    171  * We really need to look at having a single tree for all platforms!
    172  */
    173 #define	DEVINFO_TREE	1
    174 #define	OBP_TREE	2
    175 
    176 static int	tree = DEVINFO_TREE;
    177 
    178 #ifdef DEBUG
    179 #define	D_PRINTFINDENT	printfindent
    180 void
    181 printfindent(int indent, char *fmt, ...)
    182 {
    183 	va_list ap;
    184 	int i = 0;
    185 	for (i = 0; i < indent; i ++)
    186 		printf("\t");
    187 
    188 	va_start(ap);
    189 	(void) vprintf(fmt, ap);
    190 	va_end(ap);
    191 }
    192 #else
    193 #define	D_PRINTFINDENT
    194 #endif
    195 
    196 /*
    197  * display_pci
    198  * Display all the PCI IO cards on this board.
    199  */
    200 void
    201 display_pci(Board_node *board)
    202 {
    203 	struct io_card *card_list = NULL;
    204 	struct io_card card;
    205 	void *value;
    206 	Prom_node *pci;
    207 	Prom_node *card_node;
    208 	Prom_node *pci_bridge_node;
    209 	Prom_node *child_pci_bridge_node;
    210 	char	*slot_name = NULL;	/* info in "slot-names" prop */
    211 	char	*child_name;
    212 	char	*name, *type;
    213 	char	*pname, *ptype;
    214 	char	buf[MAXSTRLEN];
    215 	int	*int_val;
    216 	int	pci_bus;
    217 	int	pci_bridge = 0;
    218 	int	pci_bridge_dev_no;
    219 	char	*slot_name_arr[SG_MAX_SLOTS_PER_IO_BD] = {NULL};
    220 	int	i;
    221 	int	portid;
    222 	int	level = 0;
    223 	int	version, *pversion;
    224 #ifdef DEBUG
    225 	int	slot_name_bits;
    226 #endif
    227 
    228 	if (board == NULL)
    229 		return;
    230 
    231 	/* Initialize all the common information */
    232 	card.display = TRUE;
    233 	card.board = board->board_num;
    234 	card.node_id = board->node_id;
    235 
    236 	/*
    237 	 * Search for each schizo and xmits, then find/display all nodes under
    238 	 * each schizo and xmits node found.
    239 	 */
    240 	for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
    241 	    pci != NULL;
    242 	    pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
    243 
    244 		/* set max freq for this board */
    245 		board_bus_max_freq = DEFAULT_MAX_FREQ;
    246 		/*
    247 		 * Find out if this is a PCI or cPCI IO Board.
    248 		 * If "enum-impl" property exists in pci node => cPCI.
    249 		 */
    250 		value = get_prop_val(find_prop(pci, "enum-impl"));
    251 		if (value == NULL) {
    252 			(void) sprintf(card.bus_type, "PCI");
    253 		} else {
    254 			(void) sprintf(card.bus_type, "cPCI");
    255 		}
    256 
    257 		if (strstr((char *)get_prop_val(
    258 		    find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
    259 			sprintf(card.notes, "%s", XMITS_COMPATIBLE);
    260 			/*
    261 			 * With XMITS 3.X and PCI-X mode, the bus speed
    262 			 * can be higher than 66MHZ.
    263 			 */
    264 			value = (int *)get_prop_val
    265 			    (find_prop(pci, "module-revision#"));
    266 			if (value) {
    267 				pversion = (int *)value;
    268 				version = *pversion;
    269 				if (version >= 4)
    270 					board_bus_max_freq = PCIX_MAX_FREQ;
    271 			}
    272 		} else if (strstr((char *)get_prop_val(
    273 		    find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
    274 			sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
    275 		else
    276 			sprintf(card.notes, " ");
    277 
    278 		/*
    279 		 * Get slot-name properties from parent node and
    280 		 * store them in an array.
    281 		 */
    282 		value = (char *)get_prop_val(find_prop(pci, "slot-names"));
    283 		if (value != NULL) {
    284 #ifdef DEBUG
    285 			/* save the 4 byte bitmask */
    286 			slot_name_bits = *(int *)value;
    287 #endif
    288 			/* array starts after first int */
    289 			slot_name_arr[0] = (char *)value + sizeof (int);
    290 
    291 			D_PRINTFINDENT(0, "slot_name_arr[0] is [%s]\n",
    292 			    slot_name_arr[0]);
    293 
    294 			for (i = 1; i < SG_MAX_SLOTS_PER_IO_BD; i++) {
    295 				slot_name_arr[i] = (char *)slot_name_arr[i - 1]
    296 				    + strlen(slot_name_arr[i - 1]) +1;
    297 
    298 			D_PRINTFINDENT(0, "slot_name_arr[%d] is [%s]\n", i,
    299 			    slot_name_arr[i]);
    300 
    301 			}
    302 		}
    303 
    304 		/*
    305 		 * Search for Children of this node ie. Cards.
    306 		 * Note: any of these cards can be a pci-bridge
    307 		 *	that itself has children. If we find a
    308 		 *	pci-bridge we need to handle it specially.
    309 		 *
    310 		 *	There can now be the condition of a pci-bridge
    311 		 *	being the child of a pci-bridge which create a
    312 		 *	two levels of pci-bridges.  This special condition
    313 		 *	needs to be handled as well.  The variable level
    314 		 *	is used to track the depth of the tree.  This
    315 		 *	variable is then used to find instances of this case.
    316 		 */
    317 		level = 0;
    318 		card_node = pci->child;
    319 		while (card_node != NULL) {
    320 			pci_bridge = 0;
    321 
    322 			/* If it doesn't have a name, skip it */
    323 			name = (char *)get_prop_val(
    324 			    find_prop(card_node, "name"));
    325 			if (name == NULL) {
    326 				card_node = card_node->sibling;
    327 				continue;
    328 			}
    329 			D_PRINTFINDENT(level, "NAME is %s\n", name);
    330 
    331 			type = (char *)get_prop_val(
    332 			    find_prop(card_node, "device_type"));
    333 
    334 			/*
    335 			 * get dev# and func# for this card from the
    336 			 * 'reg' property.
    337 			 */
    338 			int_val = (int *)get_prop_val(
    339 			    find_prop(card_node, "reg"));
    340 			if (int_val != NULL) {
    341 				card.dev_no = (((*int_val) & 0xF800) >> 11);
    342 				card.func_no = (((*int_val) & 0x700) >> 8);
    343 			} else {
    344 				card.dev_no = -1;
    345 				card.func_no = -1;
    346 			}
    347 
    348 			/*
    349 			 * If this is a pci-bridge, then store it's dev#
    350 			 * as it's children nodes need this to get their slot#.
    351 			 * We set the pci_bridge flag so that we know we are
    352 			 * looking at a pci-bridge node. This flag gets reset
    353 			 * every time we enter this while loop.
    354 			 */
    355 
    356 			/*
    357 			 * Check for a PCI-PCI Bridge for PCI and cPCI
    358 			 * IO Boards using the name and type properties.
    359 			 *
    360 			 * If level is greater then 0, then check the parent
    361 			 * node to see if it was also a pci-bridge.  We do not
    362 			 * this when level is 0 as this will see the schizo or
    363 			 * xmits device as a pci-bridge node.  This will mess
    364 			 * up the slot number of child nodes.
    365 			 */
    366 			if ((type != NULL) &&
    367 			    (strncmp(name, "pci", 3) == 0) &&
    368 			    (strcmp(type, "pci") == 0)) {
    369 				if (level > 0) {
    370 					pname = (char *)get_prop_val(
    371 					    find_prop(card_node->parent,
    372 					    "name"));
    373 					ptype = (char *)get_prop_val(
    374 					    find_prop(card_node->parent,
    375 					    "device_type"));
    376 
    377 					if ((ptype != NULL) &&
    378 					    (pname != NULL) &&
    379 					    (strncmp(pname, "pci", 3) == 0) &&
    380 					    (strcmp(ptype, "pci") == 0)) {
    381 						child_pci_bridge_node =
    382 						    card_node;
    383 					} else {
    384 						pci_bridge_dev_no = card.dev_no;
    385 						pci_bridge_node = card_node;
    386 					}
    387 				} else {
    388 					pci_bridge_dev_no = card.dev_no;
    389 					pci_bridge_node = card_node;
    390 				}
    391 				pci_bridge = TRUE;
    392 
    393 				D_PRINTFINDENT(level,
    394 				    "pci_bridge_dev_no is [%d]\n",
    395 				    pci_bridge_dev_no);
    396 			}
    397 
    398 			/*
    399 			 * Get slot-names property from slot_names_arr.
    400 			 * If we are the child of a pci_bridge we use the
    401 			 * dev# of the pci_bridge as an index to get
    402 			 * the slot number. We know that we are a child of
    403 			 * a pci-bridge if our parent is the same as the last
    404 			 * pci_bridge node found above.
    405 			 */
    406 			if (type)
    407 				D_PRINTFINDENT(level,
    408 				    "*** name is [%s] - type is [%s]\n",
    409 				    name, type);
    410 			else
    411 				D_PRINTFINDENT(level,
    412 				    "*** name is [%s]\n", name);
    413 
    414 			if (card.dev_no != -1) {
    415 				/*
    416 				 * We compare this cards parent node with the
    417 				 * pci_bridge_node to see if it's a child.
    418 				 */
    419 				if (((level > 0) &&
    420 				    (card_node->parent->parent ==
    421 				    pci_bridge_node)) ||
    422 				    (card_node->parent == pci_bridge_node)) {
    423 					/* use dev_no of pci_bridge */
    424 					D_PRINTFINDENT(level,
    425 					    "   pci_bridge_dev_no is [%d]\n",
    426 					    pci_bridge_dev_no);
    427 
    428 					slot_name =
    429 					    slot_name_arr[pci_bridge_dev_no -1];
    430 				} else {
    431 					/* use cards own dev_no */
    432 					D_PRINTFINDENT(level,
    433 					    "    card.dev_no is [%d]\n",
    434 					    card.dev_no);
    435 
    436 					slot_name =
    437 					    slot_name_arr[card.dev_no - 1];
    438 				}
    439 
    440 				get_slot_name(&card, slot_name);
    441 
    442 			} else {
    443 				(void) sprintf(card.slot_str, "%c", '-');
    444 			}
    445 
    446 			/*
    447 			 * Get the portid of the schizo and xmits that this card
    448 			 * lives under.
    449 			 */
    450 			portid = -1;
    451 			value = get_prop_val(find_prop(pci, "portid"));
    452 			if (value != NULL) {
    453 				portid = *(int *)value;
    454 			}
    455 			card.schizo_portid = portid;
    456 
    457 #ifdef DEBUG
    458 			(void) sprintf(card.notes, "%s portid [%d] dev_no[%d]"
    459 			    " slot_name[%s] name_bits[%d]",
    460 			    card.notes,
    461 			    portid,
    462 			    card.dev_no, slot_name,
    463 			    slot_name_bits);
    464 #endif
    465 
    466 			/*
    467 			 * Find out whether this is PCI bus A or B
    468 			 * using the 'reg' property.
    469 			 */
    470 			int_val = (int *)get_prop_val
    471 			    (find_prop(pci, "reg"));
    472 
    473 			if (int_val != NULL) {
    474 				int_val ++; /* skip over first integer */
    475 				pci_bus = ((*int_val) & 0x7f0000);
    476 				if (pci_bus == 0x600000)
    477 					card.pci_bus = 'A';
    478 				else if (pci_bus == 0x700000)
    479 					card.pci_bus = 'B';
    480 				else
    481 					card.pci_bus = '-';
    482 			} else {
    483 				card.pci_bus = '-';
    484 			}
    485 
    486 
    487 			/*
    488 			 * Check for failed status.
    489 			 */
    490 			if (node_status(card_node, SG_FAIL))
    491 				strncpy(card.status, SG_FAIL,
    492 				    sizeof (SG_FAIL));
    493 			else if (node_status(card_node, SG_DISABLED))
    494 				strncpy(card.status, SG_DISABLED,
    495 				    sizeof (SG_DISABLED));
    496 			else
    497 				strncpy(card.status, SG_OK,
    498 				    sizeof (SG_OK));
    499 
    500 			/* Get the model of this card */
    501 			value = get_prop_val(find_prop(card_node, "model"));
    502 			if (value == NULL)
    503 				card.model[0] = '\0';
    504 			else {
    505 				(void) sprintf(card.model, "%s",
    506 				    (char *)value);
    507 				/* Skip sgsbbc nodes, they are not cards */
    508 				if (strcmp(card.model, "SUNW,sgsbbc") == 0) {
    509 					card_node = card_node->sibling;
    510 					continue;
    511 				}
    512 			}
    513 
    514 			/*
    515 			 * Check if further processing is necessary to display
    516 			 * this card uniquely.
    517 			 */
    518 			distinguish_identical_io_cards(name, card_node, &card);
    519 
    520 			/*
    521 			 * The card may have a "clock-frequency" but we
    522 			 * are not interested in that. Instead we get the
    523 			 * "clock-frequency" of the PCI Bus that the card
    524 			 * resides on. PCI-A can operate at 33Mhz or 66Mhz
    525 			 * depending on what card is plugged into the Bus.
    526 			 * PCI-B always operates at 33Mhz.
    527 			 *
    528 			 */
    529 			int_val = get_prop_val(find_prop(pci,
    530 			    "clock-frequency"));
    531 			if (int_val != NULL) {
    532 				card.freq = SG_CLK_FREQ_TO_MHZ(*int_val);
    533 			} else {
    534 				card.freq = -1;
    535 			}
    536 
    537 			/*
    538 			 * Figure out how we want to display the name
    539 			 */
    540 			value = get_prop_val(find_prop(card_node,
    541 			    "compatible"));
    542 			if (value != NULL) {
    543 				/* use 'name'-'compatible' */
    544 				(void) sprintf(buf, "%s-%s", name,
    545 				    (char *)value);
    546 			} else {
    547 				/* just use 'name' */
    548 				(void) sprintf(buf, "%s", name);
    549 			}
    550 			name = buf;
    551 
    552 			/*
    553 			 * If this node has children, add the device_type
    554 			 * of the child to the name value of this card.
    555 			 */
    556 			child_name = (char *)get_node_name(card_node->child);
    557 			if ((card_node->child != NULL) &&
    558 			    (child_name != NULL)) {
    559 				value = get_prop_val(find_prop(card_node->child,
    560 				    "device_type"));
    561 				if (value != NULL) {
    562 					/* add device_type of child to name */
    563 					(void) sprintf(card.name, "%s/%s (%s)",
    564 					    name, child_name,
    565 					    (char *)value);
    566 				} else {
    567 					/* just add childs name */
    568 					(void) sprintf(card.name, "%s/%s", name,
    569 					    child_name);
    570 				}
    571 			} else {
    572 				(void) sprintf(card.name, "%s", (char *)name);
    573 			}
    574 
    575 			/*
    576 			 * If this is a pci-bridge, then add the word
    577 			 * 'pci-bridge' to it's model.
    578 			 */
    579 			if (pci_bridge) {
    580 				if (strlen(card.model) == 0)
    581 					(void) sprintf(card.model,
    582 					    "%s", "pci-bridge");
    583 				else
    584 					(void) sprintf(card.model,
    585 					    "%s/pci-bridge", card.model);
    586 			}
    587 
    588 			/* insert this card in the list to be displayed later */
    589 			card_list = insert_io_card(card_list, &card);
    590 
    591 			/*
    592 			 * If we are dealing with a pci-bridge, we need to move
    593 			 * down to the children of this bridge if there are any.
    594 			 *
    595 			 * If we are not, we are either dealing with a regular
    596 			 * card (in which case we move onto the sibling of this
    597 			 * card) or we are dealing with a child of a pci-bridge
    598 			 * (in which case we move onto the child's siblings or
    599 			 * if there are no more siblings for this child, we
    600 			 * move onto the parents siblings).
    601 			 *
    602 			 * Once we reach the last child node of a pci-bridge,
    603 			 * we need to back up the tree to the parents sibling
    604 			 * node.  If our parent has no more siblings, we need
    605 			 * to check our grand parent for siblings.
    606 			 *
    607 			 * If we have no more siblings, we simply point to
    608 			 * to the child's sibling which moves us onto the next
    609 			 * bus leaf.
    610 			 *
    611 			 * The variable level gets adjusted on some of the
    612 			 * conditions as this is used to track level within
    613 			 * the tree we have reached.
    614 			 */
    615 			if (pci_bridge) {
    616 				if (card_node->child != NULL) {
    617 					level++;
    618 					card_node = card_node->child;
    619 				} else
    620 					card_node = card_node->sibling;
    621 			} else {
    622 				if ((card_node->parent == pci_bridge_node) &&
    623 				    (card_node->sibling == NULL)) {
    624 					card_node = pci_bridge_node->sibling;
    625 					if (level > 0)
    626 						level--;
    627 				} else if ((card_node->parent ==
    628 				    child_pci_bridge_node) &&
    629 				    (card_node->parent->parent ==
    630 				    pci_bridge_node)) {
    631 					if ((child_pci_bridge_node->sibling) &&
    632 					    (card_node->sibling == NULL)) {
    633 						card_node =
    634 						    child_pci_bridge_node-> \
    635 						    sibling;
    636 					if (level > 0)
    637 						level--;
    638 					} else if ((pci_bridge_node->sibling) &&
    639 					    (card_node->sibling == NULL)) {
    640 						card_node =
    641 						    pci_bridge_node->sibling;
    642 						if (level > 1)
    643 							level = level - 2;
    644 						else if (level > 0)
    645 							level--;
    646 					} else
    647 						card_node = card_node->sibling;
    648 				} else
    649 					card_node = card_node->sibling;
    650 			}
    651 		} /* end-while */
    652 	} /* end-for */
    653 
    654 	display_io_cards(card_list);
    655 	free_io_cards(card_list);
    656 }
    657 
    658 /*
    659  * display_ffb
    660  *
    661  * There are no FFB's on a Serengeti, however in the generic library,
    662  * the display_ffb() function is implemented so we have to define an
    663  * empty function here.
    664  */
    665 /*ARGSUSED0*/
    666 void
    667 display_ffb(Board_node *board, int table)
    668 {}
    669 
    670 static void
    671 serengeti_display_board_info_header(int state)
    672 {
    673 	char *fmt = "%-9s  %-11s  %-12s  %-12s  %-9s %-40s\n";
    674 
    675 	log_printf("\n", 0);
    676 	log_printf("=========================", 0);
    677 	if (state == ACTIVE)
    678 		log_printf(dgettext(TEXT_DOMAIN,
    679 		    " Active Boards for Domain "), 0);
    680 	else
    681 		log_printf(dgettext(TEXT_DOMAIN,
    682 		    " Available Boards/Slots for Domain "), 0);
    683 	log_printf("===========================", 0);
    684 	log_printf("\n", 0);
    685 	log_printf("\n", 0);
    686 
    687 	log_printf(fmt, "", "Board", "Receptacle", "Occupant", "", "", 0);
    688 
    689 	log_printf(fmt, "FRU Name", "Type", "Status", "Status",
    690 	    "Condition", "Info", 0);
    691 
    692 	log_printf(fmt, "---------", "-----------", "-----------",
    693 	    "------------", "---------",
    694 	    "----------------------------------------", 0);
    695 }
    696 
    697 static void
    698 serengeti_display_board_info(int state)
    699 {
    700 	int i, z, ret;
    701 	int nlist = 0;
    702 	int available_board_count = 0;
    703 	struct cfga_list_data *board_cfg = NULL;
    704 	char *err_string = NULL;
    705 	char tmp_id[CFGA_LOG_EXT_LEN + 1];
    706 	char tmp_info[DISPLAY_INFO + 1];
    707 	const char listops[] = "class=sbd";
    708 	struct cfga_list_data dat;
    709 	cfga_flags_t flags = NULL;
    710 
    711 	ret = config_list_ext(0, NULL, &board_cfg, &nlist,
    712 	    NULL, listops,
    713 	    &err_string, flags);
    714 
    715 	if (ret == CFGA_OK) {
    716 		serengeti_display_board_info_header(state);
    717 		for (i = 0; i < nlist; i++) {
    718 			dat = board_cfg[i];
    719 
    720 			if ((state != ACTIVE) &&
    721 			    (dat.ap_o_state == CFGA_STAT_CONFIGURED))
    722 				continue;
    723 			else if ((state == ACTIVE) &&
    724 			    (dat.ap_o_state != CFGA_STAT_CONFIGURED))
    725 				continue;
    726 			if (state == INACTIVE)
    727 				available_board_count++;
    728 
    729 			memcpy(tmp_id, dat.ap_log_id, CFGA_LOG_EXT_LEN);
    730 			tmp_id[CFGA_LOG_EXT_LEN] = '\0';
    731 			for (z = 0; z < strlen(tmp_id); z++) {
    732 				if (tmp_id[z] == '.')
    733 					tmp_id[z] = '/';
    734 			}
    735 			log_printf("/%-8s  ", tmp_id, 0);
    736 			log_printf("%-11s  ", dat.ap_type, 0);
    737 
    738 			log_printf("%-12s  ", EVNT2STR(dat.ap_r_state), 0);
    739 			log_printf("%-12s  ", EVNT2STR(dat.ap_o_state), 0);
    740 			log_printf("%-8s  ", COND2STR(dat.ap_cond), 0);
    741 
    742 			memcpy(tmp_info, dat.ap_info, DISPLAY_INFO);
    743 			tmp_info[DISPLAY_INFO - 1] = '\0';
    744 			if (strlen(tmp_info) >= (DISPLAY_INFO - 1))
    745 				tmp_info[DISPLAY_INFO - 2] = '+';
    746 			log_printf("%-*s\n", (DISPLAY_INFO - 1), tmp_info, 0);
    747 		}
    748 		if ((state == INACTIVE) &&
    749 		    (available_board_count == 0)) {
    750 			log_printf(dgettext(TEXT_DOMAIN,
    751 			    "There are currently no "
    752 			    "Boards/Slots available "
    753 			    "to this Domain\n"), 0);
    754 		}
    755 	}
    756 	if (board_cfg)
    757 		free(board_cfg);
    758 	if (err_string)
    759 		free(err_string);
    760 }
    761 
    762 /*
    763  * add_node
    764  *
    765  * This function adds a board node to the board structure where that
    766  * that node's physical component lives.
    767  */
    768 void
    769 add_node(Sys_tree *root, Prom_node *pnode)
    770 {
    771 	int	board	= -1;
    772 	int	portid	= -1;
    773 	int	nodeid	= -1;
    774 
    775 	void		*value	= NULL;
    776 	Board_node	*bnode	= NULL;
    777 	Prom_node	*p	= NULL;
    778 	char		*type;
    779 
    780 	/* Get the board number of this board from the portid prop */
    781 	if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
    782 		if ((type = get_node_type(pnode)) && (strcmp(type, "cpu") == 0))
    783 			value =
    784 			    get_prop_val(find_prop(pnode->parent, "portid"));
    785 	}
    786 	if (value != NULL) {
    787 		portid = *(int *)value;
    788 	}
    789 
    790 	nodeid	= SG_PORTID_TO_NODEID(portid);
    791 	board	= SG_PORTID_TO_BOARD_NUM(portid);
    792 
    793 	/* find the board node with the same board number */
    794 	if ((bnode = serengeti_find_board(root, board, nodeid)) == NULL) {
    795 		bnode = serengeti_insert_board(root, board, nodeid);
    796 	}
    797 
    798 	/* now attach this prom node to the board list */
    799 	/* Insert this node at the end of the list */
    800 	pnode->sibling = NULL;
    801 	if (bnode->nodes == NULL)
    802 		bnode->nodes = pnode;
    803 	else {
    804 		p = bnode->nodes;
    805 		while (p->sibling != NULL)
    806 			p = p->sibling;
    807 		p->sibling = pnode;
    808 	}
    809 }
    810 
    811 
    812 
    813 /*
    814  * Print out all the io cards in the list.  Also print the column
    815  * headers if told to do so.
    816  */
    817 void
    818 display_io_cards(struct io_card *list)
    819 {
    820 	char	*fmt = "%-10s  %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-34s";
    821 
    822 	static int banner = FALSE; /* Have we printed the column headings? */
    823 	struct io_card *p;
    824 
    825 	if (list == NULL)
    826 		return;
    827 
    828 	if (banner == FALSE) {
    829 		log_printf(fmt, "", "", "", "", "", "Bus", "Max",
    830 		    "", "", "", 0);
    831 		log_printf("\n", 0);
    832 		log_printf(fmt, "", "IO", "Port", "Bus", "", "Freq", "Bus",
    833 		    "Dev,", "", "", 0);
    834 		log_printf("\n", 0);
    835 		log_printf(fmt, "FRU Name", "Type", " ID", "Side", "Slot",
    836 		    "MHz", "Freq", "Func", "State", "Name", 0);
    837 #ifdef DEBUG
    838 		log_printf("Model                   Notes\n", 0);
    839 #else
    840 		log_printf("Model\n", 0);
    841 #endif
    842 
    843 		log_printf(fmt, "----------", "----", "----", "----", "----",
    844 		    "----", "----", "----", "-----",
    845 		    "--------------------------------", 0);
    846 #ifdef DEBUG
    847 		log_printf("----------------------  ", 0);
    848 #endif
    849 		log_printf("----------------------\n", 0);
    850 		banner = TRUE;
    851 	}
    852 
    853 	for (p = list; p != NULL; p = p -> next) {
    854 
    855 		display_io_slot_info(p);
    856 
    857 		display_io_max_bus_speed(p);
    858 
    859 		log_printf("\n", 0);
    860 	}
    861 }
    862 
    863 static void
    864 display_io_slot_info(struct io_card *p)
    865 {
    866 	char	fru_name[MAX_FRU_NAME_LEN] = "";
    867 
    868 	SG_SET_FRU_NAME_NODE(fru_name, p->node_id);
    869 	SG_SET_FRU_NAME_IO_BOARD(fru_name, p->board);
    870 	SG_SET_FRU_NAME_MODULE(fru_name, p->schizo_portid % 2);
    871 
    872 	log_printf("%-8s  ", fru_name, 0);
    873 	log_printf("%-4s  ", p->bus_type, 0);
    874 	log_printf("%-3d  ", p->schizo_portid, 0);
    875 	log_printf("%c    ", p->pci_bus, 0);
    876 	log_printf("%-1s    ", p->slot_str, 0);
    877 	log_printf("%-3d ", p->freq, 0);
    878 }
    879 
    880 #define	BUS_SPEED_PRINT(speed)	log_printf(" %d  ", speed, 0)
    881 
    882 static void
    883 display_io_max_bus_speed(struct io_card *p)
    884 {
    885 	int speed = board_bus_max_freq;
    886 
    887 	switch (p->pci_bus) {
    888 	case 'A':
    889 		BUS_SPEED_PRINT(speed);
    890 		break;
    891 	case 'B':
    892 		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
    893 			if ((strncmp(p->slot_str, "1", 1) == 0) ||
    894 			    (strncmp(p->slot_str, "0", 1) == 0))
    895 				BUS_SPEED_PRINT(33);
    896 			else
    897 				BUS_SPEED_PRINT(speed);
    898 		} else
    899 			BUS_SPEED_PRINT(33);
    900 		break;
    901 	default:
    902 		log_printf("  -	 ", 0);
    903 		break;
    904 	}
    905 
    906 	log_printf("%-1d,%-1d  ", p->dev_no, p->func_no, 0);
    907 	log_printf("%-5s ", p->status, 0);
    908 
    909 	log_printf("%-32.32s%c ", p->name,
    910 	    ((strlen(p->name) > 32) ? '+' : ' '), 0);
    911 	log_printf("%-22.22s%c", p->model,
    912 	    ((strlen(p->model) > 22) ? '+' : ' '), 0);
    913 #ifdef	DEBUG
    914 	log_printf(" %s", p->notes, 0);
    915 #endif	/* DEBUG */
    916 }
    917 
    918 void
    919 display_cpu_devices(Sys_tree *tree)
    920 {
    921 	Board_node *bnode;
    922 
    923 	/* printf formats */
    924 	char	*fmt1 = "%-10s  %-7s  %-4s  %-4s  %-7s  %-4s\n";
    925 
    926 	/*
    927 	 * Display the table header for CPUs . Then display the CPU
    928 	 * frequency, cache size, and processor revision of all cpus.
    929 	 */
    930 	log_printf("\n", 0);
    931 	log_printf("=========================", 0);
    932 	log_printf(" CPUs ", 0);
    933 	log_printf("=========================", 0);
    934 	log_printf("======================", 0);
    935 	log_printf("\n", 0);
    936 	log_printf("\n", 0);
    937 
    938 	log_printf(fmt1, "", "CPU ", "Run", " E$", "CPU", "CPU", 0);
    939 
    940 	log_printf(fmt1, "FRU Name", "ID ", "MHz", " MB",
    941 	    "Impl.", "Mask", 0);
    942 
    943 	log_printf(fmt1, "----------", "-------", "----", "----",
    944 	    "-------",  "----", 0);
    945 
    946 	/* Now display all of the cpus on each board */
    947 	bnode = tree->bd_list;
    948 	while (bnode != NULL) {
    949 		display_cpus(bnode);
    950 		bnode = bnode->next;
    951 	}
    952 
    953 	log_printf("\n", 0);
    954 }
    955 
    956 static boolean_t
    957 cpu_node_configured(char *const node)
    958 {
    959 	int ret, i;
    960 	int nlist = 0;
    961 	boolean_t rv;
    962 	char *err_string = NULL;
    963 	char *const *ap_args = NULL;
    964 	struct cfga_list_data *statlist = NULL;
    965 	struct cfga_list_data dat;
    966 	cfga_flags_t flags = CFGA_FLAG_LIST_ALL;
    967 
    968 	if (node == NULL)
    969 		return (FALSE);
    970 
    971 	ap_args = &node;
    972 	ret = config_list_ext(1, &node, &statlist, &nlist,
    973 	    NULL, NULL, &err_string, flags);
    974 
    975 	if (ret == CFGA_OK) {
    976 		dat = statlist[0];
    977 
    978 		if (dat.ap_o_state == CFGA_STAT_CONFIGURED)
    979 			rv = TRUE;
    980 		else
    981 			rv = FALSE;
    982 	} else {
    983 		rv = FALSE;
    984 	}
    985 	if (statlist)
    986 		free(statlist);
    987 	if (err_string)
    988 		free(err_string);
    989 	return (rv);
    990 }
    991 
    992 /*
    993  * Display the CPUs present on this board.
    994  */
    995 void
    996 display_cpus(Board_node *board)
    997 {
    998 	Prom_node *cpu;
    999 	uint_t freq;	 /* CPU clock frequency */
   1000 	int ecache_size; /* External cache size */
   1001 	int board_num = board->board_num;
   1002 	int *mid;
   1003 	int *impl;
   1004 	int *mask;
   1005 	int decoded_mask;
   1006 	int *coreid;
   1007 	int mid_prev = -1;
   1008 	int ecache_size_prev = 0;
   1009 	char fru_prev[MAX_FRU_NAME_LEN] = "";
   1010 
   1011 	/*
   1012 	 * display the CPUs' operating frequency, cache size, impl. field
   1013 	 * and mask revision.
   1014 	 */
   1015 	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
   1016 	    cpu = dev_next_type(cpu, "cpu")) {
   1017 		char	fru_name[MAX_FRU_NAME_LEN] = "";
   1018 		char	cfg_fru_name[MAX_FRU_NAME_LEN] = "";
   1019 
   1020 		mid = (int *)get_prop_val(find_prop(cpu, "portid"));
   1021 		if (mid == NULL)
   1022 			mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
   1023 		freq = SG_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
   1024 		ecache_size = get_ecache_size(cpu);
   1025 		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
   1026 		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
   1027 
   1028 		/* Do not display a failed CPU node */
   1029 		if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
   1030 			continue;
   1031 
   1032 		/* FRU Name */
   1033 		SG_SET_FRU_NAME_NODE(fru_name, board->node_id);
   1034 
   1035 		SG_SET_FRU_NAME_CPU_BOARD(fru_name, board_num);
   1036 		SG_SET_FRU_NAME_MODULE(fru_name, *mid % 4);
   1037 
   1038 		if (CPU_IMPL_IS_CMP(*impl)) {
   1039 			coreid = (int *)get_prop_val(find_prop(cpu,
   1040 			    "reg"));
   1041 			if (coreid == NULL) {
   1042 				continue;
   1043 			}
   1044 
   1045 			/*
   1046 			 * The assumption is made that 2 cores will always be
   1047 			 * listed together in the device tree. If either core
   1048 			 * is "bad" then the FRU will not be listed.
   1049 			 *
   1050 			 * As display_cpus on Serengeti does actually process
   1051 			 * all cpu's per board a copy of the fru_name needs to
   1052 			 * be made as the following core may not be its
   1053 			 * sibling. If this is the case it is assumed that a
   1054 			 * sibling core has failed, so the fru should not be
   1055 			 * displayed.
   1056 			 *
   1057 			 * For the first instance of a core, fru_prev is
   1058 			 * expected to be empty.  The current values are then
   1059 			 * stored and the next board->nodes is processed. If
   1060 			 * this is a sibling core, the ecache size it tallied
   1061 			 * and the  previous value reset and processing
   1062 			 * continues.
   1063 			 *
   1064 			 * If the following core is not a sibling, the new
   1065 			 * values are stored and the next board->nodes is
   1066 			 * processed.
   1067 			 */
   1068 			if (strncmp(fru_prev, "", sizeof (fru_prev)) == 0) {
   1069 				strncpy(fru_prev, fru_name, sizeof (fru_name));
   1070 				mid_prev = *mid;
   1071 				ecache_size_prev = ecache_size;
   1072 				continue;
   1073 			} else {
   1074 				if (strncmp(fru_name, fru_prev,
   1075 				    sizeof (fru_prev)) == 0) {
   1076 					/*
   1077 					 * Jaguar has a split E$, so the size
   1078 					 * for both cores must be added together
   1079 					 * to get the total size for the entire
   1080 					 * chip.
   1081 					 *
   1082 					 * Panther E$ (L3) is logically shared,
   1083 					 * so the total size is equal to the
   1084 					 * core size.
   1085 					 */
   1086 					if (IS_JAGUAR(*impl)) {
   1087 						ecache_size += ecache_size_prev;
   1088 					}
   1089 
   1090 					ecache_size_prev = 0;
   1091 					strncpy(fru_prev, "",
   1092 					    sizeof (fru_prev));
   1093 				} else {
   1094 					mid_prev = *mid;
   1095 					ecache_size_prev = ecache_size;
   1096 					strncpy(fru_prev, fru_name,
   1097 					    sizeof (fru_name));
   1098 					continue;
   1099 				}
   1100 			}
   1101 		}
   1102 
   1103 		/*
   1104 		 * If cpu is not configured, do not display it
   1105 		 */
   1106 		CFG_SET_FRU_NAME_NODE(cfg_fru_name, board->node_id);
   1107 		CFG_SET_FRU_NAME_CPU_BOARD(cfg_fru_name, board_num);
   1108 		CFG_SET_FRU_NAME_MODULE(cfg_fru_name, *mid % 4);
   1109 
   1110 		if (!(cpu_node_configured(cfg_fru_name))) {
   1111 			continue;
   1112 		}
   1113 
   1114 
   1115 		log_printf("%-10s  ", fru_name, 0);
   1116 
   1117 		/* CPU MID */
   1118 		if (CPU_IMPL_IS_CMP(*impl)) {
   1119 			log_printf("%3d,%3d ", mid_prev, *mid, 0);
   1120 			mid_prev = -1;
   1121 		} else
   1122 			log_printf("%3d     ", *mid, 0);
   1123 
   1124 		/* Running frequency */
   1125 		log_printf(" %4u  ", freq, 0);
   1126 
   1127 		/* Ecache size */
   1128 		if (ecache_size == 0)
   1129 			log_printf("%3s  ", "N/A", 0);
   1130 		else
   1131 			log_printf("%4.1f  ",
   1132 			    (float)ecache_size / (float)(1<<20),
   1133 			    0);
   1134 
   1135 		/* Implementation */
   1136 		if (impl == NULL) {
   1137 			log_printf("%6s  ", " N/A", 0);
   1138 		} else {
   1139 			switch (*impl) {
   1140 			case CHEETAH_IMPL:
   1141 				log_printf("%-7s ", "US-III", 0);
   1142 				break;
   1143 			case CHEETAH_PLUS_IMPL:
   1144 				log_printf("%-7s ", "US-III+", 0);
   1145 				break;
   1146 			case JAGUAR_IMPL:
   1147 				log_printf("%-7s ", "US-IV", 0);
   1148 				break;
   1149 			case PANTHER_IMPL:
   1150 				log_printf("%-7s ", "US-IV+", 0);
   1151 				break;
   1152 			default:
   1153 				log_printf("%-7x ", *impl, 0);
   1154 				break;
   1155 			}
   1156 		}
   1157 
   1158 		/* CPU Mask */
   1159 		if (mask == NULL) {
   1160 			log_printf(" %3s   ", "N/A", 0);
   1161 		} else {
   1162 			if (IS_CHEETAH(*impl))
   1163 				decoded_mask = REMAP_CHEETAH_MASK(*mask);
   1164 			else
   1165 				decoded_mask = *mask;
   1166 
   1167 			log_printf(" %d.%d   ",
   1168 			    (decoded_mask >> 4) & 0xf,
   1169 			    decoded_mask & 0xf, 0);
   1170 		}
   1171 
   1172 		log_printf("\n", 0);
   1173 	}
   1174 }
   1175 
   1176 
   1177 /*ARGSUSED3*/
   1178 void
   1179 display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
   1180 	struct system_kstat_data *kstats)
   1181 {
   1182 	log_printf("\n", 0);
   1183 	log_printf("=========================", 0);
   1184 	log_printf(dgettext(TEXT_DOMAIN, " Hardware Failures "), 0);
   1185 	log_printf("==================================", 0);
   1186 	log_printf("\n", 0);
   1187 
   1188 	/*
   1189 	 * Get a list of failed parts (ie. devices with a status of
   1190 	 * 'fail') from the OBP device tree and display them.
   1191 	 */
   1192 	get_failed_parts();
   1193 
   1194 	/* return unless -v option specified */
   1195 	if (!flag) {
   1196 		log_printf("\n", 0);
   1197 		return;
   1198 	}
   1199 
   1200 	/*
   1201 	 * display time of latest powerfail. Not all systems
   1202 	 * have this capability. For those that do not, this
   1203 	 * is just a no-op.
   1204 	 */
   1205 	disp_powerfail(root);
   1206 
   1207 	/* Print the PROM revisions here */
   1208 	serengeti_display_hw_revisions(root, tree->bd_list);
   1209 }
   1210 
   1211 /*
   1212  * local functions -  functions that are only needed inside this library
   1213  */
   1214 
   1215 static void
   1216 serengeti_display_hw_revisions(Prom_node *root, Board_node *bdlist)
   1217 {
   1218 	Prom_node	*pnode;
   1219 	char		*value;
   1220 
   1221 	/* Print the header */
   1222 	log_printf("\n", 0);
   1223 	log_printf("=========================", 0);
   1224 	log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
   1225 	log_printf("=======================================", 0);
   1226 	log_printf("\n", 0);
   1227 	log_printf("\n", 0);
   1228 
   1229 	/* Display Prom revision header */
   1230 	log_printf("System PROM revisions:\n", 0);
   1231 	log_printf("----------------------\n", 0);
   1232 
   1233 	/*
   1234 	 * Display OBP version info
   1235 	 */
   1236 	pnode = dev_find_node(root, "openprom");
   1237 	if (pnode != NULL) {
   1238 		value = (char *)get_prop_val(find_prop(pnode, "version"));
   1239 		log_printf("%s\n\n", value, 0);
   1240 	} else {
   1241 		log_printf("OBP ???\n\n", value, 0);
   1242 	}
   1243 
   1244 	/*
   1245 	 * Display ASIC revisions
   1246 	 */
   1247 	log_printf("IO ASIC revisions:\n", 0);
   1248 	log_printf("------------------\n", 0);
   1249 
   1250 	log_printf("                            Port\n", 0);
   1251 	log_printf("FRU Name    Model            ID    Status", 0);
   1252 #ifdef DEBUG
   1253 	log_printf("   Version  Notes\n", 0);
   1254 #else
   1255 	log_printf("   Version\n", 0);
   1256 #endif
   1257 	/* ---------FRU Name--Model-----------Port-Status */
   1258 	log_printf("----------- --------------- ---- ---------- "
   1259 #ifdef DEBUG
   1260 	    "-------  "
   1261 #endif
   1262 	    "-------\n", 0);
   1263 	/*
   1264 	 * Display SCHIZO version info
   1265 	 */
   1266 	display_schizo_revisions(bdlist, SG_SCHIZO_GOOD);
   1267 
   1268 	/*
   1269 	 * Display sgsbbc version info
   1270 	 */
   1271 	display_sgsbbc_revisions(bdlist);
   1272 }
   1273 
   1274 /*
   1275  * This function displays Schizo and Xmits revision of boards
   1276  */
   1277 static int
   1278 display_schizo_revisions(Board_node *bdlist, int mode)
   1279 {
   1280 	Prom_node	*pnode;
   1281 	int		*int_val;
   1282 	int		portid;
   1283 	int		prev_portid = -1;
   1284 	char		*model;
   1285 	char		*status_a, *status_b;
   1286 	char		status[MAX_STATUS_LEN];
   1287 	int		version;
   1288 	int 		node_id;
   1289 #ifdef DEBUG
   1290 	uint32_t	a_notes, b_notes;
   1291 #endif
   1292 	int		pci_bus;
   1293 	/*
   1294 	 * rv is used when mode is set to SG_SCHIZO_FAILED.
   1295 	 * We need to signal if a failure is found so that
   1296 	 * the correct headers/footers can be printed.
   1297 	 *
   1298 	 * rv = 1 implies a failed/disavled schizo device
   1299 	 * rv = 0 implies all other cases
   1300 	 */
   1301 	int		rv = 0;
   1302 	Board_node	*bnode;
   1303 	void		*value;
   1304 
   1305 	bnode = bdlist;
   1306 	while (bnode != NULL) {
   1307 		/*
   1308 		 * search this board node for all Schizos
   1309 		 */
   1310 		for (pnode = dev_find_node_by_compatible(bnode->nodes,
   1311 		    SCHIZO_COMPATIBLE); pnode != NULL;
   1312 		    pnode = dev_next_node_by_compatible(pnode,
   1313 		    SCHIZO_COMPATIBLE)) {
   1314 
   1315 			char	fru_name[MAX_FRU_NAME_LEN] = "";
   1316 
   1317 			/*
   1318 			 * get the reg property to determine
   1319 			 * whether we are looking at side A or B
   1320 			 */
   1321 			int_val = (int *)get_prop_val
   1322 			    (find_prop(pnode, "reg"));
   1323 			if (int_val != NULL) {
   1324 				int_val ++; /* second integer in array */
   1325 				pci_bus = ((*int_val) & 0x7f0000);
   1326 			}
   1327 
   1328 			/* get portid */
   1329 			int_val = (int *)get_prop_val
   1330 			    (find_prop(pnode, "portid"));
   1331 			if (int_val == NULL)
   1332 				continue;
   1333 
   1334 			portid = *int_val;
   1335 
   1336 			/*
   1337 			 * If this is a new portid and it is PCI bus B,
   1338 			 * we skip onto the PCI bus A. (PCI-A and PCI-B share
   1339 			 * the same portid)
   1340 			 */
   1341 			if ((portid != prev_portid) && (pci_bus == 0x700000)) {
   1342 				prev_portid = portid;
   1343 				/* status */
   1344 				status_b = (char *)get_prop_val
   1345 				    (find_prop(pnode, "status"));
   1346 #ifdef DEBUG
   1347 				b_notes = pci_bus;
   1348 #endif
   1349 				continue; /* skip to the next schizo */
   1350 			}
   1351 
   1352 			/*
   1353 			 * This must be side A of the same Schizo.
   1354 			 * Gather all its props and display them.
   1355 			 */
   1356 #ifdef DEBUG
   1357 			a_notes = pci_bus;
   1358 #endif
   1359 
   1360 			prev_portid = portid;
   1361 
   1362 			/* get the node-id */
   1363 			node_id =  SG_PORTID_TO_NODEID(portid);
   1364 
   1365 			/* model */
   1366 			model = (char *)get_prop_val
   1367 			    (find_prop(pnode, "model"));
   1368 
   1369 			/* version */
   1370 			value = (int *)get_prop_val
   1371 			    (find_prop(pnode, "module-revision#"));
   1372 
   1373 			if (value)
   1374 				int_val = (int *)value;
   1375 			else
   1376 				int_val = (int *)get_prop_val
   1377 				    (find_prop(pnode, "version#"));
   1378 			if (int_val != NULL)
   1379 				version = *int_val;
   1380 			else
   1381 				version = -1;
   1382 
   1383 			/* status */
   1384 			status_a = (char *)get_prop_val(find_prop
   1385 			    (pnode, "status"));
   1386 
   1387 			/*
   1388 			 * Display the data
   1389 			 */
   1390 			/* FRU Name */
   1391 			SG_SET_FRU_NAME_NODE(fru_name, node_id);
   1392 			SG_SET_FRU_NAME_IO_BOARD(fru_name,
   1393 			    SG_IO_BD_PORTID_TO_BD_NUM(portid));
   1394 			SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
   1395 
   1396 			if (mode == SG_SCHIZO_FAILED) {
   1397 				if ((status_a != (char *)NULL) &&
   1398 				    ((status_b != (char *)NULL))) {
   1399 					if ((strcmp
   1400 					    (status_a, SG_DISABLED) == 0) &&
   1401 					    (strcmp(status_b,
   1402 					    SG_DISABLED) == 0)) {
   1403 						log_printf("\tFRU Type : %s\n ",
   1404 						    model, 0);
   1405 						log_printf("\tLocation : %s\n",
   1406 						    fru_name, 0);
   1407 						log_printf
   1408 						    ("\tPROM status: %s\n\n",
   1409 						    SG_DISABLED, 0);
   1410 						rv = 1;
   1411 					}
   1412 				}
   1413 				continue;
   1414 			}
   1415 			/*
   1416 			 * This section of code is executed when displaying
   1417 			 * non-failed schizo devices.  If the mode is set to
   1418 			 * SG_SCHIZO_FAILED, then this section of code will
   1419 			 * not be executed
   1420 			 */
   1421 			if ((status_a == (char *)NULL) &&
   1422 			    ((status_b == (char *)NULL)))
   1423 				sprintf(status, " %s      ", SG_OK);
   1424 			else if ((status_a == (char *)NULL) &&
   1425 			    ((strcmp(status_b, SG_DISABLED) == 0)))
   1426 				sprintf(status, " %s", SG_DEGRADED);
   1427 			else if ((status_b == (char *)NULL) &&
   1428 			    ((strcmp(status_a, SG_DISABLED) == 0)))
   1429 				sprintf(status, " %s", SG_DEGRADED);
   1430 			else
   1431 				continue;
   1432 
   1433 			log_printf("%-12s", fru_name, 0);
   1434 
   1435 			/* model */
   1436 
   1437 			if (model != NULL)
   1438 				log_printf("%-15s  ", model, 0);
   1439 			else
   1440 				log_printf("%-15s  ", "unknown", 0);
   1441 			/* portid */
   1442 			log_printf("%-3d ", portid, 0);
   1443 
   1444 			/* status */
   1445 			log_printf("%s", status, 0);
   1446 
   1447 			/* version */
   1448 			log_printf("     %-4d   ", version, 0);
   1449 #ifdef DEBUG
   1450 			log_printf("0x%x 0x%x", a_notes, b_notes, 0);
   1451 			log_printf(" %d", portid, 0);
   1452 #endif
   1453 			log_printf("\n", 0);
   1454 		}
   1455 		bnode = bnode->next;
   1456 	}
   1457 	return (rv);
   1458 }
   1459 
   1460 static void
   1461 display_sgsbbc_revisions(Board_node *bdlist)
   1462 {
   1463 
   1464 	Prom_node	*pnode;
   1465 	int		*int_val;
   1466 	int		portid;
   1467 	char		*model;
   1468 	char		*status;
   1469 	int		revision;
   1470 	int 		node_id;
   1471 	Board_node	*bnode;
   1472 
   1473 #ifdef DEBUG
   1474 	char	*slot_name;
   1475 	char	notes[30];
   1476 	char	*value;
   1477 #endif
   1478 
   1479 	bnode = bdlist;
   1480 	while (bnode != NULL) {
   1481 		/*
   1482 		 * search this board node for all sgsbbc's
   1483 		 */
   1484 		for (pnode = dev_find_node_by_type(bnode->nodes, "model",
   1485 		    "SUNW,sgsbbc"); pnode != NULL;
   1486 		    pnode = dev_next_node_by_type(pnode, "model",
   1487 		    "SUNW,sgsbbc")) {
   1488 
   1489 			char	fru_name[MAX_FRU_NAME_LEN] = "";
   1490 
   1491 			/*
   1492 			 * We need to go to this node's parent to
   1493 			 * get a portid to tell us what board it is on
   1494 			 */
   1495 			int_val = (int *)get_prop_val
   1496 			    (find_prop(pnode->parent, "portid"));
   1497 			if (int_val == NULL)
   1498 				continue;
   1499 
   1500 			portid = *int_val;
   1501 			/* get the node-id */
   1502 			node_id =  SG_PORTID_TO_NODEID(portid);
   1503 
   1504 			/* model */
   1505 			model = (char *)get_prop_val
   1506 			    (find_prop(pnode, "model"));
   1507 
   1508 			/* status */
   1509 			status = (char *)get_prop_val(find_prop
   1510 			    (pnode, "status"));
   1511 
   1512 			/* revision */
   1513 			int_val = (int *)get_prop_val
   1514 			    (find_prop(pnode, "revision-id"));
   1515 			if (int_val != NULL)
   1516 				revision = *int_val;
   1517 			else
   1518 				revision = -1;
   1519 
   1520 #ifdef DEBUG
   1521 			value = (char *)get_prop_val(
   1522 			    find_prop(pnode->parent, "slot-names"));
   1523 			if (value != NULL) {
   1524 				/* Skip the 4 byte bitmask */
   1525 				slot_name = (char *)value + sizeof (int);
   1526 			} else {
   1527 				strcpy(slot_name, "not_found");
   1528 			}
   1529 			(void) sprintf(notes, "[%s] portid [%d]", slot_name,
   1530 			    portid);
   1531 #endif
   1532 			/*
   1533 			 * Display the data
   1534 			 */
   1535 			/* FRU Name */
   1536 			SG_SET_FRU_NAME_NODE(fru_name, node_id);
   1537 			SG_SET_FRU_NAME_IO_BOARD(fru_name,
   1538 			    SG_IO_BD_PORTID_TO_BD_NUM(portid));
   1539 			SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
   1540 			log_printf("%-12s", fru_name, 0);
   1541 
   1542 			/* model */
   1543 			if (model != NULL)
   1544 				log_printf("%-15s  ", model, 0);
   1545 			else
   1546 				log_printf("%-15s  ", "unknown", 0);
   1547 			/* portid */
   1548 			log_printf("%-3d ", portid, 0);
   1549 			/* status */
   1550 			if (status == (char *)NULL)
   1551 				log_printf(" ok      ", 0);
   1552 			else
   1553 				log_printf(" fail    ", 0);
   1554 			/* revision */
   1555 			log_printf("     %-4d   ", revision, 0);
   1556 #ifdef DEBUG
   1557 			log_printf("%s", notes, 0);
   1558 #endif
   1559 			log_printf("\n", 0);
   1560 		}
   1561 		bnode = bnode->next;
   1562 	}
   1563 }
   1564 
   1565 /*ARGSUSED0*/
   1566 void
   1567 display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
   1568 {
   1569 	serengeti_display_board_info(ACTIVE);
   1570 	serengeti_display_board_info(INACTIVE);
   1571 }
   1572 
   1573 /*
   1574  * display_failed_parts
   1575  *
   1576  * Display the failed parts in the system. This function looks for
   1577  * the status property in all PROM nodes contained in the Sys_tree
   1578  * passed in.
   1579  */
   1580 int
   1581 display_failed_parts(Sys_tree *tree)
   1582 {
   1583 	int system_failed = 0;
   1584 	int bank_failed = 0;
   1585 	int schizo_failed = FALSE;
   1586 	int portid, nodeid, board;
   1587 	Board_node *bnode = tree->bd_list;
   1588 	Prom_node *pnode;
   1589 	int *coreid, *impl;
   1590 	print_flag = TRUE;
   1591 
   1592 	/*
   1593 	 * go through all of the OBP nodes looking for
   1594 	 * failed units.
   1595 	 */
   1596 	while (bnode != NULL) {
   1597 
   1598 		pnode = find_failed_node(bnode->nodes);
   1599 		if ((pnode != NULL) && !system_failed) {
   1600 			system_failed = TRUE;
   1601 			log_printf("\n", 0);
   1602 			log_printf(dgettext(TEXT_DOMAIN,
   1603 			    "Failed Field Replaceable Units (FRU) in "
   1604 			    "System:\n"), 0);
   1605 			log_printf("=========================="
   1606 			    "====================\n", 0);
   1607 		}
   1608 
   1609 		while (pnode != NULL) {
   1610 			void *status;
   1611 			char *name, *type, *model;
   1612 
   1613 			char	fru_name[MAX_FRU_NAME_LEN] = "";
   1614 
   1615 			status = get_prop_val(find_prop(pnode, "status"));
   1616 			name = get_node_name(pnode);
   1617 
   1618 			/* sanity check of data retreived from PROM */
   1619 			if ((status == NULL) || (name == NULL)) {
   1620 				pnode = next_failed_node(pnode);
   1621 				continue;
   1622 			}
   1623 
   1624 			type = get_node_type(pnode);
   1625 			portid = get_id(pnode);
   1626 			model = (char *)get_prop_val
   1627 			    (find_prop(pnode, "model"));
   1628 
   1629 			/*
   1630 			 * Determine whether FRU is CPU module, Mem Controller,
   1631 			 * PCI card, schizo,xmits or sgsbbc.
   1632 			 */
   1633 			if ((model != NULL) && strstr(model, "sgsbbc")) {
   1634 				/*
   1635 				 * sgsbbc / bootbus-controller
   1636 				 */
   1637 				portid = get_id(pnode->parent);
   1638 				nodeid = SG_PORTID_TO_NODEID(portid);
   1639 				board = SG_PORTID_TO_BOARD_NUM(portid);
   1640 
   1641 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
   1642 				SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
   1643 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
   1644 
   1645 				log_printf("\tFailed Device : %s (%s)\n", model,
   1646 				    name, 0);
   1647 				log_printf("\tLocation : %s\n", fru_name, 0);
   1648 
   1649 			} else if (strstr(name, "pci") && (portid == -1)) {
   1650 				/*
   1651 				 * PCI Bridge if name = pci and it doesn't
   1652 				 * have a portid.
   1653 				 */
   1654 				portid = get_id(pnode->parent);
   1655 				nodeid = SG_PORTID_TO_NODEID(portid);
   1656 				board = SG_PORTID_TO_BOARD_NUM(portid);
   1657 
   1658 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
   1659 				SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
   1660 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
   1661 
   1662 				log_printf("\tFRU type : ", 0);
   1663 				log_printf("PCI Bridge Device\n", 0);
   1664 				log_printf("\tLocation : %s\n", fru_name, 0);
   1665 
   1666 			} else if ((type != NULL) &&
   1667 			    (strstr(type, "cpu") ||
   1668 			    strstr(type, "memory-controller"))) {
   1669 				/*
   1670 				 * CPU or memory controller
   1671 				 */
   1672 				portid = get_id(pnode);
   1673 				/*
   1674 				 * For cpu nodes that belong to a CMP, the
   1675 				 * portid is stored in the parent "cmp" node.
   1676 				 */
   1677 				if (portid == -1)
   1678 					portid = get_id(pnode->parent);
   1679 				nodeid = SG_PORTID_TO_NODEID(portid);
   1680 				board = SG_PORTID_TO_BOARD_NUM(portid);
   1681 
   1682 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
   1683 				SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
   1684 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 4);
   1685 
   1686 				log_printf("\tFRU type : ", 0);
   1687 
   1688 				if (strstr(type, "memory-controller"))
   1689 					log_printf("Memory Controller on ", 0);
   1690 
   1691 				log_printf("UltraSPARC module\n", 0);
   1692 
   1693 				log_printf("\tLocation : %s\n", fru_name, 0);
   1694 
   1695 			} else {
   1696 				/*
   1697 				 * It should only be a PCI card if we get to
   1698 				 * here but lets check to be sure.
   1699 				 */
   1700 				char *parents_model, *grandparents_model;
   1701 				Prom_node *parent_pnode;
   1702 				int pci_card_found = 0;
   1703 
   1704 				if (pnode->parent != NULL)
   1705 					parent_pnode = pnode->parent;
   1706 
   1707 				/*
   1708 				 * Is our parent a schizo or xmits
   1709 				 */
   1710 				parents_model = (char *)get_prop_val
   1711 				    (find_prop(pnode->parent, "model"));
   1712 				if ((parents_model != NULL) &&
   1713 				    (strstr(parents_model, "SUNW,schizo") ||
   1714 				    strstr(parents_model, "SUNW,xmits"))) {
   1715 					portid = get_id(pnode->parent);
   1716 					pci_card_found = TRUE;
   1717 				}
   1718 
   1719 				/*
   1720 				 * Is our grandparent a schizo xmits
   1721 				 */
   1722 				grandparents_model = (char *)get_prop_val
   1723 				    (find_prop(parent_pnode->parent, "model"));
   1724 				if ((grandparents_model != NULL) &&
   1725 				    (strstr(grandparents_model,
   1726 				    "SUNW,schizo") ||
   1727 				    strstr(grandparents_model,
   1728 				    "SUNW,xmits"))) {
   1729 					portid = get_id(parent_pnode->parent);
   1730 					pci_card_found = TRUE;
   1731 				}
   1732 
   1733 				if (pci_card_found) {
   1734 					nodeid = SG_PORTID_TO_NODEID(portid);
   1735 					board = SG_PORTID_TO_BOARD_NUM(portid);
   1736 
   1737 					SG_SET_FRU_NAME_NODE(fru_name, nodeid);
   1738 					SG_SET_FRU_NAME_IO_BOARD(fru_name,
   1739 					    board);
   1740 					SG_SET_FRU_NAME_MODULE(fru_name,
   1741 					    portid % 2);
   1742 
   1743 					log_printf("\tFRU type :", 0);
   1744 					log_printf(" PCI Card\n", 0);
   1745 					log_printf("\tLocation : %s\n",
   1746 					    fru_name, 0);
   1747 				}
   1748 			}
   1749 			log_printf("\tPROM status: %s\n\n", status, 0);
   1750 
   1751 			pnode = next_failed_node(pnode);
   1752 		}
   1753 		bnode = bnode->next;
   1754 
   1755 	}
   1756 
   1757 	bank_failed = display_us3_failed_banks(system_failed);
   1758 	schizo_failed = display_schizo_revisions(tree->bd_list,
   1759 	    SG_SCHIZO_FAILED);
   1760 	if (system_failed || bank_failed || schizo_failed)
   1761 		return (1);
   1762 	else
   1763 		return (0);
   1764 }
   1765 
   1766 
   1767 /*
   1768  * This routine displays the memory configuration for all boards in the
   1769  * system.
   1770  */
   1771 /*ARGSUSED0*/
   1772 void
   1773 display_memoryconf(Sys_tree *tree, struct grp_info *grps)
   1774 {
   1775 	Board_node	*bnode = tree->bd_list;
   1776 
   1777 	log_printf("========================= Memory Configuration"
   1778 	    " ===============================\n", 0);
   1779 	log_printf("\n                     Logical  Logical  Logical ", 0);
   1780 	log_printf("\n               Port  Bank     Bank     Bank         "
   1781 	    "DIMM    Interleave  Interleave", 0);
   1782 	log_printf("\nFRU Name        ID   Num      Size     Status       "
   1783 	    "Size    Factor      Segment", 0);
   1784 	log_printf("\n-------------  ----  ----     ------   -----------  "
   1785 	    "------  ----------  ----------", 0);
   1786 
   1787 	while (bnode != NULL) {
   1788 		if (get_us3_mem_regs(bnode)) {
   1789 			log_printf(dgettext(TEXT_DOMAIN,
   1790 			    "\nFailed to get memory information.\n"), 0);
   1791 			return;
   1792 		}
   1793 		bnode = bnode->next;
   1794 	}
   1795 
   1796 	/* Display what we have found */
   1797 	display_us3_banks();
   1798 }
   1799 
   1800 /*
   1801  * This function provides Serengeti's formatting of the memory config
   1802  * information that get_us3_mem_regs() and display_us3_banks() code has
   1803  * gathered. It overrides the generic print_us3_memory_line() code
   1804  * which prints an error message.
   1805  */
   1806 void
   1807 print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
   1808 	char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
   1809 {
   1810 	int		nodeid, board, mcid;
   1811 	char		fru_name[MAX_FRU_NAME_LEN] = "";
   1812 
   1813 	mcid 		= SG_PORTID_TO_SAFARI_ID(portid);
   1814 	nodeid 		= SG_PORTID_TO_NODEID(portid);
   1815 	board 		= SG_PORTID_TO_BOARD_NUM(portid);
   1816 
   1817 	SG_SET_FRU_NAME_NODE(fru_name, nodeid);
   1818 	SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
   1819 	SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
   1820 	SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
   1821 
   1822 	log_printf("\n%-13s   %2d   %2d      %4lldMB    %11-s  %4lldMB "
   1823 	    "   %2d-way       %d",
   1824 	    fru_name, mcid,
   1825 	    (bank_id % 4), bank_size, bank_status, dimm_size,
   1826 	    intlv, seg_id, 0);
   1827 }
   1828 
   1829 void
   1830 print_us3_failed_memory_line(int portid, int bank_id, char *bank_status)
   1831 {
   1832 	int		nodeid, board, mcid;
   1833 	char		fru_name[MAX_FRU_NAME_LEN] = "";
   1834 
   1835 	mcid		= SG_PORTID_TO_SAFARI_ID(portid);
   1836 	nodeid		= SG_PORTID_TO_NODEID(portid);
   1837 	board		= SG_PORTID_TO_BOARD_NUM(portid);
   1838 
   1839 	SG_SET_FRU_NAME_NODE(fru_name, nodeid);
   1840 	SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
   1841 	SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
   1842 	SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
   1843 
   1844 	log_printf("\tFRU type : ", 0);
   1845 	log_printf("Physical Memory Bank\n", 0);
   1846 	log_printf("\tLocation : %s (Logical Bank %2d)\n",
   1847 	    fru_name, (bank_id %4), 0);
   1848 	log_printf("\tPROM status: %s\n\n", bank_status, 0);
   1849 }
   1850 
   1851 
   1852 /*
   1853  * Find the requested board struct in the system device tree.
   1854  *
   1855  * This function overrides the functionality of the generic find_board()
   1856  * function in libprtdiag, but since we need to pass another parameter,
   1857  * we cannot simply overlay the symbol table.
   1858  */
   1859 static Board_node *
   1860 serengeti_find_board(Sys_tree *root, int board, int nodeid)
   1861 {
   1862 	Board_node *bnode = root->bd_list;
   1863 
   1864 	while ((bnode != NULL) &&
   1865 	    ((board != bnode->board_num) || (nodeid != bnode->node_id))) {
   1866 		bnode = bnode->next;
   1867 	}
   1868 	return (bnode);
   1869 }
   1870 
   1871 
   1872 /*
   1873  * Add a board to the system list in order (sorted by NodeID then board#).
   1874  * Initialize all pointer fields to NULL.
   1875  */
   1876 static Board_node *
   1877 serengeti_insert_board(Sys_tree *root, int board, int nodeid)
   1878 {
   1879 	Board_node *bnode;
   1880 	Board_node *temp = root->bd_list;
   1881 
   1882 	if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
   1883 		perror("malloc");
   1884 		exit(1);
   1885 	}
   1886 
   1887 	bnode->nodes = NULL;
   1888 	bnode->next = NULL;
   1889 	bnode->board_num = board;
   1890 	bnode->node_id = nodeid;
   1891 	bnode->board_type = UNKNOWN_BOARD;
   1892 
   1893 	if (temp == NULL)
   1894 		root->bd_list = bnode;
   1895 
   1896 	else if ((temp->board_num > board) && (temp->node_id >= nodeid)) {
   1897 		bnode->next = temp;
   1898 		root->bd_list = bnode;
   1899 
   1900 	} else {
   1901 		while ((temp->next != NULL) &&
   1902 		    ((board > temp->next->board_num) ||
   1903 		    (nodeid > temp->node_id)))
   1904 			temp = temp->next;
   1905 
   1906 		bnode->next = temp->next;
   1907 		temp->next = bnode;
   1908 	}
   1909 	root->board_cnt++;
   1910 
   1911 	return (bnode);
   1912 }
   1913 
   1914 /*
   1915  * We call do_devinfo() in order to use the libdevinfo device tree
   1916  * instead of OBP's device tree.
   1917  */
   1918 int
   1919 do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
   1920 {
   1921 
   1922 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
   1923 
   1924 }
   1925 
   1926 /*
   1927  * return the property value for the Prop passed in depending on
   1928  * which tree (OBP/DEVINFO) is being used.
   1929  */
   1930 void *
   1931 get_prop_val(Prop *prop)
   1932 {
   1933 	if (prop == NULL)
   1934 		return (NULL);
   1935 
   1936 	/* Check which tree is being used. */
   1937 	if (tree == DEVINFO_TREE)
   1938 		return ((void *)(prop->value.val_ptr));
   1939 	else {
   1940 		if (prop->value.opp.holds_array)
   1941 			return ((void *)(prop->value.opp.oprom_array));
   1942 		else
   1943 			return ((void *)(&prop->value.opp.oprom_node[0]));
   1944 	}
   1945 }
   1946 
   1947 /*
   1948  * Search a Prom node and retrieve the property with the correct
   1949  * name depending on which tree (OBP/DEVINFO) is being used.
   1950  */
   1951 Prop *
   1952 find_prop(Prom_node *pnode, char *name)
   1953 {
   1954 	Prop *prop;
   1955 
   1956 	if (pnode  == NULL)
   1957 		return (NULL);
   1958 
   1959 	if (pnode->props == NULL)
   1960 		return (NULL);
   1961 
   1962 	prop = pnode->props;
   1963 
   1964 	/* Check which tree is being used. */
   1965 	if (tree == DEVINFO_TREE) {
   1966 		while ((prop != NULL) &&
   1967 		    (strcmp((char *)(prop->name.val_ptr), name)))
   1968 			prop = prop->next;
   1969 	} else {
   1970 		while ((prop != NULL) && (strcmp((char *)
   1971 		    (prop->name.opp.oprom_array), name)))
   1972 			prop = prop->next;
   1973 	}
   1974 	return (prop);
   1975 }
   1976 
   1977 /*
   1978  * This function searches through the properties of the node passed in
   1979  * and returns a pointer to the value of the name property
   1980  * depending on which tree (OBP/DEVINFO) is being used.
   1981  */
   1982 char *
   1983 get_node_name(Prom_node *pnode)
   1984 {
   1985 	Prop *prop;
   1986 
   1987 	if (pnode == NULL)
   1988 		return (NULL);
   1989 
   1990 	prop = pnode->props;
   1991 	while (prop != NULL) {
   1992 		/* Check which tree is being used. */
   1993 		if (tree == DEVINFO_TREE) {
   1994 			if (strcmp("name", (char *)prop->name.val_ptr) == 0)
   1995 				return ((char *)prop->value.val_ptr);
   1996 		} else {
   1997 			if (strcmp("name", prop->name.opp.oprom_array) == 0)
   1998 				return (prop->value.opp.oprom_array);
   1999 		}
   2000 		prop = prop->next;
   2001 	}
   2002 	return (NULL);
   2003 }
   2004 
   2005 /*
   2006  * This function searches through the properties of the node passed in
   2007  * and returns a pointer to the value of the device_type property
   2008  * depending on which tree (OBP/DEVINFO) is being used.
   2009  */
   2010 char *
   2011 get_node_type(Prom_node *pnode)
   2012 {
   2013 	Prop *prop;
   2014 
   2015 	if (pnode == NULL)
   2016 		return (NULL);
   2017 
   2018 	prop = pnode->props;
   2019 	while (prop != NULL) {
   2020 		/* Check which tree is being used. */
   2021 		if (tree == DEVINFO_TREE) {
   2022 			if (strcmp("device_type", (char *)prop->name.val_ptr)
   2023 			    == 0)
   2024 				return ((char *)prop->value.val_ptr);
   2025 		} else {
   2026 			if (strcmp("device_type", prop->name.opp.oprom_array)
   2027 			    == 0)
   2028 				return (prop->value.opp.oprom_array);
   2029 		}
   2030 		prop = prop->next;
   2031 	}
   2032 	return (NULL);
   2033 }
   2034 
   2035 /*
   2036  * Take a snapshot of the OBP device tree and walk this snapshot
   2037  * to find all failed HW (ie. devices with a status property of
   2038  * 'fail'). Call display_failed_parts() to display the failed HW.
   2039  */
   2040 void
   2041 get_failed_parts(void)
   2042 {
   2043 	int system_failed = 0;
   2044 	Sys_tree obp_sys_tree;		/* system information */
   2045 
   2046 	/* set the the system tree fields */
   2047 	obp_sys_tree.sys_mem = NULL;
   2048 	obp_sys_tree.boards = NULL;
   2049 	obp_sys_tree.bd_list = NULL;
   2050 	obp_sys_tree.board_cnt = 0;
   2051 
   2052 	if (promopen(O_RDONLY)) {
   2053 		(void) fprintf(stderr, "%s",
   2054 		    dgettext(TEXT_DOMAIN, "openprom device "
   2055 		    "open failed"));
   2056 		return;
   2057 	}
   2058 
   2059 	if ((is_openprom() == 0) || (next(0) == 0)) {
   2060 		(void) fprintf(stderr, "%s",
   2061 		    dgettext(TEXT_DOMAIN, "openprom device "
   2062 		    "error encountered."));
   2063 		return;
   2064 	}
   2065 
   2066 	tree = OBP_TREE;	/* Switch to the OBP tree */
   2067 
   2068 	(void) walk(&obp_sys_tree, NULL, next(0));
   2069 
   2070 	system_failed = display_failed_parts(&obp_sys_tree);
   2071 
   2072 	if (!system_failed) {
   2073 		log_printf(dgettext(TEXT_DOMAIN,
   2074 		    "No Hardware failures found in System\n"), 0);
   2075 	}
   2076 	promclose();
   2077 	tree = DEVINFO_TREE;	/* Switch back to the DEVINFO tree */
   2078 }
   2079 
   2080 /*
   2081  * get_slot_name figures out the slot no. for the card. In the case of
   2082  * XMITS slots 2 & 3 and slots 6 & 7 are reversed in slot_name by OBP
   2083  * so we need to cater for this to correctly identify the slot no.
   2084  */
   2085 static void
   2086 get_slot_name(struct io_card *card, char *slot_name)
   2087 {
   2088 	char tmp_ptr[2];
   2089 
   2090 	if (strlen(slot_name) != 0) {
   2091 		if (strcmp(card->notes, XMITS_COMPATIBLE) == 0) {
   2092 			(void) sprintf(tmp_ptr, "%c",
   2093 			    slot_name[strlen(slot_name) -1]);
   2094 			switch (tmp_ptr[0]) {
   2095 			case '2':
   2096 				(void) sprintf(card->slot_str, "%c", '3');
   2097 				break;
   2098 			case '3':
   2099 				(void) sprintf(card->slot_str, "%c", '2');
   2100 				break;
   2101 			case '6':
   2102 				(void) sprintf(card->slot_str, "%c", '7');
   2103 				break;
   2104 			case '7':
   2105 				(void) sprintf(card->slot_str, "%c", '6');
   2106 				break;
   2107 			default:
   2108 				(void) sprintf(card->slot_str, "%c",
   2109 				    slot_name[strlen(slot_name) -1]);
   2110 			}
   2111 		} else
   2112 			(void) sprintf(card->slot_str, "%c",
   2113 			    slot_name[strlen(slot_name) -1]);
   2114 	} else
   2115 		(void) sprintf(card->slot_str, "-");
   2116 }
   2117