103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
5e79c98e6Szk  * Common Development and Distribution License (the "License").
6e79c98e6Szk  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel /*
22e79c98e6Szk  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2303831d35Sstevel  * Use is subject to license terms.
24*2bcbf80cSPeter Tribble  * Copyright 2020 Peter Tribble.
2503831d35Sstevel  *
2603831d35Sstevel  * Serengeti Platform specific functions.
2703831d35Sstevel  *
2803831d35Sstevel  */
2903831d35Sstevel 
3003831d35Sstevel #include <stdio.h>
3103831d35Sstevel #include <stdlib.h>
3203831d35Sstevel #include <unistd.h>
3303831d35Sstevel #include <kstat.h>
3403831d35Sstevel #include <string.h>
3503831d35Sstevel #include <assert.h>
3603831d35Sstevel #include <alloca.h>
3703831d35Sstevel #include <libintl.h>
3803831d35Sstevel #include <fcntl.h>
3903831d35Sstevel #include <varargs.h>
4003831d35Sstevel 
4103831d35Sstevel #include <sys/openpromio.h>
4203831d35Sstevel #include <sys/sysmacros.h>
4303831d35Sstevel 
4403831d35Sstevel #include <sys/serengeti.h>
4503831d35Sstevel #include <sys/sgfrutypes.h>
4603831d35Sstevel 
4703831d35Sstevel #include <pdevinfo.h>
4803831d35Sstevel #include <display.h>
4903831d35Sstevel #include <pdevinfo_sun4u.h>
5003831d35Sstevel #include <display_sun4u.h>
5103831d35Sstevel #include <libprtdiag.h>
5203831d35Sstevel 
5303831d35Sstevel #include <config_admin.h>
5403831d35Sstevel 
5503831d35Sstevel #if !defined(TEXT_DOMAIN)
5603831d35Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
5703831d35Sstevel #endif
5803831d35Sstevel 
5903831d35Sstevel #define	SCHIZO_COMPATIBLE	"pci108e,8001"
6003831d35Sstevel #define	XMITS_COMPATIBLE	"pci108e,8002"
6103831d35Sstevel 
6203831d35Sstevel #define	ACTIVE		0
6303831d35Sstevel #define	INACTIVE	1
6403831d35Sstevel #define	DISPLAY_INFO	40
6503831d35Sstevel 
6603831d35Sstevel #define	EVNT2STR(e)	((e) == CFGA_STAT_NONE ? "none" : \
6703831d35Sstevel 			    (e) == CFGA_STAT_EMPTY ? "empty" : \
6803831d35Sstevel 			    (e) == CFGA_STAT_DISCONNECTED ? "disconnected" : \
6903831d35Sstevel 			    (e) == CFGA_STAT_CONNECTED ? "connected" : \
7003831d35Sstevel 			    (e) == CFGA_STAT_UNCONFIGURED ? "unconfigured" : \
7103831d35Sstevel 			    (e) == CFGA_STAT_CONFIGURED ? "configured" : \
7203831d35Sstevel 			    "unknown")
7303831d35Sstevel 
7403831d35Sstevel #define	COND2STR(c)	((c) == CFGA_COND_UNKNOWN ? "unknown" : \
7503831d35Sstevel 			    (c) == CFGA_COND_OK ? "ok" : \
7603831d35Sstevel 			    (c) == CFGA_COND_FAILING ? "failing" : \
7703831d35Sstevel 			    (c) == CFGA_COND_FAILED ? "failed" : \
7803831d35Sstevel 			    (c) == CFGA_COND_UNUSABLE ? "unusable" : \
7903831d35Sstevel 			    "???")
8003831d35Sstevel 
8103831d35Sstevel #define	SG_CLK_FREQ_TO_MHZ(x)	(((x) + 500000) / 1000000)
8203831d35Sstevel 
8303831d35Sstevel #define	MAX_STATUS_LEN		8
8403831d35Sstevel #define	SG_FAIL			"fail"
8503831d35Sstevel #define	SG_DISABLED		"disabled"
8603831d35Sstevel #define	SG_DEGRADED		"degraded"
8703831d35Sstevel #define	SG_OK			"ok"
8803831d35Sstevel 
8903831d35Sstevel #define	SG_SCHIZO_FAILED	1
9003831d35Sstevel #define	SG_SCHIZO_GOOD		0
9103831d35Sstevel 
9203831d35Sstevel #define	DEFAULT_MAX_FREQ	66	/* 66 MHz */
9303831d35Sstevel #define	PCIX_MAX_FREQ		100	/* 100 MHz */
9403831d35Sstevel 
9503831d35Sstevel #define	CFG_CPU	"::cpu"
9603831d35Sstevel 
9703831d35Sstevel #define	CFG_SET_FRU_NAME_NODE(str, num) \
9803831d35Sstevel { \
9903831d35Sstevel 	char tmp_str[MAX_FRU_NAME_LEN]; \
10003831d35Sstevel 	sprintf(tmp_str, "/N%d", num); \
10103831d35Sstevel 	strncat(str, tmp_str, sizeof (tmp_str)); \
10203831d35Sstevel }
10303831d35Sstevel 
10403831d35Sstevel #define	CFG_SET_FRU_NAME_CPU_BOARD(str, num) \
10503831d35Sstevel { \
10603831d35Sstevel 	char tmp_str[MAX_FRU_NAME_LEN]; \
10703831d35Sstevel 	sprintf(tmp_str, ".%s%d", SG_HPU_TYPE_CPU_BOARD_ID, num); \
10803831d35Sstevel 	strncat(str, tmp_str, sizeof (tmp_str)); \
10903831d35Sstevel }
11003831d35Sstevel 
11103831d35Sstevel #define	CFG_SET_FRU_NAME_MODULE(str, num) \
11203831d35Sstevel { \
11303831d35Sstevel 	char tmp_str[MAX_FRU_NAME_LEN]; \
11403831d35Sstevel 	sprintf(tmp_str, "%s%d", CFG_CPU, num); \
11503831d35Sstevel 	strncat(str, tmp_str, sizeof (tmp_str)); \
11603831d35Sstevel }
11703831d35Sstevel 
11803831d35Sstevel extern	int	print_flag;
11903831d35Sstevel 
12003831d35Sstevel /*
12103831d35Sstevel  * these functions will overlay the symbol table of libprtdiag
12203831d35Sstevel  * at runtime (Serengeti systems only)
12303831d35Sstevel  */
12403831d35Sstevel int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
12503831d35Sstevel void	*get_prop_val(Prop *prop);
12603831d35Sstevel Prop	*find_prop(Prom_node *pnode, char *name);
12703831d35Sstevel char	*get_node_name(Prom_node *pnode);
12803831d35Sstevel char	*get_node_type(Prom_node *pnode);
12903831d35Sstevel void	add_node(Sys_tree *, Prom_node *);
130aa5636e5SPeter Tribble void	display_pci(Board_node *);
131aa5636e5SPeter Tribble void	display_ffb(Board_node *, int);
13203831d35Sstevel void	display_io_cards(struct io_card *list);
13303831d35Sstevel void	display_cpu_devices(Sys_tree *tree);
13403831d35Sstevel void	display_cpus(Board_node *board);
13503831d35Sstevel void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
13603831d35Sstevel 		struct system_kstat_data *kstats);
13703831d35Sstevel void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
13803831d35Sstevel void	get_failed_parts(void);
13903831d35Sstevel int	display_failed_parts(Sys_tree *tree);
140*2bcbf80cSPeter Tribble void	display_memoryconf(Sys_tree *tree);
14103831d35Sstevel void	print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
14203831d35Sstevel 	    char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
14303831d35Sstevel 
14403831d35Sstevel /* Local Functions */
14503831d35Sstevel static void	serengeti_display_hw_revisions(Prom_node *root,
14603831d35Sstevel 							Board_node *bnode);
14703831d35Sstevel static Board_node *serengeti_find_board(Sys_tree *root, int board, int nodeid);
14803831d35Sstevel static Board_node *serengeti_insert_board(Sys_tree *root, int board, int nid);
14903831d35Sstevel static int	display_schizo_revisions(Board_node *bdlist, int mode);
15003831d35Sstevel static void	display_sgsbbc_revisions(Board_node *bdlist);
15103831d35Sstevel static void	serengeti_display_board_info(int state);
15203831d35Sstevel static void	serengeti_display_board_info_header(int state);
15303831d35Sstevel static boolean_t cpu_node_configured(char *const node);
15403831d35Sstevel static void display_io_max_bus_speed(struct io_card *p);
15503831d35Sstevel static void display_io_slot_info(struct io_card *p);
15603831d35Sstevel static void get_slot_name(struct io_card *card, char *slot_name);
15703831d35Sstevel 
15803831d35Sstevel /* The bus max freq is determined based on board level in use */
15903831d35Sstevel int	board_bus_max_freq = DEFAULT_MAX_FREQ;	/* 66MHz default */
16003831d35Sstevel 
16103831d35Sstevel /*
16203831d35Sstevel  * Serengeti now uses both the devinfo tree and the OBP tree for it's
16303831d35Sstevel  * prtdiag. The devinfo tree is used for getting the HW config of the
16403831d35Sstevel  * system and the OBP device tree is used for listing the failed HW
16503831d35Sstevel  * in the system. This is because devinfo currently does not include
16603831d35Sstevel  * any PROM nodes with a status of 'fail' so we need to go to OBP to
16703831d35Sstevel  * get a list of failed HW. We use the tree flag to allow the same code
16803831d35Sstevel  * to walk both trees.
16903831d35Sstevel  *
17003831d35Sstevel  * We really need to look at having a single tree for all platforms!
17103831d35Sstevel  */
17203831d35Sstevel #define	DEVINFO_TREE	1
17303831d35Sstevel #define	OBP_TREE	2
17403831d35Sstevel 
17503831d35Sstevel static int	tree = DEVINFO_TREE;
17603831d35Sstevel 
17703831d35Sstevel #ifdef DEBUG
17803831d35Sstevel #define	D_PRINTFINDENT	printfindent
17903831d35Sstevel void
printfindent(int indent,char * fmt,...)18003831d35Sstevel printfindent(int indent, char *fmt, ...)
18103831d35Sstevel {
18203831d35Sstevel 	va_list ap;
18303831d35Sstevel 	int i = 0;
18403831d35Sstevel 	for (i = 0; i < indent; i ++)
18503831d35Sstevel 		printf("\t");
18603831d35Sstevel 
18703831d35Sstevel 	va_start(ap);
18803831d35Sstevel 	(void) vprintf(fmt, ap);
18903831d35Sstevel 	va_end(ap);
19003831d35Sstevel }
19103831d35Sstevel #else
19203831d35Sstevel #define	D_PRINTFINDENT
19303831d35Sstevel #endif
19403831d35Sstevel 
19503831d35Sstevel /*
19603831d35Sstevel  * display_pci
19703831d35Sstevel  * Display all the PCI IO cards on this board.
19803831d35Sstevel  */
19903831d35Sstevel void
display_pci(Board_node * board)20003831d35Sstevel display_pci(Board_node *board)
20103831d35Sstevel {
20203831d35Sstevel 	struct io_card *card_list = NULL;
20303831d35Sstevel 	struct io_card card;
20403831d35Sstevel 	void *value;
20503831d35Sstevel 	Prom_node *pci;
20603831d35Sstevel 	Prom_node *card_node;
20703831d35Sstevel 	Prom_node *pci_bridge_node;
20803831d35Sstevel 	Prom_node *child_pci_bridge_node;
20903831d35Sstevel 	char	*slot_name = NULL;	/* info in "slot-names" prop */
21003831d35Sstevel 	char	*child_name;
21103831d35Sstevel 	char	*name, *type;
21203831d35Sstevel 	char	*pname, *ptype;
21303831d35Sstevel 	char	buf[MAXSTRLEN];
21403831d35Sstevel 	int	*int_val;
21503831d35Sstevel 	int	pci_bus;
21603831d35Sstevel 	int	pci_bridge = 0;
21703831d35Sstevel 	int	pci_bridge_dev_no;
21803831d35Sstevel 	char	*slot_name_arr[SG_MAX_SLOTS_PER_IO_BD] = {NULL};
21903831d35Sstevel 	int	i;
22003831d35Sstevel 	int	portid;
22103831d35Sstevel 	int	level = 0;
22203831d35Sstevel 	int	version, *pversion;
22303831d35Sstevel #ifdef DEBUG
22403831d35Sstevel 	int	slot_name_bits;
22503831d35Sstevel #endif
22603831d35Sstevel 
22703831d35Sstevel 	if (board == NULL)
22803831d35Sstevel 		return;
22903831d35Sstevel 
23003831d35Sstevel 	/* Initialize all the common information */
23103831d35Sstevel 	card.display = TRUE;
23203831d35Sstevel 	card.board = board->board_num;
23303831d35Sstevel 	card.node_id = board->node_id;
23403831d35Sstevel 
23503831d35Sstevel 	/*
23603831d35Sstevel 	 * Search for each schizo and xmits, then find/display all nodes under
23703831d35Sstevel 	 * each schizo and xmits node found.
23803831d35Sstevel 	 */
23903831d35Sstevel 	for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
240e79c98e6Szk 	    pci != NULL;
241e79c98e6Szk 	    pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
24203831d35Sstevel 
24303831d35Sstevel 		/* set max freq for this board */
24403831d35Sstevel 		board_bus_max_freq = DEFAULT_MAX_FREQ;
24503831d35Sstevel 		/*
24603831d35Sstevel 		 * Find out if this is a PCI or cPCI IO Board.
24703831d35Sstevel 		 * If "enum-impl" property exists in pci node => cPCI.
24803831d35Sstevel 		 */
24903831d35Sstevel 		value = get_prop_val(find_prop(pci, "enum-impl"));
25003831d35Sstevel 		if (value == NULL) {
25103831d35Sstevel 			(void) sprintf(card.bus_type, "PCI");
25203831d35Sstevel 		} else {
25303831d35Sstevel 			(void) sprintf(card.bus_type, "cPCI");
25403831d35Sstevel 		}
25503831d35Sstevel 
25603831d35Sstevel 		if (strstr((char *)get_prop_val(
25703831d35Sstevel 		    find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
25803831d35Sstevel 			sprintf(card.notes, "%s", XMITS_COMPATIBLE);
25903831d35Sstevel 			/*
26003831d35Sstevel 			 * With XMITS 3.X and PCI-X mode, the bus speed
26103831d35Sstevel 			 * can be higher than 66MHZ.
26203831d35Sstevel 			 */
26303831d35Sstevel 			value = (int *)get_prop_val
264e79c98e6Szk 			    (find_prop(pci, "module-revision#"));
26503831d35Sstevel 			if (value) {
26603831d35Sstevel 				pversion = (int *)value;
26703831d35Sstevel 				version = *pversion;
26803831d35Sstevel 				if (version >= 4)
26903831d35Sstevel 					board_bus_max_freq = PCIX_MAX_FREQ;
27003831d35Sstevel 			}
27103831d35Sstevel 		} else if (strstr((char *)get_prop_val(
27203831d35Sstevel 		    find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
27303831d35Sstevel 			sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
27403831d35Sstevel 		else
27503831d35Sstevel 			sprintf(card.notes, " ");
27603831d35Sstevel 
27703831d35Sstevel 		/*
27803831d35Sstevel 		 * Get slot-name properties from parent node and
27903831d35Sstevel 		 * store them in an array.
28003831d35Sstevel 		 */
28103831d35Sstevel 		value = (char *)get_prop_val(find_prop(pci, "slot-names"));
28203831d35Sstevel 		if (value != NULL) {
28303831d35Sstevel #ifdef DEBUG
28403831d35Sstevel 			/* save the 4 byte bitmask */
28503831d35Sstevel 			slot_name_bits = *(int *)value;
28603831d35Sstevel #endif
28703831d35Sstevel 			/* array starts after first int */
28803831d35Sstevel 			slot_name_arr[0] = (char *)value + sizeof (int);
28903831d35Sstevel 
29003831d35Sstevel 			D_PRINTFINDENT(0, "slot_name_arr[0] is [%s]\n",
29103831d35Sstevel 			    slot_name_arr[0]);
29203831d35Sstevel 
29303831d35Sstevel 			for (i = 1; i < SG_MAX_SLOTS_PER_IO_BD; i++) {
29403831d35Sstevel 				slot_name_arr[i] = (char *)slot_name_arr[i - 1]
295e79c98e6Szk 				    + strlen(slot_name_arr[i - 1]) +1;
29603831d35Sstevel 
29703831d35Sstevel 			D_PRINTFINDENT(0, "slot_name_arr[%d] is [%s]\n", i,
29803831d35Sstevel 			    slot_name_arr[i]);
29903831d35Sstevel 
30003831d35Sstevel 			}
30103831d35Sstevel 		}
30203831d35Sstevel 
30303831d35Sstevel 		/*
30403831d35Sstevel 		 * Search for Children of this node ie. Cards.
30503831d35Sstevel 		 * Note: any of these cards can be a pci-bridge
30603831d35Sstevel 		 *	that itself has children. If we find a
30703831d35Sstevel 		 *	pci-bridge we need to handle it specially.
30803831d35Sstevel 		 *
30903831d35Sstevel 		 *	There can now be the condition of a pci-bridge
31003831d35Sstevel 		 *	being the child of a pci-bridge which create a
31103831d35Sstevel 		 *	two levels of pci-bridges.  This special condition
31203831d35Sstevel 		 *	needs to be handled as well.  The variable level
31303831d35Sstevel 		 *	is used to track the depth of the tree.  This
31403831d35Sstevel 		 *	variable is then used to find instances of this case.
31503831d35Sstevel 		 */
31603831d35Sstevel 		level = 0;
31703831d35Sstevel 		card_node = pci->child;
31803831d35Sstevel 		while (card_node != NULL) {
31903831d35Sstevel 			pci_bridge = 0;
32003831d35Sstevel 
32103831d35Sstevel 			/* If it doesn't have a name, skip it */
32203831d35Sstevel 			name = (char *)get_prop_val(
323e79c98e6Szk 			    find_prop(card_node, "name"));
32403831d35Sstevel 			if (name == NULL) {
32503831d35Sstevel 				card_node = card_node->sibling;
32603831d35Sstevel 				continue;
32703831d35Sstevel 			}
32803831d35Sstevel 			D_PRINTFINDENT(level, "NAME is %s\n", name);
32903831d35Sstevel 
33003831d35Sstevel 			type = (char *)get_prop_val(
331e79c98e6Szk 			    find_prop(card_node, "device_type"));
33203831d35Sstevel 
33303831d35Sstevel 			/*
33403831d35Sstevel 			 * get dev# and func# for this card from the
33503831d35Sstevel 			 * 'reg' property.
33603831d35Sstevel 			 */
33703831d35Sstevel 			int_val = (int *)get_prop_val(
338e79c98e6Szk 			    find_prop(card_node, "reg"));
33903831d35Sstevel 			if (int_val != NULL) {
34003831d35Sstevel 				card.dev_no = (((*int_val) & 0xF800) >> 11);
34103831d35Sstevel 				card.func_no = (((*int_val) & 0x700) >> 8);
34203831d35Sstevel 			} else {
34303831d35Sstevel 				card.dev_no = -1;
34403831d35Sstevel 				card.func_no = -1;
34503831d35Sstevel 			}
34603831d35Sstevel 
34703831d35Sstevel 			/*
34803831d35Sstevel 			 * If this is a pci-bridge, then store it's dev#
34903831d35Sstevel 			 * as it's children nodes need this to get their slot#.
35003831d35Sstevel 			 * We set the pci_bridge flag so that we know we are
35103831d35Sstevel 			 * looking at a pci-bridge node. This flag gets reset
35203831d35Sstevel 			 * every time we enter this while loop.
35303831d35Sstevel 			 */
35403831d35Sstevel 
35503831d35Sstevel 			/*
35603831d35Sstevel 			 * Check for a PCI-PCI Bridge for PCI and cPCI
35703831d35Sstevel 			 * IO Boards using the name and type properties.
35803831d35Sstevel 			 *
35903831d35Sstevel 			 * If level is greater then 0, then check the parent
36003831d35Sstevel 			 * node to see if it was also a pci-bridge.  We do not
36103831d35Sstevel 			 * this when level is 0 as this will see the schizo or
36203831d35Sstevel 			 * xmits device as a pci-bridge node.  This will mess
36303831d35Sstevel 			 * up the slot number of child nodes.
36403831d35Sstevel 			 */
36503831d35Sstevel 			if ((type != NULL) &&
366e79c98e6Szk 			    (strncmp(name, "pci", 3) == 0) &&
367e79c98e6Szk 			    (strcmp(type, "pci") == 0)) {
36803831d35Sstevel 				if (level > 0) {
369e79c98e6Szk 					pname = (char *)get_prop_val(
370e79c98e6Szk 					    find_prop(card_node->parent,
371e79c98e6Szk 					    "name"));
372e79c98e6Szk 					ptype = (char *)get_prop_val(
373e79c98e6Szk 					    find_prop(card_node->parent,
37403831d35Sstevel 					    "device_type"));
37503831d35Sstevel 
376e79c98e6Szk 					if ((ptype != NULL) &&
377e79c98e6Szk 					    (pname != NULL) &&
378e79c98e6Szk 					    (strncmp(pname, "pci", 3) == 0) &&
379e79c98e6Szk 					    (strcmp(ptype, "pci") == 0)) {
380e79c98e6Szk 						child_pci_bridge_node =
381e79c98e6Szk 						    card_node;
382e79c98e6Szk 					} else {
383e79c98e6Szk 						pci_bridge_dev_no = card.dev_no;
384e79c98e6Szk 						pci_bridge_node = card_node;
385e79c98e6Szk 					}
38603831d35Sstevel 				} else {
38703831d35Sstevel 					pci_bridge_dev_no = card.dev_no;
38803831d35Sstevel 					pci_bridge_node = card_node;
38903831d35Sstevel 				}
39003831d35Sstevel 				pci_bridge = TRUE;
39103831d35Sstevel 
39203831d35Sstevel 				D_PRINTFINDENT(level,
39303831d35Sstevel 				    "pci_bridge_dev_no is [%d]\n",
39403831d35Sstevel 				    pci_bridge_dev_no);
39503831d35Sstevel 			}
39603831d35Sstevel 
39703831d35Sstevel 			/*
39803831d35Sstevel 			 * Get slot-names property from slot_names_arr.
39903831d35Sstevel 			 * If we are the child of a pci_bridge we use the
40003831d35Sstevel 			 * dev# of the pci_bridge as an index to get
40103831d35Sstevel 			 * the slot number. We know that we are a child of
40203831d35Sstevel 			 * a pci-bridge if our parent is the same as the last
40303831d35Sstevel 			 * pci_bridge node found above.
40403831d35Sstevel 			 */
40503831d35Sstevel 			if (type)
40603831d35Sstevel 				D_PRINTFINDENT(level,
40703831d35Sstevel 				    "*** name is [%s] - type is [%s]\n",
40803831d35Sstevel 				    name, type);
40903831d35Sstevel 			else
41003831d35Sstevel 				D_PRINTFINDENT(level,
41103831d35Sstevel 				    "*** name is [%s]\n", name);
41203831d35Sstevel 
41303831d35Sstevel 			if (card.dev_no != -1) {
41403831d35Sstevel 				/*
41503831d35Sstevel 				 * We compare this cards parent node with the
41603831d35Sstevel 				 * pci_bridge_node to see if it's a child.
41703831d35Sstevel 				 */
41803831d35Sstevel 				if (((level > 0) &&
41903831d35Sstevel 				    (card_node->parent->parent ==
42003831d35Sstevel 				    pci_bridge_node)) ||
42103831d35Sstevel 				    (card_node->parent == pci_bridge_node)) {
42203831d35Sstevel 					/* use dev_no of pci_bridge */
42303831d35Sstevel 					D_PRINTFINDENT(level,
42403831d35Sstevel 					    "   pci_bridge_dev_no is [%d]\n",
42503831d35Sstevel 					    pci_bridge_dev_no);
42603831d35Sstevel 
42703831d35Sstevel 					slot_name =
42803831d35Sstevel 					    slot_name_arr[pci_bridge_dev_no -1];
42903831d35Sstevel 				} else {
43003831d35Sstevel 					/* use cards own dev_no */
43103831d35Sstevel 					D_PRINTFINDENT(level,
43203831d35Sstevel 					    "    card.dev_no is [%d]\n",
43303831d35Sstevel 					    card.dev_no);
43403831d35Sstevel 
43503831d35Sstevel 					slot_name =
43603831d35Sstevel 					    slot_name_arr[card.dev_no - 1];
43703831d35Sstevel 				}
43803831d35Sstevel 
43903831d35Sstevel 				get_slot_name(&card, slot_name);
44003831d35Sstevel 
44103831d35Sstevel 			} else {
44203831d35Sstevel 				(void) sprintf(card.slot_str, "%c", '-');
44303831d35Sstevel 			}
44403831d35Sstevel 
44503831d35Sstevel 			/*
44603831d35Sstevel 			 * Get the portid of the schizo and xmits that this card
44703831d35Sstevel 			 * lives under.
44803831d35Sstevel 			 */
44903831d35Sstevel 			portid = -1;
45003831d35Sstevel 			value = get_prop_val(find_prop(pci, "portid"));
45103831d35Sstevel 			if (value != NULL) {
45203831d35Sstevel 				portid = *(int *)value;
45303831d35Sstevel 			}
45403831d35Sstevel 			card.schizo_portid = portid;
45503831d35Sstevel 
45603831d35Sstevel #ifdef DEBUG
45703831d35Sstevel 			(void) sprintf(card.notes, "%s portid [%d] dev_no[%d]"
458e79c98e6Szk 			    " slot_name[%s] name_bits[%d]",
459e79c98e6Szk 			    card.notes,
460e79c98e6Szk 			    portid,
461e79c98e6Szk 			    card.dev_no, slot_name,
462e79c98e6Szk 			    slot_name_bits);
46303831d35Sstevel #endif
46403831d35Sstevel 
46503831d35Sstevel 			/*
46603831d35Sstevel 			 * Find out whether this is PCI bus A or B
46703831d35Sstevel 			 * using the 'reg' property.
46803831d35Sstevel 			 */
46903831d35Sstevel 			int_val = (int *)get_prop_val
470e79c98e6Szk 			    (find_prop(pci, "reg"));
47103831d35Sstevel 
47203831d35Sstevel 			if (int_val != NULL) {
47303831d35Sstevel 				int_val ++; /* skip over first integer */
47403831d35Sstevel 				pci_bus = ((*int_val) & 0x7f0000);
47503831d35Sstevel 				if (pci_bus == 0x600000)
47603831d35Sstevel 					card.pci_bus = 'A';
47703831d35Sstevel 				else if (pci_bus == 0x700000)
47803831d35Sstevel 					card.pci_bus = 'B';
47903831d35Sstevel 				else
48003831d35Sstevel 					card.pci_bus = '-';
48103831d35Sstevel 			} else {
48203831d35Sstevel 				card.pci_bus = '-';
48303831d35Sstevel 			}
48403831d35Sstevel 
48503831d35Sstevel 
48603831d35Sstevel 			/*
48703831d35Sstevel 			 * Check for failed status.
48803831d35Sstevel 			 */
48903831d35Sstevel 			if (node_status(card_node, SG_FAIL))
49003831d35Sstevel 				strncpy(card.status, SG_FAIL,
491e79c98e6Szk 				    sizeof (SG_FAIL));
49203831d35Sstevel 			else if (node_status(card_node, SG_DISABLED))
49303831d35Sstevel 				strncpy(card.status, SG_DISABLED,
494e79c98e6Szk 				    sizeof (SG_DISABLED));
49503831d35Sstevel 			else
49603831d35Sstevel 				strncpy(card.status, SG_OK,
497e79c98e6Szk 				    sizeof (SG_OK));
49803831d35Sstevel 
49903831d35Sstevel 			/* Get the model of this card */
50003831d35Sstevel 			value = get_prop_val(find_prop(card_node, "model"));
50103831d35Sstevel 			if (value == NULL)
50203831d35Sstevel 				card.model[0] = '\0';
50303831d35Sstevel 			else {
50403831d35Sstevel 				(void) sprintf(card.model, "%s",
505e79c98e6Szk 				    (char *)value);
50603831d35Sstevel 				/* Skip sgsbbc nodes, they are not cards */
50703831d35Sstevel 				if (strcmp(card.model, "SUNW,sgsbbc") == 0) {
50803831d35Sstevel 					card_node = card_node->sibling;
50903831d35Sstevel 					continue;
51003831d35Sstevel 				}
51103831d35Sstevel 			}
51203831d35Sstevel 
51303831d35Sstevel 			/*
51403831d35Sstevel 			 * Check if further processing is necessary to display
51503831d35Sstevel 			 * this card uniquely.
51603831d35Sstevel 			 */
51703831d35Sstevel 			distinguish_identical_io_cards(name, card_node, &card);
51803831d35Sstevel 
51903831d35Sstevel 			/*
52003831d35Sstevel 			 * The card may have a "clock-frequency" but we
52103831d35Sstevel 			 * are not interested in that. Instead we get the
52203831d35Sstevel 			 * "clock-frequency" of the PCI Bus that the card
52303831d35Sstevel 			 * resides on. PCI-A can operate at 33Mhz or 66Mhz
52403831d35Sstevel 			 * depending on what card is plugged into the Bus.
52503831d35Sstevel 			 * PCI-B always operates at 33Mhz.
52603831d35Sstevel 			 *
52703831d35Sstevel 			 */
52803831d35Sstevel 			int_val = get_prop_val(find_prop(pci,
529e79c98e6Szk 			    "clock-frequency"));
53003831d35Sstevel 			if (int_val != NULL) {
53103831d35Sstevel 				card.freq = SG_CLK_FREQ_TO_MHZ(*int_val);
53203831d35Sstevel 			} else {
53303831d35Sstevel 				card.freq = -1;
53403831d35Sstevel 			}
53503831d35Sstevel 
53603831d35Sstevel 			/*
53703831d35Sstevel 			 * Figure out how we want to display the name
53803831d35Sstevel 			 */
53903831d35Sstevel 			value = get_prop_val(find_prop(card_node,
540e79c98e6Szk 			    "compatible"));
54103831d35Sstevel 			if (value != NULL) {
54203831d35Sstevel 				/* use 'name'-'compatible' */
54303831d35Sstevel 				(void) sprintf(buf, "%s-%s", name,
544e79c98e6Szk 				    (char *)value);
54503831d35Sstevel 			} else {
54603831d35Sstevel 				/* just use 'name' */
54703831d35Sstevel 				(void) sprintf(buf, "%s", name);
54803831d35Sstevel 			}
54903831d35Sstevel 			name = buf;
55003831d35Sstevel 
55103831d35Sstevel 			/*
55203831d35Sstevel 			 * If this node has children, add the device_type
55303831d35Sstevel 			 * of the child to the name value of this card.
55403831d35Sstevel 			 */
55503831d35Sstevel 			child_name = (char *)get_node_name(card_node->child);
55603831d35Sstevel 			if ((card_node->child != NULL) &&
557e79c98e6Szk 			    (child_name != NULL)) {
55803831d35Sstevel 				value = get_prop_val(find_prop(card_node->child,
559e79c98e6Szk 				    "device_type"));
56003831d35Sstevel 				if (value != NULL) {
56103831d35Sstevel 					/* add device_type of child to name */
56203831d35Sstevel 					(void) sprintf(card.name, "%s/%s (%s)",
563e79c98e6Szk 					    name, child_name,
564e79c98e6Szk 					    (char *)value);
56503831d35Sstevel 				} else {
56603831d35Sstevel 					/* just add childs name */
56703831d35Sstevel 					(void) sprintf(card.name, "%s/%s", name,
568e79c98e6Szk 					    child_name);
56903831d35Sstevel 				}
57003831d35Sstevel 			} else {
57103831d35Sstevel 				(void) sprintf(card.name, "%s", (char *)name);
57203831d35Sstevel 			}
57303831d35Sstevel 
57403831d35Sstevel 			/*
57503831d35Sstevel 			 * If this is a pci-bridge, then add the word
57603831d35Sstevel 			 * 'pci-bridge' to it's model.
57703831d35Sstevel 			 */
57803831d35Sstevel 			if (pci_bridge) {
57903831d35Sstevel 				if (strlen(card.model) == 0)
58003831d35Sstevel 					(void) sprintf(card.model,
581e79c98e6Szk 					    "%s", "pci-bridge");
58203831d35Sstevel 				else
58303831d35Sstevel 					(void) sprintf(card.model,
58403831d35Sstevel 					    "%s/pci-bridge", card.model);
58503831d35Sstevel 			}
58603831d35Sstevel 
58703831d35Sstevel 			/* insert this card in the list to be displayed later */
58803831d35Sstevel 			card_list = insert_io_card(card_list, &card);
58903831d35Sstevel 
59003831d35Sstevel 			/*
59103831d35Sstevel 			 * If we are dealing with a pci-bridge, we need to move
59203831d35Sstevel 			 * down to the children of this bridge if there are any.
59303831d35Sstevel 			 *
59403831d35Sstevel 			 * If we are not, we are either dealing with a regular
59503831d35Sstevel 			 * card (in which case we move onto the sibling of this
59603831d35Sstevel 			 * card) or we are dealing with a child of a pci-bridge
59703831d35Sstevel 			 * (in which case we move onto the child's siblings or
59803831d35Sstevel 			 * if there are no more siblings for this child, we
59903831d35Sstevel 			 * move onto the parents siblings).
60003831d35Sstevel 			 *
60103831d35Sstevel 			 * Once we reach the last child node of a pci-bridge,
60203831d35Sstevel 			 * we need to back up the tree to the parents sibling
60303831d35Sstevel 			 * node.  If our parent has no more siblings, we need
60403831d35Sstevel 			 * to check our grand parent for siblings.
60503831d35Sstevel 			 *
60603831d35Sstevel 			 * If we have no more siblings, we simply point to
60703831d35Sstevel 			 * to the child's sibling which moves us onto the next
60803831d35Sstevel 			 * bus leaf.
60903831d35Sstevel 			 *
61003831d35Sstevel 			 * The variable level gets adjusted on some of the
61103831d35Sstevel 			 * conditions as this is used to track level within
61203831d35Sstevel 			 * the tree we have reached.
61303831d35Sstevel 			 */
61403831d35Sstevel 			if (pci_bridge) {
61503831d35Sstevel 				if (card_node->child != NULL) {
61603831d35Sstevel 					level++;
61703831d35Sstevel 					card_node = card_node->child;
61803831d35Sstevel 				} else
61903831d35Sstevel 					card_node = card_node->sibling;
62003831d35Sstevel 			} else {
621e79c98e6Szk 				if ((card_node->parent == pci_bridge_node) &&
622e79c98e6Szk 				    (card_node->sibling == NULL)) {
623e79c98e6Szk 					card_node = pci_bridge_node->sibling;
62403831d35Sstevel 					if (level > 0)
62503831d35Sstevel 						level--;
626e79c98e6Szk 				} else if ((card_node->parent ==
627e79c98e6Szk 				    child_pci_bridge_node) &&
628e79c98e6Szk 				    (card_node->parent->parent ==
629e79c98e6Szk 				    pci_bridge_node)) {
630e79c98e6Szk 					if ((child_pci_bridge_node->sibling) &&
631e79c98e6Szk 					    (card_node->sibling == NULL)) {
632e79c98e6Szk 						card_node =
633e79c98e6Szk 						    child_pci_bridge_node-> \
634e79c98e6Szk 						    sibling;
635e79c98e6Szk 					if (level > 0)
636e79c98e6Szk 						level--;
637e79c98e6Szk 					} else if ((pci_bridge_node->sibling) &&
638e79c98e6Szk 					    (card_node->sibling == NULL)) {
639e79c98e6Szk 						card_node =
640e79c98e6Szk 						    pci_bridge_node->sibling;
641e79c98e6Szk 						if (level > 1)
642e79c98e6Szk 							level = level - 2;
643e79c98e6Szk 						else if (level > 0)
644e79c98e6Szk 							level--;
645e79c98e6Szk 					} else
646e79c98e6Szk 						card_node = card_node->sibling;
647e79c98e6Szk 				} else
648e79c98e6Szk 					card_node = card_node->sibling;
64903831d35Sstevel 			}
65003831d35Sstevel 		} /* end-while */
65103831d35Sstevel 	} /* end-for */
65203831d35Sstevel 
65303831d35Sstevel 	display_io_cards(card_list);
65403831d35Sstevel 	free_io_cards(card_list);
65503831d35Sstevel }
65603831d35Sstevel 
65703831d35Sstevel /*
65803831d35Sstevel  * display_ffb
65903831d35Sstevel  *
66003831d35Sstevel  * There are no FFB's on a Serengeti, however in the generic library,
66103831d35Sstevel  * the display_ffb() function is implemented so we have to define an
66203831d35Sstevel  * empty function here.
66303831d35Sstevel  */
66403831d35Sstevel /*ARGSUSED0*/
66503831d35Sstevel void
display_ffb(Board_node * board,int table)66603831d35Sstevel display_ffb(Board_node *board, int table)
66703831d35Sstevel {}
66803831d35Sstevel 
66903831d35Sstevel static void
serengeti_display_board_info_header(int state)67003831d35Sstevel serengeti_display_board_info_header(int state)
67103831d35Sstevel {
67203831d35Sstevel 	char *fmt = "%-9s  %-11s  %-12s  %-12s  %-9s %-40s\n";
67303831d35Sstevel 
67403831d35Sstevel 	log_printf("\n", 0);
67503831d35Sstevel 	log_printf("=========================", 0);
67603831d35Sstevel 	if (state == ACTIVE)
67703831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
678e79c98e6Szk 		    " Active Boards for Domain "), 0);
67903831d35Sstevel 	else
68003831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
681e79c98e6Szk 		    " Available Boards/Slots for Domain "), 0);
68203831d35Sstevel 	log_printf("===========================", 0);
68303831d35Sstevel 	log_printf("\n", 0);
68403831d35Sstevel 	log_printf("\n", 0);
68503831d35Sstevel 
68603831d35Sstevel 	log_printf(fmt, "", "Board", "Receptacle", "Occupant", "", "", 0);
68703831d35Sstevel 
68803831d35Sstevel 	log_printf(fmt, "FRU Name", "Type", "Status", "Status",
689e79c98e6Szk 	    "Condition", "Info", 0);
69003831d35Sstevel 
69103831d35Sstevel 	log_printf(fmt, "---------", "-----------", "-----------",
692e79c98e6Szk 	    "------------", "---------",
693e79c98e6Szk 	    "----------------------------------------", 0);
69403831d35Sstevel }
69503831d35Sstevel 
69603831d35Sstevel static void
serengeti_display_board_info(int state)69703831d35Sstevel serengeti_display_board_info(int state)
69803831d35Sstevel {
69903831d35Sstevel 	int i, z, ret;
70003831d35Sstevel 	int nlist = 0;
70103831d35Sstevel 	int available_board_count = 0;
70203831d35Sstevel 	struct cfga_list_data *board_cfg = NULL;
70303831d35Sstevel 	char *err_string = NULL;
70403831d35Sstevel 	char tmp_id[CFGA_LOG_EXT_LEN + 1];
70503831d35Sstevel 	char tmp_info[DISPLAY_INFO + 1];
70603831d35Sstevel 	const char listops[] = "class=sbd";
70703831d35Sstevel 	struct cfga_list_data dat;
708aa5636e5SPeter Tribble 	cfga_flags_t flags = 0;
70903831d35Sstevel 
71003831d35Sstevel 	ret = config_list_ext(0, NULL, &board_cfg, &nlist,
711e79c98e6Szk 	    NULL, listops,
712e79c98e6Szk 	    &err_string, flags);
71303831d35Sstevel 
71403831d35Sstevel 	if (ret == CFGA_OK) {
71503831d35Sstevel 		serengeti_display_board_info_header(state);
71603831d35Sstevel 		for (i = 0; i < nlist; i++) {
71703831d35Sstevel 			dat = board_cfg[i];
71803831d35Sstevel 
71903831d35Sstevel 			if ((state != ACTIVE) &&
72003831d35Sstevel 			    (dat.ap_o_state == CFGA_STAT_CONFIGURED))
72103831d35Sstevel 				continue;
72203831d35Sstevel 			else if ((state == ACTIVE) &&
723e79c98e6Szk 			    (dat.ap_o_state != CFGA_STAT_CONFIGURED))
72403831d35Sstevel 				continue;
72503831d35Sstevel 			if (state == INACTIVE)
72603831d35Sstevel 				available_board_count++;
72703831d35Sstevel 
72803831d35Sstevel 			memcpy(tmp_id, dat.ap_log_id, CFGA_LOG_EXT_LEN);
72903831d35Sstevel 			tmp_id[CFGA_LOG_EXT_LEN] = '\0';
73003831d35Sstevel 			for (z = 0; z < strlen(tmp_id); z++) {
73103831d35Sstevel 				if (tmp_id[z] == '.')
73203831d35Sstevel 					tmp_id[z] = '/';
73303831d35Sstevel 			}
73403831d35Sstevel 			log_printf("/%-8s  ", tmp_id, 0);
73503831d35Sstevel 			log_printf("%-11s  ", dat.ap_type, 0);
73603831d35Sstevel 
73703831d35Sstevel 			log_printf("%-12s  ", EVNT2STR(dat.ap_r_state), 0);
73803831d35Sstevel 			log_printf("%-12s  ", EVNT2STR(dat.ap_o_state), 0);
73903831d35Sstevel 			log_printf("%-8s  ", COND2STR(dat.ap_cond), 0);
74003831d35Sstevel 
74103831d35Sstevel 			memcpy(tmp_info, dat.ap_info, DISPLAY_INFO);
74203831d35Sstevel 			tmp_info[DISPLAY_INFO - 1] = '\0';
74303831d35Sstevel 			if (strlen(tmp_info) >= (DISPLAY_INFO - 1))
74403831d35Sstevel 				tmp_info[DISPLAY_INFO - 2] = '+';
74503831d35Sstevel 			log_printf("%-*s\n", (DISPLAY_INFO - 1), tmp_info, 0);
74603831d35Sstevel 		}
74703831d35Sstevel 		if ((state == INACTIVE) &&
74803831d35Sstevel 		    (available_board_count == 0)) {
74903831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
750e79c98e6Szk 			    "There are currently no "
751e79c98e6Szk 			    "Boards/Slots available "
752e79c98e6Szk 			    "to this Domain\n"), 0);
75303831d35Sstevel 		}
75403831d35Sstevel 	}
75503831d35Sstevel 	if (board_cfg)
75603831d35Sstevel 		free(board_cfg);
75703831d35Sstevel 	if (err_string)
75803831d35Sstevel 		free(err_string);
75903831d35Sstevel }
76003831d35Sstevel 
76103831d35Sstevel /*
76203831d35Sstevel  * add_node
76303831d35Sstevel  *
76403831d35Sstevel  * This function adds a board node to the board structure where that
76503831d35Sstevel  * that node's physical component lives.
76603831d35Sstevel  */
76703831d35Sstevel void
add_node(Sys_tree * root,Prom_node * pnode)76803831d35Sstevel add_node(Sys_tree *root, Prom_node *pnode)
76903831d35Sstevel {
77003831d35Sstevel 	int	board	= -1;
77103831d35Sstevel 	int	portid	= -1;
77203831d35Sstevel 	int	nodeid	= -1;
77303831d35Sstevel 
77403831d35Sstevel 	void		*value	= NULL;
77503831d35Sstevel 	Board_node	*bnode	= NULL;
77603831d35Sstevel 	Prom_node	*p	= NULL;
77703831d35Sstevel 	char		*type;
77803831d35Sstevel 
77903831d35Sstevel 	/* Get the board number of this board from the portid prop */
78003831d35Sstevel 	if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
78103831d35Sstevel 		if ((type = get_node_type(pnode)) && (strcmp(type, "cpu") == 0))
78203831d35Sstevel 			value =
78303831d35Sstevel 			    get_prop_val(find_prop(pnode->parent, "portid"));
78403831d35Sstevel 	}
78503831d35Sstevel 	if (value != NULL) {
78603831d35Sstevel 		portid = *(int *)value;
78703831d35Sstevel 	}
78803831d35Sstevel 
78903831d35Sstevel 	nodeid	= SG_PORTID_TO_NODEID(portid);
79003831d35Sstevel 	board	= SG_PORTID_TO_BOARD_NUM(portid);
79103831d35Sstevel 
79203831d35Sstevel 	/* find the board node with the same board number */
79303831d35Sstevel 	if ((bnode = serengeti_find_board(root, board, nodeid)) == NULL) {
79403831d35Sstevel 		bnode = serengeti_insert_board(root, board, nodeid);
79503831d35Sstevel 	}
79603831d35Sstevel 
79703831d35Sstevel 	/* now attach this prom node to the board list */
79803831d35Sstevel 	/* Insert this node at the end of the list */
79903831d35Sstevel 	pnode->sibling = NULL;
80003831d35Sstevel 	if (bnode->nodes == NULL)
80103831d35Sstevel 		bnode->nodes = pnode;
80203831d35Sstevel 	else {
80303831d35Sstevel 		p = bnode->nodes;
80403831d35Sstevel 		while (p->sibling != NULL)
80503831d35Sstevel 			p = p->sibling;
80603831d35Sstevel 		p->sibling = pnode;
80703831d35Sstevel 	}
80803831d35Sstevel }
80903831d35Sstevel 
81003831d35Sstevel 
81103831d35Sstevel 
81203831d35Sstevel /*
81303831d35Sstevel  * Print out all the io cards in the list.  Also print the column
81403831d35Sstevel  * headers if told to do so.
81503831d35Sstevel  */
81603831d35Sstevel void
display_io_cards(struct io_card * list)81703831d35Sstevel display_io_cards(struct io_card *list)
81803831d35Sstevel {
81903831d35Sstevel 	char	*fmt = "%-10s  %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-34s";
82003831d35Sstevel 
82103831d35Sstevel 	static int banner = FALSE; /* Have we printed the column headings? */
82203831d35Sstevel 	struct io_card *p;
82303831d35Sstevel 
82403831d35Sstevel 	if (list == NULL)
82503831d35Sstevel 		return;
82603831d35Sstevel 
82703831d35Sstevel 	if (banner == FALSE) {
82803831d35Sstevel 		log_printf(fmt, "", "", "", "", "", "Bus", "Max",
829e79c98e6Szk 		    "", "", "", 0);
83003831d35Sstevel 		log_printf("\n", 0);
83103831d35Sstevel 		log_printf(fmt, "", "IO", "Port", "Bus", "", "Freq", "Bus",
832e79c98e6Szk 		    "Dev,", "", "", 0);
83303831d35Sstevel 		log_printf("\n", 0);
83403831d35Sstevel 		log_printf(fmt, "FRU Name", "Type", " ID", "Side", "Slot",
835e79c98e6Szk 		    "MHz", "Freq", "Func", "State", "Name", 0);
83603831d35Sstevel #ifdef DEBUG
83703831d35Sstevel 		log_printf("Model                   Notes\n", 0);
83803831d35Sstevel #else
83903831d35Sstevel 		log_printf("Model\n", 0);
84003831d35Sstevel #endif
84103831d35Sstevel 
84203831d35Sstevel 		log_printf(fmt, "----------", "----", "----", "----", "----",
843e79c98e6Szk 		    "----", "----", "----", "-----",
844e79c98e6Szk 		    "--------------------------------", 0);
84503831d35Sstevel #ifdef DEBUG
84603831d35Sstevel 		log_printf("----------------------  ", 0);
84703831d35Sstevel #endif
84803831d35Sstevel 		log_printf("----------------------\n", 0);
84903831d35Sstevel 		banner = TRUE;
85003831d35Sstevel 	}
85103831d35Sstevel 
85203831d35Sstevel 	for (p = list; p != NULL; p = p -> next) {
85303831d35Sstevel 
85403831d35Sstevel 		display_io_slot_info(p);
85503831d35Sstevel 
85603831d35Sstevel 		display_io_max_bus_speed(p);
85703831d35Sstevel 
85803831d35Sstevel 		log_printf("\n", 0);
85903831d35Sstevel 	}
86003831d35Sstevel }
86103831d35Sstevel 
86203831d35Sstevel static void
display_io_slot_info(struct io_card * p)86303831d35Sstevel display_io_slot_info(struct io_card *p)
86403831d35Sstevel {
86503831d35Sstevel 	char	fru_name[MAX_FRU_NAME_LEN] = "";
86603831d35Sstevel 
86703831d35Sstevel 	SG_SET_FRU_NAME_NODE(fru_name, p->node_id);
86803831d35Sstevel 	SG_SET_FRU_NAME_IO_BOARD(fru_name, p->board);
86903831d35Sstevel 	SG_SET_FRU_NAME_MODULE(fru_name, p->schizo_portid % 2);
87003831d35Sstevel 
87103831d35Sstevel 	log_printf("%-8s  ", fru_name, 0);
87203831d35Sstevel 	log_printf("%-4s  ", p->bus_type, 0);
87303831d35Sstevel 	log_printf("%-3d  ", p->schizo_portid, 0);
87403831d35Sstevel 	log_printf("%c    ", p->pci_bus, 0);
87503831d35Sstevel 	log_printf("%-1s    ", p->slot_str, 0);
87603831d35Sstevel 	log_printf("%-3d ", p->freq, 0);
87703831d35Sstevel }
87803831d35Sstevel 
87903831d35Sstevel #define	BUS_SPEED_PRINT(speed)	log_printf(" %d  ", speed, 0)
88003831d35Sstevel 
88103831d35Sstevel static void
display_io_max_bus_speed(struct io_card * p)88203831d35Sstevel display_io_max_bus_speed(struct io_card *p)
88303831d35Sstevel {
88403831d35Sstevel 	int speed = board_bus_max_freq;
88503831d35Sstevel 
88603831d35Sstevel 	switch (p->pci_bus) {
88703831d35Sstevel 	case 'A':
88803831d35Sstevel 		BUS_SPEED_PRINT(speed);
88903831d35Sstevel 		break;
89003831d35Sstevel 	case 'B':
89103831d35Sstevel 		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
89203831d35Sstevel 			if ((strncmp(p->slot_str, "1", 1) == 0) ||
89303831d35Sstevel 			    (strncmp(p->slot_str, "0", 1) == 0))
89403831d35Sstevel 				BUS_SPEED_PRINT(33);
89503831d35Sstevel 			else
89603831d35Sstevel 				BUS_SPEED_PRINT(speed);
89703831d35Sstevel 		} else
89803831d35Sstevel 			BUS_SPEED_PRINT(33);
89903831d35Sstevel 		break;
90003831d35Sstevel 	default:
90103831d35Sstevel 		log_printf("  -	 ", 0);
90203831d35Sstevel 		break;
90303831d35Sstevel 	}
90403831d35Sstevel 
90503831d35Sstevel 	log_printf("%-1d,%-1d  ", p->dev_no, p->func_no, 0);
90603831d35Sstevel 	log_printf("%-5s ", p->status, 0);
90703831d35Sstevel 
90803831d35Sstevel 	log_printf("%-32.32s%c ", p->name,
909e79c98e6Szk 	    ((strlen(p->name) > 32) ? '+' : ' '), 0);
91003831d35Sstevel 	log_printf("%-22.22s%c", p->model,
911e79c98e6Szk 	    ((strlen(p->model) > 22) ? '+' : ' '), 0);
91203831d35Sstevel #ifdef	DEBUG
91303831d35Sstevel 	log_printf(" %s", p->notes, 0);
91403831d35Sstevel #endif	/* DEBUG */
91503831d35Sstevel }
91603831d35Sstevel 
91703831d35Sstevel void
display_cpu_devices(Sys_tree * tree)91803831d35Sstevel display_cpu_devices(Sys_tree *tree)
91903831d35Sstevel {
92003831d35Sstevel 	Board_node *bnode;
92103831d35Sstevel 
92203831d35Sstevel 	/* printf formats */
92303831d35Sstevel 	char	*fmt1 = "%-10s  %-7s  %-4s  %-4s  %-7s  %-4s\n";
92403831d35Sstevel 
92503831d35Sstevel 	/*
92603831d35Sstevel 	 * Display the table header for CPUs . Then display the CPU
92703831d35Sstevel 	 * frequency, cache size, and processor revision of all cpus.
92803831d35Sstevel 	 */
92903831d35Sstevel 	log_printf("\n", 0);
93003831d35Sstevel 	log_printf("=========================", 0);
93103831d35Sstevel 	log_printf(" CPUs ", 0);
93203831d35Sstevel 	log_printf("=========================", 0);
93303831d35Sstevel 	log_printf("======================", 0);
93403831d35Sstevel 	log_printf("\n", 0);
93503831d35Sstevel 	log_printf("\n", 0);
93603831d35Sstevel 
93703831d35Sstevel 	log_printf(fmt1, "", "CPU ", "Run", " E$", "CPU", "CPU", 0);
93803831d35Sstevel 
93903831d35Sstevel 	log_printf(fmt1, "FRU Name", "ID ", "MHz", " MB",
940e79c98e6Szk 	    "Impl.", "Mask", 0);
94103831d35Sstevel 
94203831d35Sstevel 	log_printf(fmt1, "----------", "-------", "----", "----",
943e79c98e6Szk 	    "-------",  "----", 0);
94403831d35Sstevel 
94503831d35Sstevel 	/* Now display all of the cpus on each board */
94603831d35Sstevel 	bnode = tree->bd_list;
94703831d35Sstevel 	while (bnode != NULL) {
94803831d35Sstevel 		display_cpus(bnode);
94903831d35Sstevel 		bnode = bnode->next;
95003831d35Sstevel 	}
95103831d35Sstevel 
95203831d35Sstevel 	log_printf("\n", 0);
95303831d35Sstevel }
95403831d35Sstevel 
95503831d35Sstevel static boolean_t
cpu_node_configured(char * const node)95603831d35Sstevel cpu_node_configured(char *const node)
95703831d35Sstevel {
95803831d35Sstevel 	int ret, i;
95903831d35Sstevel 	int nlist = 0;
96003831d35Sstevel 	boolean_t rv;
96103831d35Sstevel 	char *err_string = NULL;
96203831d35Sstevel 	struct cfga_list_data *statlist = NULL;
96303831d35Sstevel 	struct cfga_list_data dat;
96403831d35Sstevel 	cfga_flags_t flags = CFGA_FLAG_LIST_ALL;
96503831d35Sstevel 
96603831d35Sstevel 	if (node == NULL)
96703831d35Sstevel 		return (FALSE);
96803831d35Sstevel 
96903831d35Sstevel 	ret = config_list_ext(1, &node, &statlist, &nlist,
970e79c98e6Szk 	    NULL, NULL, &err_string, flags);
97103831d35Sstevel 
97203831d35Sstevel 	if (ret == CFGA_OK) {
97303831d35Sstevel 		dat = statlist[0];
97403831d35Sstevel 
97503831d35Sstevel 		if (dat.ap_o_state == CFGA_STAT_CONFIGURED)
97603831d35Sstevel 			rv = TRUE;
97703831d35Sstevel 		else
97803831d35Sstevel 			rv = FALSE;
97903831d35Sstevel 	} else {
98003831d35Sstevel 		rv = FALSE;
98103831d35Sstevel 	}
98203831d35Sstevel 	if (statlist)
98303831d35Sstevel 		free(statlist);
98403831d35Sstevel 	if (err_string)
98503831d35Sstevel 		free(err_string);
98603831d35Sstevel 	return (rv);
98703831d35Sstevel }
98803831d35Sstevel 
98903831d35Sstevel /*
99003831d35Sstevel  * Display the CPUs present on this board.
99103831d35Sstevel  */
99203831d35Sstevel void
display_cpus(Board_node * board)99303831d35Sstevel display_cpus(Board_node *board)
99403831d35Sstevel {
99503831d35Sstevel 	Prom_node *cpu;
996e79c98e6Szk 	uint_t freq;	 /* CPU clock frequency */
99703831d35Sstevel 	int ecache_size; /* External cache size */
99803831d35Sstevel 	int board_num = board->board_num;
99903831d35Sstevel 	int *mid;
100003831d35Sstevel 	int *impl;
100103831d35Sstevel 	int *mask;
100203831d35Sstevel 	int decoded_mask;
100303831d35Sstevel 	int *coreid;
100403831d35Sstevel 	int mid_prev = -1;
100503831d35Sstevel 	int ecache_size_prev = 0;
100603831d35Sstevel 	char fru_prev[MAX_FRU_NAME_LEN] = "";
100703831d35Sstevel 
100803831d35Sstevel 	/*
100903831d35Sstevel 	 * display the CPUs' operating frequency, cache size, impl. field
101003831d35Sstevel 	 * and mask revision.
101103831d35Sstevel 	 */
101203831d35Sstevel 	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
101303831d35Sstevel 	    cpu = dev_next_type(cpu, "cpu")) {
101403831d35Sstevel 		char	fru_name[MAX_FRU_NAME_LEN] = "";
101503831d35Sstevel 		char	cfg_fru_name[MAX_FRU_NAME_LEN] = "";
101603831d35Sstevel 
101703831d35Sstevel 		mid = (int *)get_prop_val(find_prop(cpu, "portid"));
101803831d35Sstevel 		if (mid == NULL)
101903831d35Sstevel 			mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
102003831d35Sstevel 		freq = SG_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
102103831d35Sstevel 		ecache_size = get_ecache_size(cpu);
102203831d35Sstevel 		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
102303831d35Sstevel 		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
102403831d35Sstevel 
102503831d35Sstevel 		/* Do not display a failed CPU node */
102603831d35Sstevel 		if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
102703831d35Sstevel 			continue;
102803831d35Sstevel 
102903831d35Sstevel 		/* FRU Name */
103003831d35Sstevel 		SG_SET_FRU_NAME_NODE(fru_name, board->node_id);
103103831d35Sstevel 
103203831d35Sstevel 		SG_SET_FRU_NAME_CPU_BOARD(fru_name, board_num);
103303831d35Sstevel 		SG_SET_FRU_NAME_MODULE(fru_name, *mid % 4);
103403831d35Sstevel 
103503831d35Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
103603831d35Sstevel 			coreid = (int *)get_prop_val(find_prop(cpu,
103703831d35Sstevel 			    "reg"));
103803831d35Sstevel 			if (coreid == NULL) {
103903831d35Sstevel 				continue;
104003831d35Sstevel 			}
104103831d35Sstevel 
104203831d35Sstevel 			/*
104303831d35Sstevel 			 * The assumption is made that 2 cores will always be
104403831d35Sstevel 			 * listed together in the device tree. If either core
104503831d35Sstevel 			 * is "bad" then the FRU will not be listed.
104603831d35Sstevel 			 *
104703831d35Sstevel 			 * As display_cpus on Serengeti does actually process
104803831d35Sstevel 			 * all cpu's per board a copy of the fru_name needs to
104903831d35Sstevel 			 * be made as the following core may not be its
105003831d35Sstevel 			 * sibling. If this is the case it is assumed that a
105103831d35Sstevel 			 * sibling core has failed, so the fru should not be
105203831d35Sstevel 			 * displayed.
105303831d35Sstevel 			 *
105403831d35Sstevel 			 * For the first instance of a core, fru_prev is
105503831d35Sstevel 			 * expected to be empty.  The current values are then
105603831d35Sstevel 			 * stored and the next board->nodes is processed. If
105703831d35Sstevel 			 * this is a sibling core, the ecache size it tallied
105803831d35Sstevel 			 * and the  previous value reset and processing
105903831d35Sstevel 			 * continues.
106003831d35Sstevel 			 *
106103831d35Sstevel 			 * If the following core is not a sibling, the new
106203831d35Sstevel 			 * values are stored and the next board->nodes is
106303831d35Sstevel 			 * processed.
106403831d35Sstevel 			 */
106503831d35Sstevel 			if (strncmp(fru_prev, "", sizeof (fru_prev)) == 0) {
106603831d35Sstevel 				strncpy(fru_prev, fru_name, sizeof (fru_name));
106703831d35Sstevel 				mid_prev = *mid;
106803831d35Sstevel 				ecache_size_prev = ecache_size;
106903831d35Sstevel 				continue;
107003831d35Sstevel 			} else {
107103831d35Sstevel 				if (strncmp(fru_name, fru_prev,
107203831d35Sstevel 				    sizeof (fru_prev)) == 0) {
107303831d35Sstevel 					/*
107403831d35Sstevel 					 * Jaguar has a split E$, so the size
107503831d35Sstevel 					 * for both cores must be added together
107603831d35Sstevel 					 * to get the total size for the entire
107703831d35Sstevel 					 * chip.
107803831d35Sstevel 					 *
107903831d35Sstevel 					 * Panther E$ (L3) is logically shared,
108003831d35Sstevel 					 * so the total size is equal to the
108103831d35Sstevel 					 * core size.
108203831d35Sstevel 					 */
108303831d35Sstevel 					if (IS_JAGUAR(*impl)) {
108403831d35Sstevel 						ecache_size += ecache_size_prev;
108503831d35Sstevel 					}
108603831d35Sstevel 
108703831d35Sstevel 					ecache_size_prev = 0;
108803831d35Sstevel 					strncpy(fru_prev, "",
108903831d35Sstevel 					    sizeof (fru_prev));
109003831d35Sstevel 				} else {
109103831d35Sstevel 					mid_prev = *mid;
109203831d35Sstevel 					ecache_size_prev = ecache_size;
109303831d35Sstevel 					strncpy(fru_prev, fru_name,
109403831d35Sstevel 					    sizeof (fru_name));
109503831d35Sstevel 					continue;
109603831d35Sstevel 				}
109703831d35Sstevel 			}
109803831d35Sstevel 		}
109903831d35Sstevel 
110003831d35Sstevel 		/*
110103831d35Sstevel 		 * If cpu is not configured, do not display it
110203831d35Sstevel 		 */
110303831d35Sstevel 		CFG_SET_FRU_NAME_NODE(cfg_fru_name, board->node_id);
110403831d35Sstevel 		CFG_SET_FRU_NAME_CPU_BOARD(cfg_fru_name, board_num);
110503831d35Sstevel 		CFG_SET_FRU_NAME_MODULE(cfg_fru_name, *mid % 4);
110603831d35Sstevel 
110703831d35Sstevel 		if (!(cpu_node_configured(cfg_fru_name))) {
110803831d35Sstevel 			continue;
110903831d35Sstevel 		}
111003831d35Sstevel 
111103831d35Sstevel 
111203831d35Sstevel 		log_printf("%-10s  ", fru_name, 0);
111303831d35Sstevel 
111403831d35Sstevel 		/* CPU MID */
111503831d35Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
111603831d35Sstevel 			log_printf("%3d,%3d ", mid_prev, *mid, 0);
111703831d35Sstevel 			mid_prev = -1;
111803831d35Sstevel 		} else
111903831d35Sstevel 			log_printf("%3d     ", *mid, 0);
112003831d35Sstevel 
112103831d35Sstevel 		/* Running frequency */
1122e79c98e6Szk 		log_printf(" %4u  ", freq, 0);
112303831d35Sstevel 
112403831d35Sstevel 		/* Ecache size */
112503831d35Sstevel 		if (ecache_size == 0)
112603831d35Sstevel 			log_printf("%3s  ", "N/A", 0);
112703831d35Sstevel 		else
112803831d35Sstevel 			log_printf("%4.1f  ",
1129e79c98e6Szk 			    (float)ecache_size / (float)(1<<20),
1130e79c98e6Szk 			    0);
113103831d35Sstevel 
113203831d35Sstevel 		/* Implementation */
113303831d35Sstevel 		if (impl == NULL) {
113403831d35Sstevel 			log_printf("%6s  ", " N/A", 0);
113503831d35Sstevel 		} else {
113603831d35Sstevel 			switch (*impl) {
113703831d35Sstevel 			case CHEETAH_IMPL:
113803831d35Sstevel 				log_printf("%-7s ", "US-III", 0);
113903831d35Sstevel 				break;
114003831d35Sstevel 			case CHEETAH_PLUS_IMPL:
114103831d35Sstevel 				log_printf("%-7s ", "US-III+", 0);
114203831d35Sstevel 				break;
114303831d35Sstevel 			case JAGUAR_IMPL:
114403831d35Sstevel 				log_printf("%-7s ", "US-IV", 0);
114503831d35Sstevel 				break;
114603831d35Sstevel 			case PANTHER_IMPL:
114703831d35Sstevel 				log_printf("%-7s ", "US-IV+", 0);
114803831d35Sstevel 				break;
114903831d35Sstevel 			default:
115003831d35Sstevel 				log_printf("%-7x ", *impl, 0);
115103831d35Sstevel 				break;
115203831d35Sstevel 			}
115303831d35Sstevel 		}
115403831d35Sstevel 
115503831d35Sstevel 		/* CPU Mask */
115603831d35Sstevel 		if (mask == NULL) {
115703831d35Sstevel 			log_printf(" %3s   ", "N/A", 0);
115803831d35Sstevel 		} else {
115903831d35Sstevel 			if (IS_CHEETAH(*impl))
116003831d35Sstevel 				decoded_mask = REMAP_CHEETAH_MASK(*mask);
116103831d35Sstevel 			else
116203831d35Sstevel 				decoded_mask = *mask;
116303831d35Sstevel 
116403831d35Sstevel 			log_printf(" %d.%d   ",
116503831d35Sstevel 			    (decoded_mask >> 4) & 0xf,
116603831d35Sstevel 			    decoded_mask & 0xf, 0);
116703831d35Sstevel 		}
116803831d35Sstevel 
116903831d35Sstevel 		log_printf("\n", 0);
117003831d35Sstevel 	}
117103831d35Sstevel }
117203831d35Sstevel 
117303831d35Sstevel 
117403831d35Sstevel /*ARGSUSED3*/
117503831d35Sstevel void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)117603831d35Sstevel display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
1177aa5636e5SPeter Tribble     struct system_kstat_data *kstats)
117803831d35Sstevel {
117903831d35Sstevel 	log_printf("\n", 0);
118003831d35Sstevel 	log_printf("=========================", 0);
118103831d35Sstevel 	log_printf(dgettext(TEXT_DOMAIN, " Hardware Failures "), 0);
118203831d35Sstevel 	log_printf("==================================", 0);
118303831d35Sstevel 	log_printf("\n", 0);
118403831d35Sstevel 
118503831d35Sstevel 	/*
118603831d35Sstevel 	 * Get a list of failed parts (ie. devices with a status of
118703831d35Sstevel 	 * 'fail') from the OBP device tree and display them.
118803831d35Sstevel 	 */
118903831d35Sstevel 	get_failed_parts();
119003831d35Sstevel 
119103831d35Sstevel 	/* return unless -v option specified */
119203831d35Sstevel 	if (!flag) {
119303831d35Sstevel 		log_printf("\n", 0);
119403831d35Sstevel 		return;
119503831d35Sstevel 	}
119603831d35Sstevel 
119703831d35Sstevel 	/*
119803831d35Sstevel 	 * display time of latest powerfail. Not all systems
119903831d35Sstevel 	 * have this capability. For those that do not, this
120003831d35Sstevel 	 * is just a no-op.
120103831d35Sstevel 	 */
120203831d35Sstevel 	disp_powerfail(root);
120303831d35Sstevel 
120403831d35Sstevel 	/* Print the PROM revisions here */
120503831d35Sstevel 	serengeti_display_hw_revisions(root, tree->bd_list);
120603831d35Sstevel }
120703831d35Sstevel 
120803831d35Sstevel /*
120903831d35Sstevel  * local functions -  functions that are only needed inside this library
121003831d35Sstevel  */
121103831d35Sstevel 
121203831d35Sstevel static void
serengeti_display_hw_revisions(Prom_node * root,Board_node * bdlist)121303831d35Sstevel serengeti_display_hw_revisions(Prom_node *root, Board_node *bdlist)
121403831d35Sstevel {
121503831d35Sstevel 	Prom_node	*pnode;
121603831d35Sstevel 	char		*value;
121703831d35Sstevel 
121803831d35Sstevel 	/* Print the header */
121903831d35Sstevel 	log_printf("\n", 0);
122003831d35Sstevel 	log_printf("=========================", 0);
122103831d35Sstevel 	log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
122203831d35Sstevel 	log_printf("=======================================", 0);
122303831d35Sstevel 	log_printf("\n", 0);
122403831d35Sstevel 	log_printf("\n", 0);
122503831d35Sstevel 
122603831d35Sstevel 	/* Display Prom revision header */
122703831d35Sstevel 	log_printf("System PROM revisions:\n", 0);
122803831d35Sstevel 	log_printf("----------------------\n", 0);
122903831d35Sstevel 
123003831d35Sstevel 	/*
123103831d35Sstevel 	 * Display OBP version info
123203831d35Sstevel 	 */
123303831d35Sstevel 	pnode = dev_find_node(root, "openprom");
123403831d35Sstevel 	if (pnode != NULL) {
123503831d35Sstevel 		value = (char *)get_prop_val(find_prop(pnode, "version"));
123603831d35Sstevel 		log_printf("%s\n\n", value, 0);
123703831d35Sstevel 	} else {
123803831d35Sstevel 		log_printf("OBP ???\n\n", value, 0);
123903831d35Sstevel 	}
124003831d35Sstevel 
124103831d35Sstevel 	/*
124203831d35Sstevel 	 * Display ASIC revisions
124303831d35Sstevel 	 */
124403831d35Sstevel 	log_printf("IO ASIC revisions:\n", 0);
124503831d35Sstevel 	log_printf("------------------\n", 0);
124603831d35Sstevel 
124703831d35Sstevel 	log_printf("                            Port\n", 0);
124803831d35Sstevel 	log_printf("FRU Name    Model            ID    Status", 0);
124903831d35Sstevel #ifdef DEBUG
125003831d35Sstevel 	log_printf("   Version  Notes\n", 0);
125103831d35Sstevel #else
125203831d35Sstevel 	log_printf("   Version\n", 0);
125303831d35Sstevel #endif
125403831d35Sstevel 	/* ---------FRU Name--Model-----------Port-Status */
125503831d35Sstevel 	log_printf("----------- --------------- ---- ---------- "
125603831d35Sstevel #ifdef DEBUG
1257e79c98e6Szk 	    "-------  "
125803831d35Sstevel #endif
1259e79c98e6Szk 	    "-------\n", 0);
126003831d35Sstevel 	/*
126103831d35Sstevel 	 * Display SCHIZO version info
126203831d35Sstevel 	 */
126303831d35Sstevel 	display_schizo_revisions(bdlist, SG_SCHIZO_GOOD);
126403831d35Sstevel 
126503831d35Sstevel 	/*
126603831d35Sstevel 	 * Display sgsbbc version info
126703831d35Sstevel 	 */
126803831d35Sstevel 	display_sgsbbc_revisions(bdlist);
126903831d35Sstevel }
127003831d35Sstevel 
127103831d35Sstevel /*
127203831d35Sstevel  * This function displays Schizo and Xmits revision of boards
127303831d35Sstevel  */
127403831d35Sstevel static int
display_schizo_revisions(Board_node * bdlist,int mode)127503831d35Sstevel display_schizo_revisions(Board_node *bdlist, int mode)
127603831d35Sstevel {
127703831d35Sstevel 	Prom_node	*pnode;
127803831d35Sstevel 	int		*int_val;
127903831d35Sstevel 	int		portid;
128003831d35Sstevel 	int		prev_portid = -1;
128103831d35Sstevel 	char		*model;
128203831d35Sstevel 	char		*status_a, *status_b;
128303831d35Sstevel 	char		status[MAX_STATUS_LEN];
128403831d35Sstevel 	int		version;
1285aa5636e5SPeter Tribble 	int		node_id;
128603831d35Sstevel #ifdef DEBUG
128703831d35Sstevel 	uint32_t	a_notes, b_notes;
128803831d35Sstevel #endif
128903831d35Sstevel 	int		pci_bus;
129003831d35Sstevel 	/*
129103831d35Sstevel 	 * rv is used when mode is set to SG_SCHIZO_FAILED.
129203831d35Sstevel 	 * We need to signal if a failure is found so that
129303831d35Sstevel 	 * the correct headers/footers can be printed.
129403831d35Sstevel 	 *
129503831d35Sstevel 	 * rv = 1 implies a failed/disavled schizo device
129603831d35Sstevel 	 * rv = 0 implies all other cases
129703831d35Sstevel 	 */
129803831d35Sstevel 	int		rv = 0;
129903831d35Sstevel 	Board_node	*bnode;
130003831d35Sstevel 	void		*value;
130103831d35Sstevel 
130203831d35Sstevel 	bnode = bdlist;
130303831d35Sstevel 	while (bnode != NULL) {
130403831d35Sstevel 		/*
130503831d35Sstevel 		 * search this board node for all Schizos
130603831d35Sstevel 		 */
130703831d35Sstevel 		for (pnode = dev_find_node_by_compatible(bnode->nodes,
1308e79c98e6Szk 		    SCHIZO_COMPATIBLE); pnode != NULL;
130903831d35Sstevel 		    pnode = dev_next_node_by_compatible(pnode,
1310e79c98e6Szk 		    SCHIZO_COMPATIBLE)) {
131103831d35Sstevel 
131203831d35Sstevel 			char	fru_name[MAX_FRU_NAME_LEN] = "";
131303831d35Sstevel 
131403831d35Sstevel 			/*
131503831d35Sstevel 			 * get the reg property to determine
131603831d35Sstevel 			 * whether we are looking at side A or B
131703831d35Sstevel 			 */
131803831d35Sstevel 			int_val = (int *)get_prop_val
1319e79c98e6Szk 			    (find_prop(pnode, "reg"));
132003831d35Sstevel 			if (int_val != NULL) {
132103831d35Sstevel 				int_val ++; /* second integer in array */
132203831d35Sstevel 				pci_bus = ((*int_val) & 0x7f0000);
132303831d35Sstevel 			}
132403831d35Sstevel 
132503831d35Sstevel 			/* get portid */
132603831d35Sstevel 			int_val = (int *)get_prop_val
1327e79c98e6Szk 			    (find_prop(pnode, "portid"));
132803831d35Sstevel 			if (int_val == NULL)
132903831d35Sstevel 				continue;
133003831d35Sstevel 
133103831d35Sstevel 			portid = *int_val;
133203831d35Sstevel 
133303831d35Sstevel 			/*
133403831d35Sstevel 			 * If this is a new portid and it is PCI bus B,
133503831d35Sstevel 			 * we skip onto the PCI bus A. (PCI-A and PCI-B share
133603831d35Sstevel 			 * the same portid)
133703831d35Sstevel 			 */
133803831d35Sstevel 			if ((portid != prev_portid) && (pci_bus == 0x700000)) {
133903831d35Sstevel 				prev_portid = portid;
134003831d35Sstevel 				/* status */
134103831d35Sstevel 				status_b = (char *)get_prop_val
134203831d35Sstevel 				    (find_prop(pnode, "status"));
134303831d35Sstevel #ifdef DEBUG
134403831d35Sstevel 				b_notes = pci_bus;
134503831d35Sstevel #endif
134603831d35Sstevel 				continue; /* skip to the next schizo */
134703831d35Sstevel 			}
134803831d35Sstevel 
134903831d35Sstevel 			/*
135003831d35Sstevel 			 * This must be side A of the same Schizo.
135103831d35Sstevel 			 * Gather all its props and display them.
135203831d35Sstevel 			 */
135303831d35Sstevel #ifdef DEBUG
135403831d35Sstevel 			a_notes = pci_bus;
135503831d35Sstevel #endif
135603831d35Sstevel 
135703831d35Sstevel 			prev_portid = portid;
135803831d35Sstevel 
135903831d35Sstevel 			/* get the node-id */
136003831d35Sstevel 			node_id =  SG_PORTID_TO_NODEID(portid);
136103831d35Sstevel 
136203831d35Sstevel 			/* model */
136303831d35Sstevel 			model = (char *)get_prop_val
1364e79c98e6Szk 			    (find_prop(pnode, "model"));
136503831d35Sstevel 
136603831d35Sstevel 			/* version */
136703831d35Sstevel 			value = (int *)get_prop_val
1368e79c98e6Szk 			    (find_prop(pnode, "module-revision#"));
136903831d35Sstevel 
137003831d35Sstevel 			if (value)
137103831d35Sstevel 				int_val = (int *)value;
137203831d35Sstevel 			else
137303831d35Sstevel 				int_val = (int *)get_prop_val
1374e79c98e6Szk 				    (find_prop(pnode, "version#"));
137503831d35Sstevel 			if (int_val != NULL)
137603831d35Sstevel 				version = *int_val;
137703831d35Sstevel 			else
137803831d35Sstevel 				version = -1;
137903831d35Sstevel 
138003831d35Sstevel 			/* status */
138103831d35Sstevel 			status_a = (char *)get_prop_val(find_prop
1382e79c98e6Szk 			    (pnode, "status"));
138303831d35Sstevel 
138403831d35Sstevel 			/*
138503831d35Sstevel 			 * Display the data
138603831d35Sstevel 			 */
138703831d35Sstevel 			/* FRU Name */
138803831d35Sstevel 			SG_SET_FRU_NAME_NODE(fru_name, node_id);
138903831d35Sstevel 			SG_SET_FRU_NAME_IO_BOARD(fru_name,
1390e79c98e6Szk 			    SG_IO_BD_PORTID_TO_BD_NUM(portid));
139103831d35Sstevel 			SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
139203831d35Sstevel 
139303831d35Sstevel 			if (mode == SG_SCHIZO_FAILED) {
139403831d35Sstevel 				if ((status_a != (char *)NULL) &&
139503831d35Sstevel 				    ((status_b != (char *)NULL))) {
139603831d35Sstevel 					if ((strcmp
139703831d35Sstevel 					    (status_a, SG_DISABLED) == 0) &&
139803831d35Sstevel 					    (strcmp(status_b,
1399e79c98e6Szk 					    SG_DISABLED) == 0)) {
140003831d35Sstevel 						log_printf("\tFRU Type : %s\n ",
1401e79c98e6Szk 						    model, 0);
140203831d35Sstevel 						log_printf("\tLocation : %s\n",
1403e79c98e6Szk 						    fru_name, 0);
140403831d35Sstevel 						log_printf
140503831d35Sstevel 						    ("\tPROM status: %s\n\n",
140603831d35Sstevel 						    SG_DISABLED, 0);
140703831d35Sstevel 						rv = 1;
140803831d35Sstevel 					}
140903831d35Sstevel 				}
141003831d35Sstevel 				continue;
141103831d35Sstevel 			}
141203831d35Sstevel 			/*
141303831d35Sstevel 			 * This section of code is executed when displaying
141403831d35Sstevel 			 * non-failed schizo devices.  If the mode is set to
141503831d35Sstevel 			 * SG_SCHIZO_FAILED, then this section of code will
141603831d35Sstevel 			 * not be executed
141703831d35Sstevel 			 */
141803831d35Sstevel 			if ((status_a == (char *)NULL) &&
141903831d35Sstevel 			    ((status_b == (char *)NULL)))
142003831d35Sstevel 				sprintf(status, " %s      ", SG_OK);
142103831d35Sstevel 			else if ((status_a == (char *)NULL) &&
1422e79c98e6Szk 			    ((strcmp(status_b, SG_DISABLED) == 0)))
142303831d35Sstevel 				sprintf(status, " %s", SG_DEGRADED);
142403831d35Sstevel 			else if ((status_b == (char *)NULL) &&
1425e79c98e6Szk 			    ((strcmp(status_a, SG_DISABLED) == 0)))
142603831d35Sstevel 				sprintf(status, " %s", SG_DEGRADED);
142703831d35Sstevel 			else
142803831d35Sstevel 				continue;
142903831d35Sstevel 
143003831d35Sstevel 			log_printf("%-12s", fru_name, 0);
143103831d35Sstevel 
143203831d35Sstevel 			/* model */
143303831d35Sstevel 
143403831d35Sstevel 			if (model != NULL)
143503831d35Sstevel 				log_printf("%-15s  ", model, 0);
143603831d35Sstevel 			else
143703831d35Sstevel 				log_printf("%-15s  ", "unknown", 0);
143803831d35Sstevel 			/* portid */
143903831d35Sstevel 			log_printf("%-3d ", portid, 0);
144003831d35Sstevel 
144103831d35Sstevel 			/* status */
144203831d35Sstevel 			log_printf("%s", status, 0);
144303831d35Sstevel 
144403831d35Sstevel 			/* version */
144503831d35Sstevel 			log_printf("     %-4d   ", version, 0);
144603831d35Sstevel #ifdef DEBUG
144703831d35Sstevel 			log_printf("0x%x 0x%x", a_notes, b_notes, 0);
144803831d35Sstevel 			log_printf(" %d", portid, 0);
144903831d35Sstevel #endif
145003831d35Sstevel 			log_printf("\n", 0);
145103831d35Sstevel 		}
145203831d35Sstevel 		bnode = bnode->next;
145303831d35Sstevel 	}
145403831d35Sstevel 	return (rv);
145503831d35Sstevel }
145603831d35Sstevel 
145703831d35Sstevel static void
display_sgsbbc_revisions(Board_node * bdlist)145803831d35Sstevel display_sgsbbc_revisions(Board_node *bdlist)
145903831d35Sstevel {
146003831d35Sstevel 
146103831d35Sstevel 	Prom_node	*pnode;
146203831d35Sstevel 	int		*int_val;
146303831d35Sstevel 	int		portid;
146403831d35Sstevel 	char		*model;
146503831d35Sstevel 	char		*status;
146603831d35Sstevel 	int		revision;
1467aa5636e5SPeter Tribble 	int		node_id;
146803831d35Sstevel 	Board_node	*bnode;
146903831d35Sstevel 
147003831d35Sstevel #ifdef DEBUG
147103831d35Sstevel 	char	*slot_name;
147203831d35Sstevel 	char	notes[30];
147303831d35Sstevel 	char	*value;
147403831d35Sstevel #endif
147503831d35Sstevel 
147603831d35Sstevel 	bnode = bdlist;
147703831d35Sstevel 	while (bnode != NULL) {
147803831d35Sstevel 		/*
147903831d35Sstevel 		 * search this board node for all sgsbbc's
148003831d35Sstevel 		 */
148103831d35Sstevel 		for (pnode = dev_find_node_by_type(bnode->nodes, "model",
1482e79c98e6Szk 		    "SUNW,sgsbbc"); pnode != NULL;
1483e79c98e6Szk 		    pnode = dev_next_node_by_type(pnode, "model",
1484e79c98e6Szk 		    "SUNW,sgsbbc")) {
148503831d35Sstevel 
148603831d35Sstevel 			char	fru_name[MAX_FRU_NAME_LEN] = "";
148703831d35Sstevel 
148803831d35Sstevel 			/*
148903831d35Sstevel 			 * We need to go to this node's parent to
149003831d35Sstevel 			 * get a portid to tell us what board it is on
149103831d35Sstevel 			 */
149203831d35Sstevel 			int_val = (int *)get_prop_val
1493e79c98e6Szk 			    (find_prop(pnode->parent, "portid"));
149403831d35Sstevel 			if (int_val == NULL)
149503831d35Sstevel 				continue;
149603831d35Sstevel 
149703831d35Sstevel 			portid = *int_val;
149803831d35Sstevel 			/* get the node-id */
149903831d35Sstevel 			node_id =  SG_PORTID_TO_NODEID(portid);
150003831d35Sstevel 
150103831d35Sstevel 			/* model */
150203831d35Sstevel 			model = (char *)get_prop_val
1503e79c98e6Szk 			    (find_prop(pnode, "model"));
150403831d35Sstevel 
150503831d35Sstevel 			/* status */
150603831d35Sstevel 			status = (char *)get_prop_val(find_prop
1507e79c98e6Szk 			    (pnode, "status"));
150803831d35Sstevel 
150903831d35Sstevel 			/* revision */
151003831d35Sstevel 			int_val = (int *)get_prop_val
1511e79c98e6Szk 			    (find_prop(pnode, "revision-id"));
151203831d35Sstevel 			if (int_val != NULL)
151303831d35Sstevel 				revision = *int_val;
151403831d35Sstevel 			else
151503831d35Sstevel 				revision = -1;
151603831d35Sstevel 
151703831d35Sstevel #ifdef DEBUG
151803831d35Sstevel 			value = (char *)get_prop_val(
1519e79c98e6Szk 			    find_prop(pnode->parent, "slot-names"));
152003831d35Sstevel 			if (value != NULL) {
152103831d35Sstevel 				/* Skip the 4 byte bitmask */
152203831d35Sstevel 				slot_name = (char *)value + sizeof (int);
152303831d35Sstevel 			} else {
152403831d35Sstevel 				strcpy(slot_name, "not_found");
152503831d35Sstevel 			}
152603831d35Sstevel 			(void) sprintf(notes, "[%s] portid [%d]", slot_name,
1527e79c98e6Szk 			    portid);
152803831d35Sstevel #endif
152903831d35Sstevel 			/*
153003831d35Sstevel 			 * Display the data
153103831d35Sstevel 			 */
153203831d35Sstevel 			/* FRU Name */
153303831d35Sstevel 			SG_SET_FRU_NAME_NODE(fru_name, node_id);
153403831d35Sstevel 			SG_SET_FRU_NAME_IO_BOARD(fru_name,
1535e79c98e6Szk 			    SG_IO_BD_PORTID_TO_BD_NUM(portid));
153603831d35Sstevel 			SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
153703831d35Sstevel 			log_printf("%-12s", fru_name, 0);
153803831d35Sstevel 
153903831d35Sstevel 			/* model */
154003831d35Sstevel 			if (model != NULL)
154103831d35Sstevel 				log_printf("%-15s  ", model, 0);
154203831d35Sstevel 			else
154303831d35Sstevel 				log_printf("%-15s  ", "unknown", 0);
154403831d35Sstevel 			/* portid */
154503831d35Sstevel 			log_printf("%-3d ", portid, 0);
154603831d35Sstevel 			/* status */
154703831d35Sstevel 			if (status == (char *)NULL)
154803831d35Sstevel 				log_printf(" ok      ", 0);
154903831d35Sstevel 			else
155003831d35Sstevel 				log_printf(" fail    ", 0);
155103831d35Sstevel 			/* revision */
155203831d35Sstevel 			log_printf("     %-4d   ", revision, 0);
155303831d35Sstevel #ifdef DEBUG
155403831d35Sstevel 			log_printf("%s", notes, 0);
155503831d35Sstevel #endif
155603831d35Sstevel 			log_printf("\n", 0);
155703831d35Sstevel 		}
155803831d35Sstevel 		bnode = bnode->next;
155903831d35Sstevel 	}
156003831d35Sstevel }
156103831d35Sstevel 
156203831d35Sstevel /*ARGSUSED0*/
156303831d35Sstevel void
display_hp_fail_fault(Sys_tree * tree,struct system_kstat_data * kstats)156403831d35Sstevel display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
156503831d35Sstevel {
156603831d35Sstevel 	serengeti_display_board_info(ACTIVE);
156703831d35Sstevel 	serengeti_display_board_info(INACTIVE);
156803831d35Sstevel }
156903831d35Sstevel 
157003831d35Sstevel /*
157103831d35Sstevel  * display_failed_parts
157203831d35Sstevel  *
157303831d35Sstevel  * Display the failed parts in the system. This function looks for
157403831d35Sstevel  * the status property in all PROM nodes contained in the Sys_tree
157503831d35Sstevel  * passed in.
157603831d35Sstevel  */
157703831d35Sstevel int
display_failed_parts(Sys_tree * tree)157803831d35Sstevel display_failed_parts(Sys_tree *tree)
157903831d35Sstevel {
158003831d35Sstevel 	int system_failed = 0;
158103831d35Sstevel 	int bank_failed = 0;
158203831d35Sstevel 	int schizo_failed = FALSE;
158303831d35Sstevel 	int portid, nodeid, board;
158403831d35Sstevel 	Board_node *bnode = tree->bd_list;
158503831d35Sstevel 	Prom_node *pnode;
158603831d35Sstevel 	int *coreid, *impl;
158703831d35Sstevel 	print_flag = TRUE;
158803831d35Sstevel 
158903831d35Sstevel 	/*
159003831d35Sstevel 	 * go through all of the OBP nodes looking for
159103831d35Sstevel 	 * failed units.
159203831d35Sstevel 	 */
159303831d35Sstevel 	while (bnode != NULL) {
159403831d35Sstevel 
159503831d35Sstevel 		pnode = find_failed_node(bnode->nodes);
159603831d35Sstevel 		if ((pnode != NULL) && !system_failed) {
159703831d35Sstevel 			system_failed = TRUE;
159803831d35Sstevel 			log_printf("\n", 0);
159903831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
1600e79c98e6Szk 			    "Failed Field Replaceable Units (FRU) in "
1601e79c98e6Szk 			    "System:\n"), 0);
160203831d35Sstevel 			log_printf("=========================="
1603e79c98e6Szk 			    "====================\n", 0);
160403831d35Sstevel 		}
160503831d35Sstevel 
160603831d35Sstevel 		while (pnode != NULL) {
160703831d35Sstevel 			void *status;
160803831d35Sstevel 			char *name, *type, *model;
160903831d35Sstevel 
161003831d35Sstevel 			char	fru_name[MAX_FRU_NAME_LEN] = "";
161103831d35Sstevel 
161203831d35Sstevel 			status = get_prop_val(find_prop(pnode, "status"));
161303831d35Sstevel 			name = get_node_name(pnode);
161403831d35Sstevel 
161503831d35Sstevel 			/* sanity check of data retreived from PROM */
161603831d35Sstevel 			if ((status == NULL) || (name == NULL)) {
161703831d35Sstevel 				pnode = next_failed_node(pnode);
161803831d35Sstevel 				continue;
161903831d35Sstevel 			}
162003831d35Sstevel 
162103831d35Sstevel 			type = get_node_type(pnode);
162203831d35Sstevel 			portid = get_id(pnode);
162303831d35Sstevel 			model = (char *)get_prop_val
162403831d35Sstevel 			    (find_prop(pnode, "model"));
162503831d35Sstevel 
162603831d35Sstevel 			/*
162703831d35Sstevel 			 * Determine whether FRU is CPU module, Mem Controller,
162803831d35Sstevel 			 * PCI card, schizo,xmits or sgsbbc.
162903831d35Sstevel 			 */
163003831d35Sstevel 			if ((model != NULL) && strstr(model, "sgsbbc")) {
163103831d35Sstevel 				/*
163203831d35Sstevel 				 * sgsbbc / bootbus-controller
163303831d35Sstevel 				 */
163403831d35Sstevel 				portid = get_id(pnode->parent);
163503831d35Sstevel 				nodeid = SG_PORTID_TO_NODEID(portid);
163603831d35Sstevel 				board = SG_PORTID_TO_BOARD_NUM(portid);
163703831d35Sstevel 
163803831d35Sstevel 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
163903831d35Sstevel 				SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
164003831d35Sstevel 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
164103831d35Sstevel 
164203831d35Sstevel 				log_printf("\tFailed Device : %s (%s)\n", model,
1643e79c98e6Szk 				    name, 0);
164403831d35Sstevel 				log_printf("\tLocation : %s\n", fru_name, 0);
164503831d35Sstevel 
164603831d35Sstevel 			} else if (strstr(name, "pci") && (portid == -1)) {
164703831d35Sstevel 				/*
164803831d35Sstevel 				 * PCI Bridge if name = pci and it doesn't
164903831d35Sstevel 				 * have a portid.
165003831d35Sstevel 				 */
165103831d35Sstevel 				portid = get_id(pnode->parent);
165203831d35Sstevel 				nodeid = SG_PORTID_TO_NODEID(portid);
165303831d35Sstevel 				board = SG_PORTID_TO_BOARD_NUM(portid);
165403831d35Sstevel 
165503831d35Sstevel 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
165603831d35Sstevel 				SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
165703831d35Sstevel 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
165803831d35Sstevel 
165903831d35Sstevel 				log_printf("\tFRU type : ", 0);
166003831d35Sstevel 				log_printf("PCI Bridge Device\n", 0);
166103831d35Sstevel 				log_printf("\tLocation : %s\n", fru_name, 0);
166203831d35Sstevel 
166303831d35Sstevel 			} else if ((type != NULL) &&
166403831d35Sstevel 			    (strstr(type, "cpu") ||
166503831d35Sstevel 			    strstr(type, "memory-controller"))) {
166603831d35Sstevel 				/*
166703831d35Sstevel 				 * CPU or memory controller
166803831d35Sstevel 				 */
166903831d35Sstevel 				portid = get_id(pnode);
167003831d35Sstevel 				/*
167103831d35Sstevel 				 * For cpu nodes that belong to a CMP, the
167203831d35Sstevel 				 * portid is stored in the parent "cmp" node.
167303831d35Sstevel 				 */
167403831d35Sstevel 				if (portid == -1)
167503831d35Sstevel 					portid = get_id(pnode->parent);
167603831d35Sstevel 				nodeid = SG_PORTID_TO_NODEID(portid);
167703831d35Sstevel 				board = SG_PORTID_TO_BOARD_NUM(portid);
167803831d35Sstevel 
167903831d35Sstevel 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
168003831d35Sstevel 				SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
168103831d35Sstevel 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 4);
168203831d35Sstevel 
168303831d35Sstevel 				log_printf("\tFRU type : ", 0);
168403831d35Sstevel 
168503831d35Sstevel 				if (strstr(type, "memory-controller"))
168603831d35Sstevel 					log_printf("Memory Controller on ", 0);
168703831d35Sstevel 
168803831d35Sstevel 				log_printf("UltraSPARC module\n", 0);
168903831d35Sstevel 
169003831d35Sstevel 				log_printf("\tLocation : %s\n", fru_name, 0);
169103831d35Sstevel 
169203831d35Sstevel 			} else {
169303831d35Sstevel 				/*
169403831d35Sstevel 				 * It should only be a PCI card if we get to
169503831d35Sstevel 				 * here but lets check to be sure.
169603831d35Sstevel 				 */
169703831d35Sstevel 				char *parents_model, *grandparents_model;
169803831d35Sstevel 				Prom_node *parent_pnode;
169903831d35Sstevel 				int pci_card_found = 0;
170003831d35Sstevel 
170103831d35Sstevel 				if (pnode->parent != NULL)
170203831d35Sstevel 					parent_pnode = pnode->parent;
170303831d35Sstevel 
170403831d35Sstevel 				/*
170503831d35Sstevel 				 * Is our parent a schizo or xmits
170603831d35Sstevel 				 */
170703831d35Sstevel 				parents_model = (char *)get_prop_val
170803831d35Sstevel 				    (find_prop(pnode->parent, "model"));
170903831d35Sstevel 				if ((parents_model != NULL) &&
171003831d35Sstevel 				    (strstr(parents_model, "SUNW,schizo") ||
171103831d35Sstevel 				    strstr(parents_model, "SUNW,xmits"))) {
171203831d35Sstevel 					portid = get_id(pnode->parent);
171303831d35Sstevel 					pci_card_found = TRUE;
171403831d35Sstevel 				}
171503831d35Sstevel 
171603831d35Sstevel 				/*
171703831d35Sstevel 				 * Is our grandparent a schizo xmits
171803831d35Sstevel 				 */
171903831d35Sstevel 				grandparents_model = (char *)get_prop_val
172003831d35Sstevel 				    (find_prop(parent_pnode->parent, "model"));
172103831d35Sstevel 				if ((grandparents_model != NULL) &&
172203831d35Sstevel 				    (strstr(grandparents_model,
172303831d35Sstevel 				    "SUNW,schizo") ||
172403831d35Sstevel 				    strstr(grandparents_model,
172503831d35Sstevel 				    "SUNW,xmits"))) {
172603831d35Sstevel 					portid = get_id(parent_pnode->parent);
172703831d35Sstevel 					pci_card_found = TRUE;
172803831d35Sstevel 				}
172903831d35Sstevel 
173003831d35Sstevel 				if (pci_card_found) {
173103831d35Sstevel 					nodeid = SG_PORTID_TO_NODEID(portid);
173203831d35Sstevel 					board = SG_PORTID_TO_BOARD_NUM(portid);
173303831d35Sstevel 
173403831d35Sstevel 					SG_SET_FRU_NAME_NODE(fru_name, nodeid);
173503831d35Sstevel 					SG_SET_FRU_NAME_IO_BOARD(fru_name,
1736e79c98e6Szk 					    board);
173703831d35Sstevel 					SG_SET_FRU_NAME_MODULE(fru_name,
1738e79c98e6Szk 					    portid % 2);
173903831d35Sstevel 
174003831d35Sstevel 					log_printf("\tFRU type :", 0);
174103831d35Sstevel 					log_printf(" PCI Card\n", 0);
174203831d35Sstevel 					log_printf("\tLocation : %s\n",
1743e79c98e6Szk 					    fru_name, 0);
174403831d35Sstevel 				}
174503831d35Sstevel 			}
174603831d35Sstevel 			log_printf("\tPROM status: %s\n\n", status, 0);
174703831d35Sstevel 
174803831d35Sstevel 			pnode = next_failed_node(pnode);
174903831d35Sstevel 		}
175003831d35Sstevel 		bnode = bnode->next;
175103831d35Sstevel 
175203831d35Sstevel 	}
175303831d35Sstevel 
175403831d35Sstevel 	bank_failed = display_us3_failed_banks(system_failed);
175503831d35Sstevel 	schizo_failed = display_schizo_revisions(tree->bd_list,
1756e79c98e6Szk 	    SG_SCHIZO_FAILED);
175703831d35Sstevel 	if (system_failed || bank_failed || schizo_failed)
175803831d35Sstevel 		return (1);
175903831d35Sstevel 	else
176003831d35Sstevel 		return (0);
176103831d35Sstevel }
176203831d35Sstevel 
176303831d35Sstevel 
176403831d35Sstevel /*
176503831d35Sstevel  * This routine displays the memory configuration for all boards in the
176603831d35Sstevel  * system.
176703831d35Sstevel  */
176803831d35Sstevel void
display_memoryconf(Sys_tree * tree)1769*2bcbf80cSPeter Tribble display_memoryconf(Sys_tree *tree)
177003831d35Sstevel {
177103831d35Sstevel 	Board_node	*bnode = tree->bd_list;
177203831d35Sstevel 
177303831d35Sstevel 	log_printf("========================= Memory Configuration"
1774e79c98e6Szk 	    " ===============================\n", 0);
177503831d35Sstevel 	log_printf("\n                     Logical  Logical  Logical ", 0);
177603831d35Sstevel 	log_printf("\n               Port  Bank     Bank     Bank         "
1777e79c98e6Szk 	    "DIMM    Interleave  Interleave", 0);
177803831d35Sstevel 	log_printf("\nFRU Name        ID   Num      Size     Status       "
1779e79c98e6Szk 	    "Size    Factor      Segment", 0);
178003831d35Sstevel 	log_printf("\n-------------  ----  ----     ------   -----------  "
1781e79c98e6Szk 	    "------  ----------  ----------", 0);
178203831d35Sstevel 
178303831d35Sstevel 	while (bnode != NULL) {
178403831d35Sstevel 		if (get_us3_mem_regs(bnode)) {
178503831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
178603831d35Sstevel 			    "\nFailed to get memory information.\n"), 0);
178703831d35Sstevel 			return;
178803831d35Sstevel 		}
178903831d35Sstevel 		bnode = bnode->next;
179003831d35Sstevel 	}
179103831d35Sstevel 
179203831d35Sstevel 	/* Display what we have found */
179303831d35Sstevel 	display_us3_banks();
179403831d35Sstevel }
179503831d35Sstevel 
179603831d35Sstevel /*
179703831d35Sstevel  * This function provides Serengeti's formatting of the memory config
179803831d35Sstevel  * information that get_us3_mem_regs() and display_us3_banks() code has
179903831d35Sstevel  * gathered. It overrides the generic print_us3_memory_line() code
180003831d35Sstevel  * which prints an error message.
180103831d35Sstevel  */
180203831d35Sstevel void
print_us3_memory_line(int portid,int bank_id,uint64_t bank_size,char * bank_status,uint64_t dimm_size,uint32_t intlv,int seg_id)180303831d35Sstevel print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
1804aa5636e5SPeter Tribble     char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
180503831d35Sstevel {
180603831d35Sstevel 	int		nodeid, board, mcid;
180703831d35Sstevel 	char		fru_name[MAX_FRU_NAME_LEN] = "";
180803831d35Sstevel 
1809aa5636e5SPeter Tribble 	mcid		= SG_PORTID_TO_SAFARI_ID(portid);
1810aa5636e5SPeter Tribble 	nodeid		= SG_PORTID_TO_NODEID(portid);
1811aa5636e5SPeter Tribble 	board		= SG_PORTID_TO_BOARD_NUM(portid);
181203831d35Sstevel 
181303831d35Sstevel 	SG_SET_FRU_NAME_NODE(fru_name, nodeid);
181403831d35Sstevel 	SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
181503831d35Sstevel 	SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
181603831d35Sstevel 	SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
181703831d35Sstevel 
181803831d35Sstevel 	log_printf("\n%-13s   %2d   %2d      %4lldMB    %11-s  %4lldMB "
1819e79c98e6Szk 	    "   %2d-way       %d",
1820e79c98e6Szk 	    fru_name, mcid,
1821e79c98e6Szk 	    (bank_id % 4), bank_size, bank_status, dimm_size,
1822e79c98e6Szk 	    intlv, seg_id, 0);
182303831d35Sstevel }
182403831d35Sstevel 
182503831d35Sstevel void
print_us3_failed_memory_line(int portid,int bank_id,char * bank_status)182603831d35Sstevel print_us3_failed_memory_line(int portid, int bank_id, char *bank_status)
182703831d35Sstevel {
182803831d35Sstevel 	int		nodeid, board, mcid;
182903831d35Sstevel 	char		fru_name[MAX_FRU_NAME_LEN] = "";
183003831d35Sstevel 
183103831d35Sstevel 	mcid		= SG_PORTID_TO_SAFARI_ID(portid);
183203831d35Sstevel 	nodeid		= SG_PORTID_TO_NODEID(portid);
183303831d35Sstevel 	board		= SG_PORTID_TO_BOARD_NUM(portid);
183403831d35Sstevel 
183503831d35Sstevel 	SG_SET_FRU_NAME_NODE(fru_name, nodeid);
183603831d35Sstevel 	SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
183703831d35Sstevel 	SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
183803831d35Sstevel 	SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
183903831d35Sstevel 
184003831d35Sstevel 	log_printf("\tFRU type : ", 0);
184103831d35Sstevel 	log_printf("Physical Memory Bank\n", 0);
184203831d35Sstevel 	log_printf("\tLocation : %s (Logical Bank %2d)\n",
1843e79c98e6Szk 	    fru_name, (bank_id %4), 0);
184403831d35Sstevel 	log_printf("\tPROM status: %s\n\n", bank_status, 0);
184503831d35Sstevel }
184603831d35Sstevel 
184703831d35Sstevel 
184803831d35Sstevel /*
184903831d35Sstevel  * Find the requested board struct in the system device tree.
185003831d35Sstevel  *
185103831d35Sstevel  * This function overrides the functionality of the generic find_board()
185203831d35Sstevel  * function in libprtdiag, but since we need to pass another parameter,
185303831d35Sstevel  * we cannot simply overlay the symbol table.
185403831d35Sstevel  */
185503831d35Sstevel static Board_node *
serengeti_find_board(Sys_tree * root,int board,int nodeid)185603831d35Sstevel serengeti_find_board(Sys_tree *root, int board, int nodeid)
185703831d35Sstevel {
185803831d35Sstevel 	Board_node *bnode = root->bd_list;
185903831d35Sstevel 
186003831d35Sstevel 	while ((bnode != NULL) &&
1861e79c98e6Szk 	    ((board != bnode->board_num) || (nodeid != bnode->node_id))) {
186203831d35Sstevel 		bnode = bnode->next;
186303831d35Sstevel 	}
186403831d35Sstevel 	return (bnode);
186503831d35Sstevel }
186603831d35Sstevel 
186703831d35Sstevel 
186803831d35Sstevel /*
186903831d35Sstevel  * Add a board to the system list in order (sorted by NodeID then board#).
187003831d35Sstevel  * Initialize all pointer fields to NULL.
187103831d35Sstevel  */
187203831d35Sstevel static Board_node *
serengeti_insert_board(Sys_tree * root,int board,int nodeid)187303831d35Sstevel serengeti_insert_board(Sys_tree *root, int board, int nodeid)
187403831d35Sstevel {
187503831d35Sstevel 	Board_node *bnode;
187603831d35Sstevel 	Board_node *temp = root->bd_list;
187703831d35Sstevel 
187803831d35Sstevel 	if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
187903831d35Sstevel 		perror("malloc");
188003831d35Sstevel 		exit(1);
188103831d35Sstevel 	}
188203831d35Sstevel 
188303831d35Sstevel 	bnode->nodes = NULL;
188403831d35Sstevel 	bnode->next = NULL;
188503831d35Sstevel 	bnode->board_num = board;
188603831d35Sstevel 	bnode->node_id = nodeid;
188703831d35Sstevel 	bnode->board_type = UNKNOWN_BOARD;
188803831d35Sstevel 
188903831d35Sstevel 	if (temp == NULL)
189003831d35Sstevel 		root->bd_list = bnode;
189103831d35Sstevel 
189203831d35Sstevel 	else if ((temp->board_num > board) && (temp->node_id >= nodeid)) {
189303831d35Sstevel 		bnode->next = temp;
189403831d35Sstevel 		root->bd_list = bnode;
189503831d35Sstevel 
189603831d35Sstevel 	} else {
189703831d35Sstevel 		while ((temp->next != NULL) &&
1898e79c98e6Szk 		    ((board > temp->next->board_num) ||
1899e79c98e6Szk 		    (nodeid > temp->node_id)))
190003831d35Sstevel 			temp = temp->next;
190103831d35Sstevel 
190203831d35Sstevel 		bnode->next = temp->next;
190303831d35Sstevel 		temp->next = bnode;
190403831d35Sstevel 	}
190503831d35Sstevel 	root->board_cnt++;
190603831d35Sstevel 
190703831d35Sstevel 	return (bnode);
190803831d35Sstevel }
190903831d35Sstevel 
191003831d35Sstevel /*
191103831d35Sstevel  * We call do_devinfo() in order to use the libdevinfo device tree
191203831d35Sstevel  * instead of OBP's device tree.
191303831d35Sstevel  */
191403831d35Sstevel int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)191503831d35Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
191603831d35Sstevel {
191703831d35Sstevel 
191803831d35Sstevel 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
191903831d35Sstevel 
192003831d35Sstevel }
192103831d35Sstevel 
192203831d35Sstevel /*
192303831d35Sstevel  * return the property value for the Prop passed in depending on
192403831d35Sstevel  * which tree (OBP/DEVINFO) is being used.
192503831d35Sstevel  */
192603831d35Sstevel void *
get_prop_val(Prop * prop)192703831d35Sstevel get_prop_val(Prop *prop)
192803831d35Sstevel {
192903831d35Sstevel 	if (prop == NULL)
193003831d35Sstevel 		return (NULL);
193103831d35Sstevel 
193203831d35Sstevel 	/* Check which tree is being used. */
193303831d35Sstevel 	if (tree == DEVINFO_TREE)
193403831d35Sstevel 		return ((void *)(prop->value.val_ptr));
193503831d35Sstevel 	else {
193603831d35Sstevel 		if (prop->value.opp.holds_array)
193703831d35Sstevel 			return ((void *)(prop->value.opp.oprom_array));
193803831d35Sstevel 		else
193903831d35Sstevel 			return ((void *)(&prop->value.opp.oprom_node[0]));
194003831d35Sstevel 	}
194103831d35Sstevel }
194203831d35Sstevel 
194303831d35Sstevel /*
194403831d35Sstevel  * Search a Prom node and retrieve the property with the correct
194503831d35Sstevel  * name depending on which tree (OBP/DEVINFO) is being used.
194603831d35Sstevel  */
194703831d35Sstevel Prop *
find_prop(Prom_node * pnode,char * name)194803831d35Sstevel find_prop(Prom_node *pnode, char *name)
194903831d35Sstevel {
195003831d35Sstevel 	Prop *prop;
195103831d35Sstevel 
195203831d35Sstevel 	if (pnode  == NULL)
195303831d35Sstevel 		return (NULL);
195403831d35Sstevel 
195503831d35Sstevel 	if (pnode->props == NULL)
195603831d35Sstevel 		return (NULL);
195703831d35Sstevel 
195803831d35Sstevel 	prop = pnode->props;
195903831d35Sstevel 
196003831d35Sstevel 	/* Check which tree is being used. */
196103831d35Sstevel 	if (tree == DEVINFO_TREE) {
196203831d35Sstevel 		while ((prop != NULL) &&
196303831d35Sstevel 		    (strcmp((char *)(prop->name.val_ptr), name)))
196403831d35Sstevel 			prop = prop->next;
196503831d35Sstevel 	} else {
196603831d35Sstevel 		while ((prop != NULL) && (strcmp((char *)
196703831d35Sstevel 		    (prop->name.opp.oprom_array), name)))
196803831d35Sstevel 			prop = prop->next;
196903831d35Sstevel 	}
197003831d35Sstevel 	return (prop);
197103831d35Sstevel }
197203831d35Sstevel 
197303831d35Sstevel /*
197403831d35Sstevel  * This function searches through the properties of the node passed in
197503831d35Sstevel  * and returns a pointer to the value of the name property
197603831d35Sstevel  * depending on which tree (OBP/DEVINFO) is being used.
197703831d35Sstevel  */
197803831d35Sstevel char *
get_node_name(Prom_node * pnode)197903831d35Sstevel get_node_name(Prom_node *pnode)
198003831d35Sstevel {
198103831d35Sstevel 	Prop *prop;
198203831d35Sstevel 
198303831d35Sstevel 	if (pnode == NULL)
198403831d35Sstevel 		return (NULL);
198503831d35Sstevel 
198603831d35Sstevel 	prop = pnode->props;
198703831d35Sstevel 	while (prop != NULL) {
198803831d35Sstevel 		/* Check which tree is being used. */
198903831d35Sstevel 		if (tree == DEVINFO_TREE) {
199003831d35Sstevel 			if (strcmp("name", (char *)prop->name.val_ptr) == 0)
199103831d35Sstevel 				return ((char *)prop->value.val_ptr);
199203831d35Sstevel 		} else {
199303831d35Sstevel 			if (strcmp("name", prop->name.opp.oprom_array) == 0)
199403831d35Sstevel 				return (prop->value.opp.oprom_array);
199503831d35Sstevel 		}
199603831d35Sstevel 		prop = prop->next;
199703831d35Sstevel 	}
199803831d35Sstevel 	return (NULL);
199903831d35Sstevel }
200003831d35Sstevel 
200103831d35Sstevel /*
200203831d35Sstevel  * This function searches through the properties of the node passed in
200303831d35Sstevel  * and returns a pointer to the value of the device_type property
200403831d35Sstevel  * depending on which tree (OBP/DEVINFO) is being used.
200503831d35Sstevel  */
200603831d35Sstevel char *
get_node_type(Prom_node * pnode)200703831d35Sstevel get_node_type(Prom_node *pnode)
200803831d35Sstevel {
200903831d35Sstevel 	Prop *prop;
201003831d35Sstevel 
201103831d35Sstevel 	if (pnode == NULL)
201203831d35Sstevel 		return (NULL);
201303831d35Sstevel 
201403831d35Sstevel 	prop = pnode->props;
201503831d35Sstevel 	while (prop != NULL) {
201603831d35Sstevel 		/* Check which tree is being used. */
201703831d35Sstevel 		if (tree == DEVINFO_TREE) {
201803831d35Sstevel 			if (strcmp("device_type", (char *)prop->name.val_ptr)
201903831d35Sstevel 			    == 0)
202003831d35Sstevel 				return ((char *)prop->value.val_ptr);
202103831d35Sstevel 		} else {
202203831d35Sstevel 			if (strcmp("device_type", prop->name.opp.oprom_array)
202303831d35Sstevel 			    == 0)
202403831d35Sstevel 				return (prop->value.opp.oprom_array);
202503831d35Sstevel 		}
202603831d35Sstevel 		prop = prop->next;
202703831d35Sstevel 	}
202803831d35Sstevel 	return (NULL);
202903831d35Sstevel }
203003831d35Sstevel 
203103831d35Sstevel /*
203203831d35Sstevel  * Take a snapshot of the OBP device tree and walk this snapshot
203303831d35Sstevel  * to find all failed HW (ie. devices with a status property of
203403831d35Sstevel  * 'fail'). Call display_failed_parts() to display the failed HW.
203503831d35Sstevel  */
203603831d35Sstevel void
get_failed_parts(void)203703831d35Sstevel get_failed_parts(void)
203803831d35Sstevel {
203903831d35Sstevel 	int system_failed = 0;
204003831d35Sstevel 	Sys_tree obp_sys_tree;		/* system information */
204103831d35Sstevel 
204203831d35Sstevel 	/* set the the system tree fields */
204303831d35Sstevel 	obp_sys_tree.sys_mem = NULL;
204403831d35Sstevel 	obp_sys_tree.boards = NULL;
204503831d35Sstevel 	obp_sys_tree.bd_list = NULL;
204603831d35Sstevel 	obp_sys_tree.board_cnt = 0;
204703831d35Sstevel 
204803831d35Sstevel 	if (promopen(O_RDONLY)) {
204903831d35Sstevel 		(void) fprintf(stderr, "%s",
2050e79c98e6Szk 		    dgettext(TEXT_DOMAIN, "openprom device "
2051e79c98e6Szk 		    "open failed"));
205203831d35Sstevel 		return;
205303831d35Sstevel 	}
205403831d35Sstevel 
205503831d35Sstevel 	if ((is_openprom() == 0) || (next(0) == 0)) {
205603831d35Sstevel 		(void) fprintf(stderr, "%s",
2057e79c98e6Szk 		    dgettext(TEXT_DOMAIN, "openprom device "
2058e79c98e6Szk 		    "error encountered."));
205903831d35Sstevel 		return;
206003831d35Sstevel 	}
206103831d35Sstevel 
206203831d35Sstevel 	tree = OBP_TREE;	/* Switch to the OBP tree */
206303831d35Sstevel 
206403831d35Sstevel 	(void) walk(&obp_sys_tree, NULL, next(0));
206503831d35Sstevel 
206603831d35Sstevel 	system_failed = display_failed_parts(&obp_sys_tree);
206703831d35Sstevel 
206803831d35Sstevel 	if (!system_failed) {
206903831d35Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
2070e79c98e6Szk 		    "No Hardware failures found in System\n"), 0);
207103831d35Sstevel 	}
207203831d35Sstevel 	promclose();
207303831d35Sstevel 	tree = DEVINFO_TREE;	/* Switch back to the DEVINFO tree */
207403831d35Sstevel }
207503831d35Sstevel 
207603831d35Sstevel /*
207703831d35Sstevel  * get_slot_name figures out the slot no. for the card. In the case of
207803831d35Sstevel  * XMITS slots 2 & 3 and slots 6 & 7 are reversed in slot_name by OBP
207903831d35Sstevel  * so we need to cater for this to correctly identify the slot no.
208003831d35Sstevel  */
208103831d35Sstevel static void
get_slot_name(struct io_card * card,char * slot_name)208203831d35Sstevel get_slot_name(struct io_card *card, char *slot_name)
208303831d35Sstevel {
208403831d35Sstevel 	char tmp_ptr[2];
208503831d35Sstevel 
208603831d35Sstevel 	if (strlen(slot_name) != 0) {
208703831d35Sstevel 		if (strcmp(card->notes, XMITS_COMPATIBLE) == 0) {
208803831d35Sstevel 			(void) sprintf(tmp_ptr, "%c",
2089e79c98e6Szk 			    slot_name[strlen(slot_name) -1]);
209003831d35Sstevel 			switch (tmp_ptr[0]) {
209103831d35Sstevel 			case '2':
209203831d35Sstevel 				(void) sprintf(card->slot_str, "%c", '3');
209303831d35Sstevel 				break;
209403831d35Sstevel 			case '3':
209503831d35Sstevel 				(void) sprintf(card->slot_str, "%c", '2');
209603831d35Sstevel 				break;
209703831d35Sstevel 			case '6':
209803831d35Sstevel 				(void) sprintf(card->slot_str, "%c", '7');
209903831d35Sstevel 				break;
210003831d35Sstevel 			case '7':
210103831d35Sstevel 				(void) sprintf(card->slot_str, "%c", '6');
210203831d35Sstevel 				break;
210303831d35Sstevel 			default:
210403831d35Sstevel 				(void) sprintf(card->slot_str, "%c",
2105e79c98e6Szk 				    slot_name[strlen(slot_name) -1]);
210603831d35Sstevel 			}
210703831d35Sstevel 		} else
210803831d35Sstevel 			(void) sprintf(card->slot_str, "%c",
2109e79c98e6Szk 			    slot_name[strlen(slot_name) -1]);
211003831d35Sstevel 	} else
211103831d35Sstevel 		(void) sprintf(card->slot_str, "-");
211203831d35Sstevel }
2113