11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
5*5889Szk194757  * Common Development and Distribution License (the "License").
6*5889Szk194757  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel /*
22*5889Szk194757  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
231708Sstevel  * Use is subject to license terms.
241708Sstevel  *
251708Sstevel  * Serengeti Platform specific functions.
261708Sstevel  *
271708Sstevel  */
281708Sstevel 
291708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
301708Sstevel 
311708Sstevel #include <stdio.h>
321708Sstevel #include <stdlib.h>
331708Sstevel #include <unistd.h>
341708Sstevel #include <kstat.h>
351708Sstevel #include <string.h>
361708Sstevel #include <assert.h>
371708Sstevel #include <alloca.h>
381708Sstevel #include <libintl.h>
391708Sstevel #include <fcntl.h>
401708Sstevel #include <varargs.h>
411708Sstevel 
421708Sstevel #include <sys/openpromio.h>
431708Sstevel #include <sys/sysmacros.h>
441708Sstevel 
451708Sstevel #include <sys/serengeti.h>
461708Sstevel #include <sys/sgfrutypes.h>
471708Sstevel 
481708Sstevel #include <pdevinfo.h>
491708Sstevel #include <display.h>
501708Sstevel #include <pdevinfo_sun4u.h>
511708Sstevel #include <display_sun4u.h>
521708Sstevel #include <libprtdiag.h>
531708Sstevel 
541708Sstevel #include <config_admin.h>
551708Sstevel 
561708Sstevel #if !defined(TEXT_DOMAIN)
571708Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
581708Sstevel #endif
591708Sstevel 
601708Sstevel #define	SCHIZO_COMPATIBLE	"pci108e,8001"
611708Sstevel #define	XMITS_COMPATIBLE	"pci108e,8002"
621708Sstevel 
631708Sstevel #define	ACTIVE		0
641708Sstevel #define	INACTIVE	1
651708Sstevel #define	DISPLAY_INFO	40
661708Sstevel 
671708Sstevel #define	EVNT2STR(e)	((e) == CFGA_STAT_NONE ? "none" : \
681708Sstevel 			    (e) == CFGA_STAT_EMPTY ? "empty" : \
691708Sstevel 			    (e) == CFGA_STAT_DISCONNECTED ? "disconnected" : \
701708Sstevel 			    (e) == CFGA_STAT_CONNECTED ? "connected" : \
711708Sstevel 			    (e) == CFGA_STAT_UNCONFIGURED ? "unconfigured" : \
721708Sstevel 			    (e) == CFGA_STAT_CONFIGURED ? "configured" : \
731708Sstevel 			    "unknown")
741708Sstevel 
751708Sstevel #define	COND2STR(c)	((c) == CFGA_COND_UNKNOWN ? "unknown" : \
761708Sstevel 			    (c) == CFGA_COND_OK ? "ok" : \
771708Sstevel 			    (c) == CFGA_COND_FAILING ? "failing" : \
781708Sstevel 			    (c) == CFGA_COND_FAILED ? "failed" : \
791708Sstevel 			    (c) == CFGA_COND_UNUSABLE ? "unusable" : \
801708Sstevel 			    "???")
811708Sstevel 
821708Sstevel #define	SG_CLK_FREQ_TO_MHZ(x)	(((x) + 500000) / 1000000)
831708Sstevel 
841708Sstevel #define	MAX_STATUS_LEN		8
851708Sstevel #define	SG_FAIL			"fail"
861708Sstevel #define	SG_DISABLED		"disabled"
871708Sstevel #define	SG_DEGRADED		"degraded"
881708Sstevel #define	SG_OK			"ok"
891708Sstevel 
901708Sstevel #define	SG_SCHIZO_FAILED	1
911708Sstevel #define	SG_SCHIZO_GOOD		0
921708Sstevel 
931708Sstevel #define	DEFAULT_MAX_FREQ	66	/* 66 MHz */
941708Sstevel #define	PCIX_MAX_FREQ		100	/* 100 MHz */
951708Sstevel 
961708Sstevel #define	CFG_CPU	"::cpu"
971708Sstevel 
981708Sstevel #define	CFG_SET_FRU_NAME_NODE(str, num) \
991708Sstevel { \
1001708Sstevel 	char tmp_str[MAX_FRU_NAME_LEN]; \
1011708Sstevel 	sprintf(tmp_str, "/N%d", num); \
1021708Sstevel 	strncat(str, tmp_str, sizeof (tmp_str)); \
1031708Sstevel }
1041708Sstevel 
1051708Sstevel #define	CFG_SET_FRU_NAME_CPU_BOARD(str, num) \
1061708Sstevel { \
1071708Sstevel 	char tmp_str[MAX_FRU_NAME_LEN]; \
1081708Sstevel 	sprintf(tmp_str, ".%s%d", SG_HPU_TYPE_CPU_BOARD_ID, num); \
1091708Sstevel 	strncat(str, tmp_str, sizeof (tmp_str)); \
1101708Sstevel }
1111708Sstevel 
1121708Sstevel #define	CFG_SET_FRU_NAME_MODULE(str, num) \
1131708Sstevel { \
1141708Sstevel 	char tmp_str[MAX_FRU_NAME_LEN]; \
1151708Sstevel 	sprintf(tmp_str, "%s%d", CFG_CPU, num); \
1161708Sstevel 	strncat(str, tmp_str, sizeof (tmp_str)); \
1171708Sstevel }
1181708Sstevel 
1191708Sstevel extern	int	print_flag;
1201708Sstevel 
1211708Sstevel /*
1221708Sstevel  * these functions will overlay the symbol table of libprtdiag
1231708Sstevel  * at runtime (Serengeti systems only)
1241708Sstevel  */
1251708Sstevel int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
1261708Sstevel void	*get_prop_val(Prop *prop);
1271708Sstevel Prop	*find_prop(Prom_node *pnode, char *name);
1281708Sstevel char	*get_node_name(Prom_node *pnode);
1291708Sstevel char	*get_node_type(Prom_node *pnode);
1301708Sstevel void	add_node(Sys_tree *, Prom_node *);
1311708Sstevel void 	display_pci(Board_node *);
1321708Sstevel void 	display_ffb(Board_node *, int);
1331708Sstevel void	display_io_cards(struct io_card *list);
1341708Sstevel void	display_cpu_devices(Sys_tree *tree);
1351708Sstevel void	display_cpus(Board_node *board);
1361708Sstevel void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
1371708Sstevel 		struct system_kstat_data *kstats);
1381708Sstevel void	display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
1391708Sstevel void	get_failed_parts(void);
1401708Sstevel int	display_failed_parts(Sys_tree *tree);
1411708Sstevel void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
1421708Sstevel void	print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
1431708Sstevel 	    char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
1441708Sstevel 
1451708Sstevel /* Local Functions */
1461708Sstevel static void	serengeti_display_hw_revisions(Prom_node *root,
1471708Sstevel 							Board_node *bnode);
1481708Sstevel static Board_node *serengeti_find_board(Sys_tree *root, int board, int nodeid);
1491708Sstevel static Board_node *serengeti_insert_board(Sys_tree *root, int board, int nid);
1501708Sstevel static int	display_schizo_revisions(Board_node *bdlist, int mode);
1511708Sstevel static void	display_sgsbbc_revisions(Board_node *bdlist);
1521708Sstevel static void	serengeti_display_board_info(int state);
1531708Sstevel static void	serengeti_display_board_info_header(int state);
1541708Sstevel static boolean_t cpu_node_configured(char *const node);
1551708Sstevel static void display_io_max_bus_speed(struct io_card *p);
1561708Sstevel static void display_io_slot_info(struct io_card *p);
1571708Sstevel static void get_slot_name(struct io_card *card, char *slot_name);
1581708Sstevel 
1591708Sstevel /* The bus max freq is determined based on board level in use */
1601708Sstevel int	board_bus_max_freq = DEFAULT_MAX_FREQ;	/* 66MHz default */
1611708Sstevel 
1621708Sstevel /*
1631708Sstevel  * Serengeti now uses both the devinfo tree and the OBP tree for it's
1641708Sstevel  * prtdiag. The devinfo tree is used for getting the HW config of the
1651708Sstevel  * system and the OBP device tree is used for listing the failed HW
1661708Sstevel  * in the system. This is because devinfo currently does not include
1671708Sstevel  * any PROM nodes with a status of 'fail' so we need to go to OBP to
1681708Sstevel  * get a list of failed HW. We use the tree flag to allow the same code
1691708Sstevel  * to walk both trees.
1701708Sstevel  *
1711708Sstevel  * We really need to look at having a single tree for all platforms!
1721708Sstevel  */
1731708Sstevel #define	DEVINFO_TREE	1
1741708Sstevel #define	OBP_TREE	2
1751708Sstevel 
1761708Sstevel static int	tree = DEVINFO_TREE;
1771708Sstevel 
1781708Sstevel #ifdef DEBUG
1791708Sstevel #define	D_PRINTFINDENT	printfindent
1801708Sstevel void
printfindent(int indent,char * fmt,...)1811708Sstevel printfindent(int indent, char *fmt, ...)
1821708Sstevel {
1831708Sstevel 	va_list ap;
1841708Sstevel 	int i = 0;
1851708Sstevel 	for (i = 0; i < indent; i ++)
1861708Sstevel 		printf("\t");
1871708Sstevel 
1881708Sstevel 	va_start(ap);
1891708Sstevel 	(void) vprintf(fmt, ap);
1901708Sstevel 	va_end(ap);
1911708Sstevel }
1921708Sstevel #else
1931708Sstevel #define	D_PRINTFINDENT
1941708Sstevel #endif
1951708Sstevel 
1961708Sstevel /*
1971708Sstevel  * display_pci
1981708Sstevel  * Display all the PCI IO cards on this board.
1991708Sstevel  */
2001708Sstevel void
display_pci(Board_node * board)2011708Sstevel display_pci(Board_node *board)
2021708Sstevel {
2031708Sstevel 	struct io_card *card_list = NULL;
2041708Sstevel 	struct io_card card;
2051708Sstevel 	void *value;
2061708Sstevel 	Prom_node *pci;
2071708Sstevel 	Prom_node *card_node;
2081708Sstevel 	Prom_node *pci_bridge_node;
2091708Sstevel 	Prom_node *child_pci_bridge_node;
2101708Sstevel 	char	*slot_name = NULL;	/* info in "slot-names" prop */
2111708Sstevel 	char	*child_name;
2121708Sstevel 	char	*name, *type;
2131708Sstevel 	char	*pname, *ptype;
2141708Sstevel 	char	buf[MAXSTRLEN];
2151708Sstevel 	int	*int_val;
2161708Sstevel 	int	pci_bus;
2171708Sstevel 	int	pci_bridge = 0;
2181708Sstevel 	int	pci_bridge_dev_no;
2191708Sstevel 	char	*slot_name_arr[SG_MAX_SLOTS_PER_IO_BD] = {NULL};
2201708Sstevel 	int	i;
2211708Sstevel 	int	portid;
2221708Sstevel 	int	level = 0;
2231708Sstevel 	int	version, *pversion;
2241708Sstevel #ifdef DEBUG
2251708Sstevel 	int	slot_name_bits;
2261708Sstevel #endif
2271708Sstevel 
2281708Sstevel 	if (board == NULL)
2291708Sstevel 		return;
2301708Sstevel 
2311708Sstevel 	/* Initialize all the common information */
2321708Sstevel 	card.display = TRUE;
2331708Sstevel 	card.board = board->board_num;
2341708Sstevel 	card.node_id = board->node_id;
2351708Sstevel 
2361708Sstevel 	/*
2371708Sstevel 	 * Search for each schizo and xmits, then find/display all nodes under
2381708Sstevel 	 * each schizo and xmits node found.
2391708Sstevel 	 */
2401708Sstevel 	for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
241*5889Szk194757 	    pci != NULL;
242*5889Szk194757 	    pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
2431708Sstevel 
2441708Sstevel 		/* set max freq for this board */
2451708Sstevel 		board_bus_max_freq = DEFAULT_MAX_FREQ;
2461708Sstevel 		/*
2471708Sstevel 		 * Find out if this is a PCI or cPCI IO Board.
2481708Sstevel 		 * If "enum-impl" property exists in pci node => cPCI.
2491708Sstevel 		 */
2501708Sstevel 		value = get_prop_val(find_prop(pci, "enum-impl"));
2511708Sstevel 		if (value == NULL) {
2521708Sstevel 			(void) sprintf(card.bus_type, "PCI");
2531708Sstevel 		} else {
2541708Sstevel 			(void) sprintf(card.bus_type, "cPCI");
2551708Sstevel 		}
2561708Sstevel 
2571708Sstevel 		if (strstr((char *)get_prop_val(
2581708Sstevel 		    find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
2591708Sstevel 			sprintf(card.notes, "%s", XMITS_COMPATIBLE);
2601708Sstevel 			/*
2611708Sstevel 			 * With XMITS 3.X and PCI-X mode, the bus speed
2621708Sstevel 			 * can be higher than 66MHZ.
2631708Sstevel 			 */
2641708Sstevel 			value = (int *)get_prop_val
265*5889Szk194757 			    (find_prop(pci, "module-revision#"));
2661708Sstevel 			if (value) {
2671708Sstevel 				pversion = (int *)value;
2681708Sstevel 				version = *pversion;
2691708Sstevel 				if (version >= 4)
2701708Sstevel 					board_bus_max_freq = PCIX_MAX_FREQ;
2711708Sstevel 			}
2721708Sstevel 		} else if (strstr((char *)get_prop_val(
2731708Sstevel 		    find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
2741708Sstevel 			sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
2751708Sstevel 		else
2761708Sstevel 			sprintf(card.notes, " ");
2771708Sstevel 
2781708Sstevel 		/*
2791708Sstevel 		 * Get slot-name properties from parent node and
2801708Sstevel 		 * store them in an array.
2811708Sstevel 		 */
2821708Sstevel 		value = (char *)get_prop_val(find_prop(pci, "slot-names"));
2831708Sstevel 		if (value != NULL) {
2841708Sstevel #ifdef DEBUG
2851708Sstevel 			/* save the 4 byte bitmask */
2861708Sstevel 			slot_name_bits = *(int *)value;
2871708Sstevel #endif
2881708Sstevel 			/* array starts after first int */
2891708Sstevel 			slot_name_arr[0] = (char *)value + sizeof (int);
2901708Sstevel 
2911708Sstevel 			D_PRINTFINDENT(0, "slot_name_arr[0] is [%s]\n",
2921708Sstevel 			    slot_name_arr[0]);
2931708Sstevel 
2941708Sstevel 			for (i = 1; i < SG_MAX_SLOTS_PER_IO_BD; i++) {
2951708Sstevel 				slot_name_arr[i] = (char *)slot_name_arr[i - 1]
296*5889Szk194757 				    + strlen(slot_name_arr[i - 1]) +1;
2971708Sstevel 
2981708Sstevel 			D_PRINTFINDENT(0, "slot_name_arr[%d] is [%s]\n", i,
2991708Sstevel 			    slot_name_arr[i]);
3001708Sstevel 
3011708Sstevel 			}
3021708Sstevel 		}
3031708Sstevel 
3041708Sstevel 		/*
3051708Sstevel 		 * Search for Children of this node ie. Cards.
3061708Sstevel 		 * Note: any of these cards can be a pci-bridge
3071708Sstevel 		 *	that itself has children. If we find a
3081708Sstevel 		 *	pci-bridge we need to handle it specially.
3091708Sstevel 		 *
3101708Sstevel 		 *	There can now be the condition of a pci-bridge
3111708Sstevel 		 *	being the child of a pci-bridge which create a
3121708Sstevel 		 *	two levels of pci-bridges.  This special condition
3131708Sstevel 		 *	needs to be handled as well.  The variable level
3141708Sstevel 		 *	is used to track the depth of the tree.  This
3151708Sstevel 		 *	variable is then used to find instances of this case.
3161708Sstevel 		 */
3171708Sstevel 		level = 0;
3181708Sstevel 		card_node = pci->child;
3191708Sstevel 		while (card_node != NULL) {
3201708Sstevel 			pci_bridge = 0;
3211708Sstevel 
3221708Sstevel 			/* If it doesn't have a name, skip it */
3231708Sstevel 			name = (char *)get_prop_val(
324*5889Szk194757 			    find_prop(card_node, "name"));
3251708Sstevel 			if (name == NULL) {
3261708Sstevel 				card_node = card_node->sibling;
3271708Sstevel 				continue;
3281708Sstevel 			}
3291708Sstevel 			D_PRINTFINDENT(level, "NAME is %s\n", name);
3301708Sstevel 
3311708Sstevel 			type = (char *)get_prop_val(
332*5889Szk194757 			    find_prop(card_node, "device_type"));
3331708Sstevel 
3341708Sstevel 			/*
3351708Sstevel 			 * get dev# and func# for this card from the
3361708Sstevel 			 * 'reg' property.
3371708Sstevel 			 */
3381708Sstevel 			int_val = (int *)get_prop_val(
339*5889Szk194757 			    find_prop(card_node, "reg"));
3401708Sstevel 			if (int_val != NULL) {
3411708Sstevel 				card.dev_no = (((*int_val) & 0xF800) >> 11);
3421708Sstevel 				card.func_no = (((*int_val) & 0x700) >> 8);
3431708Sstevel 			} else {
3441708Sstevel 				card.dev_no = -1;
3451708Sstevel 				card.func_no = -1;
3461708Sstevel 			}
3471708Sstevel 
3481708Sstevel 			/*
3491708Sstevel 			 * If this is a pci-bridge, then store it's dev#
3501708Sstevel 			 * as it's children nodes need this to get their slot#.
3511708Sstevel 			 * We set the pci_bridge flag so that we know we are
3521708Sstevel 			 * looking at a pci-bridge node. This flag gets reset
3531708Sstevel 			 * every time we enter this while loop.
3541708Sstevel 			 */
3551708Sstevel 
3561708Sstevel 			/*
3571708Sstevel 			 * Check for a PCI-PCI Bridge for PCI and cPCI
3581708Sstevel 			 * IO Boards using the name and type properties.
3591708Sstevel 			 *
3601708Sstevel 			 * If level is greater then 0, then check the parent
3611708Sstevel 			 * node to see if it was also a pci-bridge.  We do not
3621708Sstevel 			 * this when level is 0 as this will see the schizo or
3631708Sstevel 			 * xmits device as a pci-bridge node.  This will mess
3641708Sstevel 			 * up the slot number of child nodes.
3651708Sstevel 			 */
3661708Sstevel 			if ((type != NULL) &&
367*5889Szk194757 			    (strncmp(name, "pci", 3) == 0) &&
368*5889Szk194757 			    (strcmp(type, "pci") == 0)) {
3691708Sstevel 				if (level > 0) {
370*5889Szk194757 					pname = (char *)get_prop_val(
371*5889Szk194757 					    find_prop(card_node->parent,
372*5889Szk194757 					    "name"));
373*5889Szk194757 					ptype = (char *)get_prop_val(
374*5889Szk194757 					    find_prop(card_node->parent,
3751708Sstevel 					    "device_type"));
3761708Sstevel 
377*5889Szk194757 					if ((ptype != NULL) &&
378*5889Szk194757 					    (pname != NULL) &&
379*5889Szk194757 					    (strncmp(pname, "pci", 3) == 0) &&
380*5889Szk194757 					    (strcmp(ptype, "pci") == 0)) {
381*5889Szk194757 						child_pci_bridge_node =
382*5889Szk194757 						    card_node;
383*5889Szk194757 					} else {
384*5889Szk194757 						pci_bridge_dev_no = card.dev_no;
385*5889Szk194757 						pci_bridge_node = card_node;
386*5889Szk194757 					}
3871708Sstevel 				} else {
3881708Sstevel 					pci_bridge_dev_no = card.dev_no;
3891708Sstevel 					pci_bridge_node = card_node;
3901708Sstevel 				}
3911708Sstevel 				pci_bridge = TRUE;
3921708Sstevel 
3931708Sstevel 				D_PRINTFINDENT(level,
3941708Sstevel 				    "pci_bridge_dev_no is [%d]\n",
3951708Sstevel 				    pci_bridge_dev_no);
3961708Sstevel 			}
3971708Sstevel 
3981708Sstevel 			/*
3991708Sstevel 			 * Get slot-names property from slot_names_arr.
4001708Sstevel 			 * If we are the child of a pci_bridge we use the
4011708Sstevel 			 * dev# of the pci_bridge as an index to get
4021708Sstevel 			 * the slot number. We know that we are a child of
4031708Sstevel 			 * a pci-bridge if our parent is the same as the last
4041708Sstevel 			 * pci_bridge node found above.
4051708Sstevel 			 */
4061708Sstevel 			if (type)
4071708Sstevel 				D_PRINTFINDENT(level,
4081708Sstevel 				    "*** name is [%s] - type is [%s]\n",
4091708Sstevel 				    name, type);
4101708Sstevel 			else
4111708Sstevel 				D_PRINTFINDENT(level,
4121708Sstevel 				    "*** name is [%s]\n", name);
4131708Sstevel 
4141708Sstevel 			if (card.dev_no != -1) {
4151708Sstevel 				/*
4161708Sstevel 				 * We compare this cards parent node with the
4171708Sstevel 				 * pci_bridge_node to see if it's a child.
4181708Sstevel 				 */
4191708Sstevel 				if (((level > 0) &&
4201708Sstevel 				    (card_node->parent->parent ==
4211708Sstevel 				    pci_bridge_node)) ||
4221708Sstevel 				    (card_node->parent == pci_bridge_node)) {
4231708Sstevel 					/* use dev_no of pci_bridge */
4241708Sstevel 					D_PRINTFINDENT(level,
4251708Sstevel 					    "   pci_bridge_dev_no is [%d]\n",
4261708Sstevel 					    pci_bridge_dev_no);
4271708Sstevel 
4281708Sstevel 					slot_name =
4291708Sstevel 					    slot_name_arr[pci_bridge_dev_no -1];
4301708Sstevel 				} else {
4311708Sstevel 					/* use cards own dev_no */
4321708Sstevel 					D_PRINTFINDENT(level,
4331708Sstevel 					    "    card.dev_no is [%d]\n",
4341708Sstevel 					    card.dev_no);
4351708Sstevel 
4361708Sstevel 					slot_name =
4371708Sstevel 					    slot_name_arr[card.dev_no - 1];
4381708Sstevel 				}
4391708Sstevel 
4401708Sstevel 				get_slot_name(&card, slot_name);
4411708Sstevel 
4421708Sstevel 			} else {
4431708Sstevel 				(void) sprintf(card.slot_str, "%c", '-');
4441708Sstevel 			}
4451708Sstevel 
4461708Sstevel 			/*
4471708Sstevel 			 * Get the portid of the schizo and xmits that this card
4481708Sstevel 			 * lives under.
4491708Sstevel 			 */
4501708Sstevel 			portid = -1;
4511708Sstevel 			value = get_prop_val(find_prop(pci, "portid"));
4521708Sstevel 			if (value != NULL) {
4531708Sstevel 				portid = *(int *)value;
4541708Sstevel 			}
4551708Sstevel 			card.schizo_portid = portid;
4561708Sstevel 
4571708Sstevel #ifdef DEBUG
4581708Sstevel 			(void) sprintf(card.notes, "%s portid [%d] dev_no[%d]"
459*5889Szk194757 			    " slot_name[%s] name_bits[%d]",
460*5889Szk194757 			    card.notes,
461*5889Szk194757 			    portid,
462*5889Szk194757 			    card.dev_no, slot_name,
463*5889Szk194757 			    slot_name_bits);
4641708Sstevel #endif
4651708Sstevel 
4661708Sstevel 			/*
4671708Sstevel 			 * Find out whether this is PCI bus A or B
4681708Sstevel 			 * using the 'reg' property.
4691708Sstevel 			 */
4701708Sstevel 			int_val = (int *)get_prop_val
471*5889Szk194757 			    (find_prop(pci, "reg"));
4721708Sstevel 
4731708Sstevel 			if (int_val != NULL) {
4741708Sstevel 				int_val ++; /* skip over first integer */
4751708Sstevel 				pci_bus = ((*int_val) & 0x7f0000);
4761708Sstevel 				if (pci_bus == 0x600000)
4771708Sstevel 					card.pci_bus = 'A';
4781708Sstevel 				else if (pci_bus == 0x700000)
4791708Sstevel 					card.pci_bus = 'B';
4801708Sstevel 				else
4811708Sstevel 					card.pci_bus = '-';
4821708Sstevel 			} else {
4831708Sstevel 				card.pci_bus = '-';
4841708Sstevel 			}
4851708Sstevel 
4861708Sstevel 
4871708Sstevel 			/*
4881708Sstevel 			 * Check for failed status.
4891708Sstevel 			 */
4901708Sstevel 			if (node_status(card_node, SG_FAIL))
4911708Sstevel 				strncpy(card.status, SG_FAIL,
492*5889Szk194757 				    sizeof (SG_FAIL));
4931708Sstevel 			else if (node_status(card_node, SG_DISABLED))
4941708Sstevel 				strncpy(card.status, SG_DISABLED,
495*5889Szk194757 				    sizeof (SG_DISABLED));
4961708Sstevel 			else
4971708Sstevel 				strncpy(card.status, SG_OK,
498*5889Szk194757 				    sizeof (SG_OK));
4991708Sstevel 
5001708Sstevel 			/* Get the model of this card */
5011708Sstevel 			value = get_prop_val(find_prop(card_node, "model"));
5021708Sstevel 			if (value == NULL)
5031708Sstevel 				card.model[0] = '\0';
5041708Sstevel 			else {
5051708Sstevel 				(void) sprintf(card.model, "%s",
506*5889Szk194757 				    (char *)value);
5071708Sstevel 				/* Skip sgsbbc nodes, they are not cards */
5081708Sstevel 				if (strcmp(card.model, "SUNW,sgsbbc") == 0) {
5091708Sstevel 					card_node = card_node->sibling;
5101708Sstevel 					continue;
5111708Sstevel 				}
5121708Sstevel 			}
5131708Sstevel 
5141708Sstevel 			/*
5151708Sstevel 			 * Check if further processing is necessary to display
5161708Sstevel 			 * this card uniquely.
5171708Sstevel 			 */
5181708Sstevel 			distinguish_identical_io_cards(name, card_node, &card);
5191708Sstevel 
5201708Sstevel 			/*
5211708Sstevel 			 * The card may have a "clock-frequency" but we
5221708Sstevel 			 * are not interested in that. Instead we get the
5231708Sstevel 			 * "clock-frequency" of the PCI Bus that the card
5241708Sstevel 			 * resides on. PCI-A can operate at 33Mhz or 66Mhz
5251708Sstevel 			 * depending on what card is plugged into the Bus.
5261708Sstevel 			 * PCI-B always operates at 33Mhz.
5271708Sstevel 			 *
5281708Sstevel 			 */
5291708Sstevel 			int_val = get_prop_val(find_prop(pci,
530*5889Szk194757 			    "clock-frequency"));
5311708Sstevel 			if (int_val != NULL) {
5321708Sstevel 				card.freq = SG_CLK_FREQ_TO_MHZ(*int_val);
5331708Sstevel 			} else {
5341708Sstevel 				card.freq = -1;
5351708Sstevel 			}
5361708Sstevel 
5371708Sstevel 			/*
5381708Sstevel 			 * Figure out how we want to display the name
5391708Sstevel 			 */
5401708Sstevel 			value = get_prop_val(find_prop(card_node,
541*5889Szk194757 			    "compatible"));
5421708Sstevel 			if (value != NULL) {
5431708Sstevel 				/* use 'name'-'compatible' */
5441708Sstevel 				(void) sprintf(buf, "%s-%s", name,
545*5889Szk194757 				    (char *)value);
5461708Sstevel 			} else {
5471708Sstevel 				/* just use 'name' */
5481708Sstevel 				(void) sprintf(buf, "%s", name);
5491708Sstevel 			}
5501708Sstevel 			name = buf;
5511708Sstevel 
5521708Sstevel 			/*
5531708Sstevel 			 * If this node has children, add the device_type
5541708Sstevel 			 * of the child to the name value of this card.
5551708Sstevel 			 */
5561708Sstevel 			child_name = (char *)get_node_name(card_node->child);
5571708Sstevel 			if ((card_node->child != NULL) &&
558*5889Szk194757 			    (child_name != NULL)) {
5591708Sstevel 				value = get_prop_val(find_prop(card_node->child,
560*5889Szk194757 				    "device_type"));
5611708Sstevel 				if (value != NULL) {
5621708Sstevel 					/* add device_type of child to name */
5631708Sstevel 					(void) sprintf(card.name, "%s/%s (%s)",
564*5889Szk194757 					    name, child_name,
565*5889Szk194757 					    (char *)value);
5661708Sstevel 				} else {
5671708Sstevel 					/* just add childs name */
5681708Sstevel 					(void) sprintf(card.name, "%s/%s", name,
569*5889Szk194757 					    child_name);
5701708Sstevel 				}
5711708Sstevel 			} else {
5721708Sstevel 				(void) sprintf(card.name, "%s", (char *)name);
5731708Sstevel 			}
5741708Sstevel 
5751708Sstevel 			/*
5761708Sstevel 			 * If this is a pci-bridge, then add the word
5771708Sstevel 			 * 'pci-bridge' to it's model.
5781708Sstevel 			 */
5791708Sstevel 			if (pci_bridge) {
5801708Sstevel 				if (strlen(card.model) == 0)
5811708Sstevel 					(void) sprintf(card.model,
582*5889Szk194757 					    "%s", "pci-bridge");
5831708Sstevel 				else
5841708Sstevel 					(void) sprintf(card.model,
5851708Sstevel 					    "%s/pci-bridge", card.model);
5861708Sstevel 			}
5871708Sstevel 
5881708Sstevel 			/* insert this card in the list to be displayed later */
5891708Sstevel 			card_list = insert_io_card(card_list, &card);
5901708Sstevel 
5911708Sstevel 			/*
5921708Sstevel 			 * If we are dealing with a pci-bridge, we need to move
5931708Sstevel 			 * down to the children of this bridge if there are any.
5941708Sstevel 			 *
5951708Sstevel 			 * If we are not, we are either dealing with a regular
5961708Sstevel 			 * card (in which case we move onto the sibling of this
5971708Sstevel 			 * card) or we are dealing with a child of a pci-bridge
5981708Sstevel 			 * (in which case we move onto the child's siblings or
5991708Sstevel 			 * if there are no more siblings for this child, we
6001708Sstevel 			 * move onto the parents siblings).
6011708Sstevel 			 *
6021708Sstevel 			 * Once we reach the last child node of a pci-bridge,
6031708Sstevel 			 * we need to back up the tree to the parents sibling
6041708Sstevel 			 * node.  If our parent has no more siblings, we need
6051708Sstevel 			 * to check our grand parent for siblings.
6061708Sstevel 			 *
6071708Sstevel 			 * If we have no more siblings, we simply point to
6081708Sstevel 			 * to the child's sibling which moves us onto the next
6091708Sstevel 			 * bus leaf.
6101708Sstevel 			 *
6111708Sstevel 			 * The variable level gets adjusted on some of the
6121708Sstevel 			 * conditions as this is used to track level within
6131708Sstevel 			 * the tree we have reached.
6141708Sstevel 			 */
6151708Sstevel 			if (pci_bridge) {
6161708Sstevel 				if (card_node->child != NULL) {
6171708Sstevel 					level++;
6181708Sstevel 					card_node = card_node->child;
6191708Sstevel 				} else
6201708Sstevel 					card_node = card_node->sibling;
6211708Sstevel 			} else {
622*5889Szk194757 				if ((card_node->parent == pci_bridge_node) &&
623*5889Szk194757 				    (card_node->sibling == NULL)) {
624*5889Szk194757 					card_node = pci_bridge_node->sibling;
6251708Sstevel 					if (level > 0)
626*5889Szk194757 						level--;
627*5889Szk194757 				} else if ((card_node->parent ==
628*5889Szk194757 				    child_pci_bridge_node) &&
629*5889Szk194757 				    (card_node->parent->parent ==
630*5889Szk194757 				    pci_bridge_node)) {
631*5889Szk194757 					if ((child_pci_bridge_node->sibling) &&
632*5889Szk194757 					    (card_node->sibling == NULL)) {
633*5889Szk194757 						card_node =
634*5889Szk194757 						    child_pci_bridge_node-> \
635*5889Szk194757 						    sibling;
636*5889Szk194757 					if (level > 0)
6371708Sstevel 						level--;
638*5889Szk194757 					} else if ((pci_bridge_node->sibling) &&
639*5889Szk194757 					    (card_node->sibling == NULL)) {
640*5889Szk194757 						card_node =
641*5889Szk194757 						    pci_bridge_node->sibling;
642*5889Szk194757 						if (level > 1)
643*5889Szk194757 							level = level - 2;
644*5889Szk194757 						else if (level > 0)
645*5889Szk194757 							level--;
646*5889Szk194757 					} else
647*5889Szk194757 						card_node = card_node->sibling;
648*5889Szk194757 				} else
649*5889Szk194757 					card_node = card_node->sibling;
6501708Sstevel 			}
6511708Sstevel 		} /* end-while */
6521708Sstevel 	} /* end-for */
6531708Sstevel 
6541708Sstevel 	display_io_cards(card_list);
6551708Sstevel 	free_io_cards(card_list);
6561708Sstevel }
6571708Sstevel 
6581708Sstevel /*
6591708Sstevel  * display_ffb
6601708Sstevel  *
6611708Sstevel  * There are no FFB's on a Serengeti, however in the generic library,
6621708Sstevel  * the display_ffb() function is implemented so we have to define an
6631708Sstevel  * empty function here.
6641708Sstevel  */
6651708Sstevel /*ARGSUSED0*/
6661708Sstevel void
display_ffb(Board_node * board,int table)6671708Sstevel display_ffb(Board_node *board, int table)
6681708Sstevel {}
6691708Sstevel 
6701708Sstevel static void
serengeti_display_board_info_header(int state)6711708Sstevel serengeti_display_board_info_header(int state)
6721708Sstevel {
6731708Sstevel 	char *fmt = "%-9s  %-11s  %-12s  %-12s  %-9s %-40s\n";
6741708Sstevel 
6751708Sstevel 	log_printf("\n", 0);
6761708Sstevel 	log_printf("=========================", 0);
6771708Sstevel 	if (state == ACTIVE)
6781708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
679*5889Szk194757 		    " Active Boards for Domain "), 0);
6801708Sstevel 	else
6811708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
682*5889Szk194757 		    " Available Boards/Slots for Domain "), 0);
6831708Sstevel 	log_printf("===========================", 0);
6841708Sstevel 	log_printf("\n", 0);
6851708Sstevel 	log_printf("\n", 0);
6861708Sstevel 
6871708Sstevel 	log_printf(fmt, "", "Board", "Receptacle", "Occupant", "", "", 0);
6881708Sstevel 
6891708Sstevel 	log_printf(fmt, "FRU Name", "Type", "Status", "Status",
690*5889Szk194757 	    "Condition", "Info", 0);
6911708Sstevel 
6921708Sstevel 	log_printf(fmt, "---------", "-----------", "-----------",
693*5889Szk194757 	    "------------", "---------",
694*5889Szk194757 	    "----------------------------------------", 0);
6951708Sstevel }
6961708Sstevel 
6971708Sstevel static void
serengeti_display_board_info(int state)6981708Sstevel serengeti_display_board_info(int state)
6991708Sstevel {
7001708Sstevel 	int i, z, ret;
7011708Sstevel 	int nlist = 0;
7021708Sstevel 	int available_board_count = 0;
7031708Sstevel 	struct cfga_list_data *board_cfg = NULL;
7041708Sstevel 	char *err_string = NULL;
7051708Sstevel 	char tmp_id[CFGA_LOG_EXT_LEN + 1];
7061708Sstevel 	char tmp_info[DISPLAY_INFO + 1];
7071708Sstevel 	const char listops[] = "class=sbd";
7081708Sstevel 	struct cfga_list_data dat;
7091708Sstevel 	cfga_flags_t flags = NULL;
7101708Sstevel 
7111708Sstevel 	ret = config_list_ext(0, NULL, &board_cfg, &nlist,
712*5889Szk194757 	    NULL, listops,
713*5889Szk194757 	    &err_string, flags);
7141708Sstevel 
7151708Sstevel 	if (ret == CFGA_OK) {
7161708Sstevel 		serengeti_display_board_info_header(state);
7171708Sstevel 		for (i = 0; i < nlist; i++) {
7181708Sstevel 			dat = board_cfg[i];
7191708Sstevel 
7201708Sstevel 			if ((state != ACTIVE) &&
7211708Sstevel 			    (dat.ap_o_state == CFGA_STAT_CONFIGURED))
7221708Sstevel 				continue;
7231708Sstevel 			else if ((state == ACTIVE) &&
724*5889Szk194757 			    (dat.ap_o_state != CFGA_STAT_CONFIGURED))
7251708Sstevel 				continue;
7261708Sstevel 			if (state == INACTIVE)
7271708Sstevel 				available_board_count++;
7281708Sstevel 
7291708Sstevel 			memcpy(tmp_id, dat.ap_log_id, CFGA_LOG_EXT_LEN);
7301708Sstevel 			tmp_id[CFGA_LOG_EXT_LEN] = '\0';
7311708Sstevel 			for (z = 0; z < strlen(tmp_id); z++) {
7321708Sstevel 				if (tmp_id[z] == '.')
7331708Sstevel 					tmp_id[z] = '/';
7341708Sstevel 			}
7351708Sstevel 			log_printf("/%-8s  ", tmp_id, 0);
7361708Sstevel 			log_printf("%-11s  ", dat.ap_type, 0);
7371708Sstevel 
7381708Sstevel 			log_printf("%-12s  ", EVNT2STR(dat.ap_r_state), 0);
7391708Sstevel 			log_printf("%-12s  ", EVNT2STR(dat.ap_o_state), 0);
7401708Sstevel 			log_printf("%-8s  ", COND2STR(dat.ap_cond), 0);
7411708Sstevel 
7421708Sstevel 			memcpy(tmp_info, dat.ap_info, DISPLAY_INFO);
7431708Sstevel 			tmp_info[DISPLAY_INFO - 1] = '\0';
7441708Sstevel 			if (strlen(tmp_info) >= (DISPLAY_INFO - 1))
7451708Sstevel 				tmp_info[DISPLAY_INFO - 2] = '+';
7461708Sstevel 			log_printf("%-*s\n", (DISPLAY_INFO - 1), tmp_info, 0);
7471708Sstevel 		}
7481708Sstevel 		if ((state == INACTIVE) &&
7491708Sstevel 		    (available_board_count == 0)) {
7501708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
751*5889Szk194757 			    "There are currently no "
752*5889Szk194757 			    "Boards/Slots available "
753*5889Szk194757 			    "to this Domain\n"), 0);
7541708Sstevel 		}
7551708Sstevel 	}
7561708Sstevel 	if (board_cfg)
7571708Sstevel 		free(board_cfg);
7581708Sstevel 	if (err_string)
7591708Sstevel 		free(err_string);
7601708Sstevel }
7611708Sstevel 
7621708Sstevel /*
7631708Sstevel  * add_node
7641708Sstevel  *
7651708Sstevel  * This function adds a board node to the board structure where that
7661708Sstevel  * that node's physical component lives.
7671708Sstevel  */
7681708Sstevel void
add_node(Sys_tree * root,Prom_node * pnode)7691708Sstevel add_node(Sys_tree *root, Prom_node *pnode)
7701708Sstevel {
7711708Sstevel 	int	board	= -1;
7721708Sstevel 	int	portid	= -1;
7731708Sstevel 	int	nodeid	= -1;
7741708Sstevel 
7751708Sstevel 	void		*value	= NULL;
7761708Sstevel 	Board_node	*bnode	= NULL;
7771708Sstevel 	Prom_node	*p	= NULL;
7781708Sstevel 	char		*type;
7791708Sstevel 
7801708Sstevel 	/* Get the board number of this board from the portid prop */
7811708Sstevel 	if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
7821708Sstevel 		if ((type = get_node_type(pnode)) && (strcmp(type, "cpu") == 0))
7831708Sstevel 			value =
7841708Sstevel 			    get_prop_val(find_prop(pnode->parent, "portid"));
7851708Sstevel 	}
7861708Sstevel 	if (value != NULL) {
7871708Sstevel 		portid = *(int *)value;
7881708Sstevel 	}
7891708Sstevel 
7901708Sstevel 	nodeid	= SG_PORTID_TO_NODEID(portid);
7911708Sstevel 	board	= SG_PORTID_TO_BOARD_NUM(portid);
7921708Sstevel 
7931708Sstevel 	/* find the board node with the same board number */
7941708Sstevel 	if ((bnode = serengeti_find_board(root, board, nodeid)) == NULL) {
7951708Sstevel 		bnode = serengeti_insert_board(root, board, nodeid);
7961708Sstevel 	}
7971708Sstevel 
7981708Sstevel 	/* now attach this prom node to the board list */
7991708Sstevel 	/* Insert this node at the end of the list */
8001708Sstevel 	pnode->sibling = NULL;
8011708Sstevel 	if (bnode->nodes == NULL)
8021708Sstevel 		bnode->nodes = pnode;
8031708Sstevel 	else {
8041708Sstevel 		p = bnode->nodes;
8051708Sstevel 		while (p->sibling != NULL)
8061708Sstevel 			p = p->sibling;
8071708Sstevel 		p->sibling = pnode;
8081708Sstevel 	}
8091708Sstevel }
8101708Sstevel 
8111708Sstevel 
8121708Sstevel 
8131708Sstevel /*
8141708Sstevel  * Print out all the io cards in the list.  Also print the column
8151708Sstevel  * headers if told to do so.
8161708Sstevel  */
8171708Sstevel void
display_io_cards(struct io_card * list)8181708Sstevel display_io_cards(struct io_card *list)
8191708Sstevel {
8201708Sstevel 	char	*fmt = "%-10s  %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-34s";
8211708Sstevel 
8221708Sstevel 	static int banner = FALSE; /* Have we printed the column headings? */
8231708Sstevel 	struct io_card *p;
8241708Sstevel 
8251708Sstevel 	if (list == NULL)
8261708Sstevel 		return;
8271708Sstevel 
8281708Sstevel 	if (banner == FALSE) {
8291708Sstevel 		log_printf(fmt, "", "", "", "", "", "Bus", "Max",
830*5889Szk194757 		    "", "", "", 0);
8311708Sstevel 		log_printf("\n", 0);
8321708Sstevel 		log_printf(fmt, "", "IO", "Port", "Bus", "", "Freq", "Bus",
833*5889Szk194757 		    "Dev,", "", "", 0);
8341708Sstevel 		log_printf("\n", 0);
8351708Sstevel 		log_printf(fmt, "FRU Name", "Type", " ID", "Side", "Slot",
836*5889Szk194757 		    "MHz", "Freq", "Func", "State", "Name", 0);
8371708Sstevel #ifdef DEBUG
8381708Sstevel 		log_printf("Model                   Notes\n", 0);
8391708Sstevel #else
8401708Sstevel 		log_printf("Model\n", 0);
8411708Sstevel #endif
8421708Sstevel 
8431708Sstevel 		log_printf(fmt, "----------", "----", "----", "----", "----",
844*5889Szk194757 		    "----", "----", "----", "-----",
845*5889Szk194757 		    "--------------------------------", 0);
8461708Sstevel #ifdef DEBUG
8471708Sstevel 		log_printf("----------------------  ", 0);
8481708Sstevel #endif
8491708Sstevel 		log_printf("----------------------\n", 0);
8501708Sstevel 		banner = TRUE;
8511708Sstevel 	}
8521708Sstevel 
8531708Sstevel 	for (p = list; p != NULL; p = p -> next) {
8541708Sstevel 
8551708Sstevel 		display_io_slot_info(p);
8561708Sstevel 
8571708Sstevel 		display_io_max_bus_speed(p);
8581708Sstevel 
8591708Sstevel 		log_printf("\n", 0);
8601708Sstevel 	}
8611708Sstevel }
8621708Sstevel 
8631708Sstevel static void
display_io_slot_info(struct io_card * p)8641708Sstevel display_io_slot_info(struct io_card *p)
8651708Sstevel {
8661708Sstevel 	char	fru_name[MAX_FRU_NAME_LEN] = "";
8671708Sstevel 
8681708Sstevel 	SG_SET_FRU_NAME_NODE(fru_name, p->node_id);
8691708Sstevel 	SG_SET_FRU_NAME_IO_BOARD(fru_name, p->board);
8701708Sstevel 	SG_SET_FRU_NAME_MODULE(fru_name, p->schizo_portid % 2);
8711708Sstevel 
8721708Sstevel 	log_printf("%-8s  ", fru_name, 0);
8731708Sstevel 	log_printf("%-4s  ", p->bus_type, 0);
8741708Sstevel 	log_printf("%-3d  ", p->schizo_portid, 0);
8751708Sstevel 	log_printf("%c    ", p->pci_bus, 0);
8761708Sstevel 	log_printf("%-1s    ", p->slot_str, 0);
8771708Sstevel 	log_printf("%-3d ", p->freq, 0);
8781708Sstevel }
8791708Sstevel 
8801708Sstevel #define	BUS_SPEED_PRINT(speed)	log_printf(" %d  ", speed, 0)
8811708Sstevel 
8821708Sstevel static void
display_io_max_bus_speed(struct io_card * p)8831708Sstevel display_io_max_bus_speed(struct io_card *p)
8841708Sstevel {
8851708Sstevel 	int speed = board_bus_max_freq;
8861708Sstevel 
8871708Sstevel 	switch (p->pci_bus) {
8881708Sstevel 	case 'A':
8891708Sstevel 		BUS_SPEED_PRINT(speed);
8901708Sstevel 		break;
8911708Sstevel 	case 'B':
8921708Sstevel 		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
8931708Sstevel 			if ((strncmp(p->slot_str, "1", 1) == 0) ||
8941708Sstevel 			    (strncmp(p->slot_str, "0", 1) == 0))
8951708Sstevel 				BUS_SPEED_PRINT(33);
8961708Sstevel 			else
8971708Sstevel 				BUS_SPEED_PRINT(speed);
8981708Sstevel 		} else
8991708Sstevel 			BUS_SPEED_PRINT(33);
9001708Sstevel 		break;
9011708Sstevel 	default:
9021708Sstevel 		log_printf("  -	 ", 0);
9031708Sstevel 		break;
9041708Sstevel 	}
9051708Sstevel 
9061708Sstevel 	log_printf("%-1d,%-1d  ", p->dev_no, p->func_no, 0);
9071708Sstevel 	log_printf("%-5s ", p->status, 0);
9081708Sstevel 
9091708Sstevel 	log_printf("%-32.32s%c ", p->name,
910*5889Szk194757 	    ((strlen(p->name) > 32) ? '+' : ' '), 0);
9111708Sstevel 	log_printf("%-22.22s%c", p->model,
912*5889Szk194757 	    ((strlen(p->model) > 22) ? '+' : ' '), 0);
9131708Sstevel #ifdef	DEBUG
9141708Sstevel 	log_printf(" %s", p->notes, 0);
9151708Sstevel #endif	/* DEBUG */
9161708Sstevel }
9171708Sstevel 
9181708Sstevel void
display_cpu_devices(Sys_tree * tree)9191708Sstevel display_cpu_devices(Sys_tree *tree)
9201708Sstevel {
9211708Sstevel 	Board_node *bnode;
9221708Sstevel 
9231708Sstevel 	/* printf formats */
9241708Sstevel 	char	*fmt1 = "%-10s  %-7s  %-4s  %-4s  %-7s  %-4s\n";
9251708Sstevel 
9261708Sstevel 	/*
9271708Sstevel 	 * Display the table header for CPUs . Then display the CPU
9281708Sstevel 	 * frequency, cache size, and processor revision of all cpus.
9291708Sstevel 	 */
9301708Sstevel 	log_printf("\n", 0);
9311708Sstevel 	log_printf("=========================", 0);
9321708Sstevel 	log_printf(" CPUs ", 0);
9331708Sstevel 	log_printf("=========================", 0);
9341708Sstevel 	log_printf("======================", 0);
9351708Sstevel 	log_printf("\n", 0);
9361708Sstevel 	log_printf("\n", 0);
9371708Sstevel 
9381708Sstevel 	log_printf(fmt1, "", "CPU ", "Run", " E$", "CPU", "CPU", 0);
9391708Sstevel 
9401708Sstevel 	log_printf(fmt1, "FRU Name", "ID ", "MHz", " MB",
941*5889Szk194757 	    "Impl.", "Mask", 0);
9421708Sstevel 
9431708Sstevel 	log_printf(fmt1, "----------", "-------", "----", "----",
944*5889Szk194757 	    "-------",  "----", 0);
9451708Sstevel 
9461708Sstevel 	/* Now display all of the cpus on each board */
9471708Sstevel 	bnode = tree->bd_list;
9481708Sstevel 	while (bnode != NULL) {
9491708Sstevel 		display_cpus(bnode);
9501708Sstevel 		bnode = bnode->next;
9511708Sstevel 	}
9521708Sstevel 
9531708Sstevel 	log_printf("\n", 0);
9541708Sstevel }
9551708Sstevel 
9561708Sstevel static boolean_t
cpu_node_configured(char * const node)9571708Sstevel cpu_node_configured(char *const node)
9581708Sstevel {
9591708Sstevel 	int ret, i;
9601708Sstevel 	int nlist = 0;
9611708Sstevel 	boolean_t rv;
9621708Sstevel 	char *err_string = NULL;
9631708Sstevel 	char *const *ap_args = NULL;
9641708Sstevel 	struct cfga_list_data *statlist = NULL;
9651708Sstevel 	struct cfga_list_data dat;
9661708Sstevel 	cfga_flags_t flags = CFGA_FLAG_LIST_ALL;
9671708Sstevel 
9681708Sstevel 	if (node == NULL)
9691708Sstevel 		return (FALSE);
9701708Sstevel 
9711708Sstevel 	ap_args = &node;
9721708Sstevel 	ret = config_list_ext(1, &node, &statlist, &nlist,
973*5889Szk194757 	    NULL, NULL, &err_string, flags);
9741708Sstevel 
9751708Sstevel 	if (ret == CFGA_OK) {
9761708Sstevel 		dat = statlist[0];
9771708Sstevel 
9781708Sstevel 		if (dat.ap_o_state == CFGA_STAT_CONFIGURED)
9791708Sstevel 			rv = TRUE;
9801708Sstevel 		else
9811708Sstevel 			rv = FALSE;
9821708Sstevel 	} else {
9831708Sstevel 		rv = FALSE;
9841708Sstevel 	}
9851708Sstevel 	if (statlist)
9861708Sstevel 		free(statlist);
9871708Sstevel 	if (err_string)
9881708Sstevel 		free(err_string);
9891708Sstevel 	return (rv);
9901708Sstevel }
9911708Sstevel 
9921708Sstevel /*
9931708Sstevel  * Display the CPUs present on this board.
9941708Sstevel  */
9951708Sstevel void
display_cpus(Board_node * board)9961708Sstevel display_cpus(Board_node *board)
9971708Sstevel {
9981708Sstevel 	Prom_node *cpu;
999*5889Szk194757 	uint_t freq;	 /* CPU clock frequency */
10001708Sstevel 	int ecache_size; /* External cache size */
10011708Sstevel 	int board_num = board->board_num;
10021708Sstevel 	int *mid;
10031708Sstevel 	int *impl;
10041708Sstevel 	int *mask;
10051708Sstevel 	int decoded_mask;
10061708Sstevel 	int *coreid;
10071708Sstevel 	int mid_prev = -1;
10081708Sstevel 	int ecache_size_prev = 0;
10091708Sstevel 	char fru_prev[MAX_FRU_NAME_LEN] = "";
10101708Sstevel 
10111708Sstevel 	/*
10121708Sstevel 	 * display the CPUs' operating frequency, cache size, impl. field
10131708Sstevel 	 * and mask revision.
10141708Sstevel 	 */
10151708Sstevel 	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
10161708Sstevel 	    cpu = dev_next_type(cpu, "cpu")) {
10171708Sstevel 		char	fru_name[MAX_FRU_NAME_LEN] = "";
10181708Sstevel 		char	cfg_fru_name[MAX_FRU_NAME_LEN] = "";
10191708Sstevel 
10201708Sstevel 		mid = (int *)get_prop_val(find_prop(cpu, "portid"));
10211708Sstevel 		if (mid == NULL)
10221708Sstevel 			mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
10231708Sstevel 		freq = SG_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
10241708Sstevel 		ecache_size = get_ecache_size(cpu);
10251708Sstevel 		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
10261708Sstevel 		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
10271708Sstevel 
10281708Sstevel 		/* Do not display a failed CPU node */
10291708Sstevel 		if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
10301708Sstevel 			continue;
10311708Sstevel 
10321708Sstevel 		/* FRU Name */
10331708Sstevel 		SG_SET_FRU_NAME_NODE(fru_name, board->node_id);
10341708Sstevel 
10351708Sstevel 		SG_SET_FRU_NAME_CPU_BOARD(fru_name, board_num);
10361708Sstevel 		SG_SET_FRU_NAME_MODULE(fru_name, *mid % 4);
10371708Sstevel 
10381708Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
10391708Sstevel 			coreid = (int *)get_prop_val(find_prop(cpu,
10401708Sstevel 			    "reg"));
10411708Sstevel 			if (coreid == NULL) {
10421708Sstevel 				continue;
10431708Sstevel 			}
10441708Sstevel 
10451708Sstevel 			/*
10461708Sstevel 			 * The assumption is made that 2 cores will always be
10471708Sstevel 			 * listed together in the device tree. If either core
10481708Sstevel 			 * is "bad" then the FRU will not be listed.
10491708Sstevel 			 *
10501708Sstevel 			 * As display_cpus on Serengeti does actually process
10511708Sstevel 			 * all cpu's per board a copy of the fru_name needs to
10521708Sstevel 			 * be made as the following core may not be its
10531708Sstevel 			 * sibling. If this is the case it is assumed that a
10541708Sstevel 			 * sibling core has failed, so the fru should not be
10551708Sstevel 			 * displayed.
10561708Sstevel 			 *
10571708Sstevel 			 * For the first instance of a core, fru_prev is
10581708Sstevel 			 * expected to be empty.  The current values are then
10591708Sstevel 			 * stored and the next board->nodes is processed. If
10601708Sstevel 			 * this is a sibling core, the ecache size it tallied
10611708Sstevel 			 * and the  previous value reset and processing
10621708Sstevel 			 * continues.
10631708Sstevel 			 *
10641708Sstevel 			 * If the following core is not a sibling, the new
10651708Sstevel 			 * values are stored and the next board->nodes is
10661708Sstevel 			 * processed.
10671708Sstevel 			 */
10681708Sstevel 			if (strncmp(fru_prev, "", sizeof (fru_prev)) == 0) {
10691708Sstevel 				strncpy(fru_prev, fru_name, sizeof (fru_name));
10701708Sstevel 				mid_prev = *mid;
10711708Sstevel 				ecache_size_prev = ecache_size;
10721708Sstevel 				continue;
10731708Sstevel 			} else {
10741708Sstevel 				if (strncmp(fru_name, fru_prev,
10751708Sstevel 				    sizeof (fru_prev)) == 0) {
10761708Sstevel 					/*
10771708Sstevel 					 * Jaguar has a split E$, so the size
10781708Sstevel 					 * for both cores must be added together
10791708Sstevel 					 * to get the total size for the entire
10801708Sstevel 					 * chip.
10811708Sstevel 					 *
10821708Sstevel 					 * Panther E$ (L3) is logically shared,
10831708Sstevel 					 * so the total size is equal to the
10841708Sstevel 					 * core size.
10851708Sstevel 					 */
10861708Sstevel 					if (IS_JAGUAR(*impl)) {
10871708Sstevel 						ecache_size += ecache_size_prev;
10881708Sstevel 					}
10891708Sstevel 
10901708Sstevel 					ecache_size_prev = 0;
10911708Sstevel 					strncpy(fru_prev, "",
10921708Sstevel 					    sizeof (fru_prev));
10931708Sstevel 				} else {
10941708Sstevel 					mid_prev = *mid;
10951708Sstevel 					ecache_size_prev = ecache_size;
10961708Sstevel 					strncpy(fru_prev, fru_name,
10971708Sstevel 					    sizeof (fru_name));
10981708Sstevel 					continue;
10991708Sstevel 				}
11001708Sstevel 			}
11011708Sstevel 		}
11021708Sstevel 
11031708Sstevel 		/*
11041708Sstevel 		 * If cpu is not configured, do not display it
11051708Sstevel 		 */
11061708Sstevel 		CFG_SET_FRU_NAME_NODE(cfg_fru_name, board->node_id);
11071708Sstevel 		CFG_SET_FRU_NAME_CPU_BOARD(cfg_fru_name, board_num);
11081708Sstevel 		CFG_SET_FRU_NAME_MODULE(cfg_fru_name, *mid % 4);
11091708Sstevel 
11101708Sstevel 		if (!(cpu_node_configured(cfg_fru_name))) {
11111708Sstevel 			continue;
11121708Sstevel 		}
11131708Sstevel 
11141708Sstevel 
11151708Sstevel 		log_printf("%-10s  ", fru_name, 0);
11161708Sstevel 
11171708Sstevel 		/* CPU MID */
11181708Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
11191708Sstevel 			log_printf("%3d,%3d ", mid_prev, *mid, 0);
11201708Sstevel 			mid_prev = -1;
11211708Sstevel 		} else
11221708Sstevel 			log_printf("%3d     ", *mid, 0);
11231708Sstevel 
11241708Sstevel 		/* Running frequency */
1125*5889Szk194757 		log_printf(" %4u  ", freq, 0);
11261708Sstevel 
11271708Sstevel 		/* Ecache size */
11281708Sstevel 		if (ecache_size == 0)
11291708Sstevel 			log_printf("%3s  ", "N/A", 0);
11301708Sstevel 		else
11311708Sstevel 			log_printf("%4.1f  ",
1132*5889Szk194757 			    (float)ecache_size / (float)(1<<20),
1133*5889Szk194757 			    0);
11341708Sstevel 
11351708Sstevel 		/* Implementation */
11361708Sstevel 		if (impl == NULL) {
11371708Sstevel 			log_printf("%6s  ", " N/A", 0);
11381708Sstevel 		} else {
11391708Sstevel 			switch (*impl) {
11401708Sstevel 			case CHEETAH_IMPL:
11411708Sstevel 				log_printf("%-7s ", "US-III", 0);
11421708Sstevel 				break;
11431708Sstevel 			case CHEETAH_PLUS_IMPL:
11441708Sstevel 				log_printf("%-7s ", "US-III+", 0);
11451708Sstevel 				break;
11461708Sstevel 			case JAGUAR_IMPL:
11471708Sstevel 				log_printf("%-7s ", "US-IV", 0);
11481708Sstevel 				break;
11491708Sstevel 			case PANTHER_IMPL:
11501708Sstevel 				log_printf("%-7s ", "US-IV+", 0);
11511708Sstevel 				break;
11521708Sstevel 			default:
11531708Sstevel 				log_printf("%-7x ", *impl, 0);
11541708Sstevel 				break;
11551708Sstevel 			}
11561708Sstevel 		}
11571708Sstevel 
11581708Sstevel 		/* CPU Mask */
11591708Sstevel 		if (mask == NULL) {
11601708Sstevel 			log_printf(" %3s   ", "N/A", 0);
11611708Sstevel 		} else {
11621708Sstevel 			if (IS_CHEETAH(*impl))
11631708Sstevel 				decoded_mask = REMAP_CHEETAH_MASK(*mask);
11641708Sstevel 			else
11651708Sstevel 				decoded_mask = *mask;
11661708Sstevel 
11671708Sstevel 			log_printf(" %d.%d   ",
11681708Sstevel 			    (decoded_mask >> 4) & 0xf,
11691708Sstevel 			    decoded_mask & 0xf, 0);
11701708Sstevel 		}
11711708Sstevel 
11721708Sstevel 		log_printf("\n", 0);
11731708Sstevel 	}
11741708Sstevel }
11751708Sstevel 
11761708Sstevel 
11771708Sstevel /*ARGSUSED3*/
11781708Sstevel void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)11791708Sstevel display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
11801708Sstevel 	struct system_kstat_data *kstats)
11811708Sstevel {
11821708Sstevel 	log_printf("\n", 0);
11831708Sstevel 	log_printf("=========================", 0);
11841708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, " Hardware Failures "), 0);
11851708Sstevel 	log_printf("==================================", 0);
11861708Sstevel 	log_printf("\n", 0);
11871708Sstevel 
11881708Sstevel 	/*
11891708Sstevel 	 * Get a list of failed parts (ie. devices with a status of
11901708Sstevel 	 * 'fail') from the OBP device tree and display them.
11911708Sstevel 	 */
11921708Sstevel 	get_failed_parts();
11931708Sstevel 
11941708Sstevel 	/* return unless -v option specified */
11951708Sstevel 	if (!flag) {
11961708Sstevel 		log_printf("\n", 0);
11971708Sstevel 		return;
11981708Sstevel 	}
11991708Sstevel 
12001708Sstevel 	/*
12011708Sstevel 	 * display time of latest powerfail. Not all systems
12021708Sstevel 	 * have this capability. For those that do not, this
12031708Sstevel 	 * is just a no-op.
12041708Sstevel 	 */
12051708Sstevel 	disp_powerfail(root);
12061708Sstevel 
12071708Sstevel 	/* Print the PROM revisions here */
12081708Sstevel 	serengeti_display_hw_revisions(root, tree->bd_list);
12091708Sstevel }
12101708Sstevel 
12111708Sstevel /*
12121708Sstevel  * local functions -  functions that are only needed inside this library
12131708Sstevel  */
12141708Sstevel 
12151708Sstevel static void
serengeti_display_hw_revisions(Prom_node * root,Board_node * bdlist)12161708Sstevel serengeti_display_hw_revisions(Prom_node *root, Board_node *bdlist)
12171708Sstevel {
12181708Sstevel 	Prom_node	*pnode;
12191708Sstevel 	char		*value;
12201708Sstevel 
12211708Sstevel 	/* Print the header */
12221708Sstevel 	log_printf("\n", 0);
12231708Sstevel 	log_printf("=========================", 0);
12241708Sstevel 	log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
12251708Sstevel 	log_printf("=======================================", 0);
12261708Sstevel 	log_printf("\n", 0);
12271708Sstevel 	log_printf("\n", 0);
12281708Sstevel 
12291708Sstevel 	/* Display Prom revision header */
12301708Sstevel 	log_printf("System PROM revisions:\n", 0);
12311708Sstevel 	log_printf("----------------------\n", 0);
12321708Sstevel 
12331708Sstevel 	/*
12341708Sstevel 	 * Display OBP version info
12351708Sstevel 	 */
12361708Sstevel 	pnode = dev_find_node(root, "openprom");
12371708Sstevel 	if (pnode != NULL) {
12381708Sstevel 		value = (char *)get_prop_val(find_prop(pnode, "version"));
12391708Sstevel 		log_printf("%s\n\n", value, 0);
12401708Sstevel 	} else {
12411708Sstevel 		log_printf("OBP ???\n\n", value, 0);
12421708Sstevel 	}
12431708Sstevel 
12441708Sstevel 	/*
12451708Sstevel 	 * Display ASIC revisions
12461708Sstevel 	 */
12471708Sstevel 	log_printf("IO ASIC revisions:\n", 0);
12481708Sstevel 	log_printf("------------------\n", 0);
12491708Sstevel 
12501708Sstevel 	log_printf("                            Port\n", 0);
12511708Sstevel 	log_printf("FRU Name    Model            ID    Status", 0);
12521708Sstevel #ifdef DEBUG
12531708Sstevel 	log_printf("   Version  Notes\n", 0);
12541708Sstevel #else
12551708Sstevel 	log_printf("   Version\n", 0);
12561708Sstevel #endif
12571708Sstevel 	/* ---------FRU Name--Model-----------Port-Status */
12581708Sstevel 	log_printf("----------- --------------- ---- ---------- "
12591708Sstevel #ifdef DEBUG
1260*5889Szk194757 	    "-------  "
12611708Sstevel #endif
1262*5889Szk194757 	    "-------\n", 0);
12631708Sstevel 	/*
12641708Sstevel 	 * Display SCHIZO version info
12651708Sstevel 	 */
12661708Sstevel 	display_schizo_revisions(bdlist, SG_SCHIZO_GOOD);
12671708Sstevel 
12681708Sstevel 	/*
12691708Sstevel 	 * Display sgsbbc version info
12701708Sstevel 	 */
12711708Sstevel 	display_sgsbbc_revisions(bdlist);
12721708Sstevel }
12731708Sstevel 
12741708Sstevel /*
12751708Sstevel  * This function displays Schizo and Xmits revision of boards
12761708Sstevel  */
12771708Sstevel static int
display_schizo_revisions(Board_node * bdlist,int mode)12781708Sstevel display_schizo_revisions(Board_node *bdlist, int mode)
12791708Sstevel {
12801708Sstevel 	Prom_node	*pnode;
12811708Sstevel 	int		*int_val;
12821708Sstevel 	int		portid;
12831708Sstevel 	int		prev_portid = -1;
12841708Sstevel 	char		*model;
12851708Sstevel 	char		*status_a, *status_b;
12861708Sstevel 	char		status[MAX_STATUS_LEN];
12871708Sstevel 	int		version;
12881708Sstevel 	int 		node_id;
12891708Sstevel #ifdef DEBUG
12901708Sstevel 	uint32_t	a_notes, b_notes;
12911708Sstevel #endif
12921708Sstevel 	int		pci_bus;
12931708Sstevel 	/*
12941708Sstevel 	 * rv is used when mode is set to SG_SCHIZO_FAILED.
12951708Sstevel 	 * We need to signal if a failure is found so that
12961708Sstevel 	 * the correct headers/footers can be printed.
12971708Sstevel 	 *
12981708Sstevel 	 * rv = 1 implies a failed/disavled schizo device
12991708Sstevel 	 * rv = 0 implies all other cases
13001708Sstevel 	 */
13011708Sstevel 	int		rv = 0;
13021708Sstevel 	Board_node	*bnode;
13031708Sstevel 	void		*value;
13041708Sstevel 
13051708Sstevel 	bnode = bdlist;
13061708Sstevel 	while (bnode != NULL) {
13071708Sstevel 		/*
13081708Sstevel 		 * search this board node for all Schizos
13091708Sstevel 		 */
13101708Sstevel 		for (pnode = dev_find_node_by_compatible(bnode->nodes,
1311*5889Szk194757 		    SCHIZO_COMPATIBLE); pnode != NULL;
13121708Sstevel 		    pnode = dev_next_node_by_compatible(pnode,
1313*5889Szk194757 		    SCHIZO_COMPATIBLE)) {
13141708Sstevel 
13151708Sstevel 			char	fru_name[MAX_FRU_NAME_LEN] = "";
13161708Sstevel 
13171708Sstevel 			/*
13181708Sstevel 			 * get the reg property to determine
13191708Sstevel 			 * whether we are looking at side A or B
13201708Sstevel 			 */
13211708Sstevel 			int_val = (int *)get_prop_val
1322*5889Szk194757 			    (find_prop(pnode, "reg"));
13231708Sstevel 			if (int_val != NULL) {
13241708Sstevel 				int_val ++; /* second integer in array */
13251708Sstevel 				pci_bus = ((*int_val) & 0x7f0000);
13261708Sstevel 			}
13271708Sstevel 
13281708Sstevel 			/* get portid */
13291708Sstevel 			int_val = (int *)get_prop_val
1330*5889Szk194757 			    (find_prop(pnode, "portid"));
13311708Sstevel 			if (int_val == NULL)
13321708Sstevel 				continue;
13331708Sstevel 
13341708Sstevel 			portid = *int_val;
13351708Sstevel 
13361708Sstevel 			/*
13371708Sstevel 			 * If this is a new portid and it is PCI bus B,
13381708Sstevel 			 * we skip onto the PCI bus A. (PCI-A and PCI-B share
13391708Sstevel 			 * the same portid)
13401708Sstevel 			 */
13411708Sstevel 			if ((portid != prev_portid) && (pci_bus == 0x700000)) {
13421708Sstevel 				prev_portid = portid;
13431708Sstevel 				/* status */
13441708Sstevel 				status_b = (char *)get_prop_val
13451708Sstevel 				    (find_prop(pnode, "status"));
13461708Sstevel #ifdef DEBUG
13471708Sstevel 				b_notes = pci_bus;
13481708Sstevel #endif
13491708Sstevel 				continue; /* skip to the next schizo */
13501708Sstevel 			}
13511708Sstevel 
13521708Sstevel 			/*
13531708Sstevel 			 * This must be side A of the same Schizo.
13541708Sstevel 			 * Gather all its props and display them.
13551708Sstevel 			 */
13561708Sstevel #ifdef DEBUG
13571708Sstevel 			a_notes = pci_bus;
13581708Sstevel #endif
13591708Sstevel 
13601708Sstevel 			prev_portid = portid;
13611708Sstevel 
13621708Sstevel 			/* get the node-id */
13631708Sstevel 			node_id =  SG_PORTID_TO_NODEID(portid);
13641708Sstevel 
13651708Sstevel 			/* model */
13661708Sstevel 			model = (char *)get_prop_val
1367*5889Szk194757 			    (find_prop(pnode, "model"));
13681708Sstevel 
13691708Sstevel 			/* version */
13701708Sstevel 			value = (int *)get_prop_val
1371*5889Szk194757 			    (find_prop(pnode, "module-revision#"));
13721708Sstevel 
13731708Sstevel 			if (value)
13741708Sstevel 				int_val = (int *)value;
13751708Sstevel 			else
13761708Sstevel 				int_val = (int *)get_prop_val
1377*5889Szk194757 				    (find_prop(pnode, "version#"));
13781708Sstevel 			if (int_val != NULL)
13791708Sstevel 				version = *int_val;
13801708Sstevel 			else
13811708Sstevel 				version = -1;
13821708Sstevel 
13831708Sstevel 			/* status */
13841708Sstevel 			status_a = (char *)get_prop_val(find_prop
1385*5889Szk194757 			    (pnode, "status"));
13861708Sstevel 
13871708Sstevel 			/*
13881708Sstevel 			 * Display the data
13891708Sstevel 			 */
13901708Sstevel 			/* FRU Name */
13911708Sstevel 			SG_SET_FRU_NAME_NODE(fru_name, node_id);
13921708Sstevel 			SG_SET_FRU_NAME_IO_BOARD(fru_name,
1393*5889Szk194757 			    SG_IO_BD_PORTID_TO_BD_NUM(portid));
13941708Sstevel 			SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
13951708Sstevel 
13961708Sstevel 			if (mode == SG_SCHIZO_FAILED) {
13971708Sstevel 				if ((status_a != (char *)NULL) &&
13981708Sstevel 				    ((status_b != (char *)NULL))) {
13991708Sstevel 					if ((strcmp
14001708Sstevel 					    (status_a, SG_DISABLED) == 0) &&
14011708Sstevel 					    (strcmp(status_b,
1402*5889Szk194757 					    SG_DISABLED) == 0)) {
14031708Sstevel 						log_printf("\tFRU Type : %s\n ",
1404*5889Szk194757 						    model, 0);
14051708Sstevel 						log_printf("\tLocation : %s\n",
1406*5889Szk194757 						    fru_name, 0);
14071708Sstevel 						log_printf
14081708Sstevel 						    ("\tPROM status: %s\n\n",
14091708Sstevel 						    SG_DISABLED, 0);
14101708Sstevel 						rv = 1;
14111708Sstevel 					}
14121708Sstevel 				}
14131708Sstevel 				continue;
14141708Sstevel 			}
14151708Sstevel 			/*
14161708Sstevel 			 * This section of code is executed when displaying
14171708Sstevel 			 * non-failed schizo devices.  If the mode is set to
14181708Sstevel 			 * SG_SCHIZO_FAILED, then this section of code will
14191708Sstevel 			 * not be executed
14201708Sstevel 			 */
14211708Sstevel 			if ((status_a == (char *)NULL) &&
14221708Sstevel 			    ((status_b == (char *)NULL)))
14231708Sstevel 				sprintf(status, " %s      ", SG_OK);
14241708Sstevel 			else if ((status_a == (char *)NULL) &&
1425*5889Szk194757 			    ((strcmp(status_b, SG_DISABLED) == 0)))
14261708Sstevel 				sprintf(status, " %s", SG_DEGRADED);
14271708Sstevel 			else if ((status_b == (char *)NULL) &&
1428*5889Szk194757 			    ((strcmp(status_a, SG_DISABLED) == 0)))
14291708Sstevel 				sprintf(status, " %s", SG_DEGRADED);
14301708Sstevel 			else
14311708Sstevel 				continue;
14321708Sstevel 
14331708Sstevel 			log_printf("%-12s", fru_name, 0);
14341708Sstevel 
14351708Sstevel 			/* model */
14361708Sstevel 
14371708Sstevel 			if (model != NULL)
14381708Sstevel 				log_printf("%-15s  ", model, 0);
14391708Sstevel 			else
14401708Sstevel 				log_printf("%-15s  ", "unknown", 0);
14411708Sstevel 			/* portid */
14421708Sstevel 			log_printf("%-3d ", portid, 0);
14431708Sstevel 
14441708Sstevel 			/* status */
14451708Sstevel 			log_printf("%s", status, 0);
14461708Sstevel 
14471708Sstevel 			/* version */
14481708Sstevel 			log_printf("     %-4d   ", version, 0);
14491708Sstevel #ifdef DEBUG
14501708Sstevel 			log_printf("0x%x 0x%x", a_notes, b_notes, 0);
14511708Sstevel 			log_printf(" %d", portid, 0);
14521708Sstevel #endif
14531708Sstevel 			log_printf("\n", 0);
14541708Sstevel 		}
14551708Sstevel 		bnode = bnode->next;
14561708Sstevel 	}
14571708Sstevel 	return (rv);
14581708Sstevel }
14591708Sstevel 
14601708Sstevel static void
display_sgsbbc_revisions(Board_node * bdlist)14611708Sstevel display_sgsbbc_revisions(Board_node *bdlist)
14621708Sstevel {
14631708Sstevel 
14641708Sstevel 	Prom_node	*pnode;
14651708Sstevel 	int		*int_val;
14661708Sstevel 	int		portid;
14671708Sstevel 	char		*model;
14681708Sstevel 	char		*status;
14691708Sstevel 	int		revision;
14701708Sstevel 	int 		node_id;
14711708Sstevel 	Board_node	*bnode;
14721708Sstevel 
14731708Sstevel #ifdef DEBUG
14741708Sstevel 	char	*slot_name;
14751708Sstevel 	char	notes[30];
14761708Sstevel 	char	*value;
14771708Sstevel #endif
14781708Sstevel 
14791708Sstevel 	bnode = bdlist;
14801708Sstevel 	while (bnode != NULL) {
14811708Sstevel 		/*
14821708Sstevel 		 * search this board node for all sgsbbc's
14831708Sstevel 		 */
14841708Sstevel 		for (pnode = dev_find_node_by_type(bnode->nodes, "model",
1485*5889Szk194757 		    "SUNW,sgsbbc"); pnode != NULL;
1486*5889Szk194757 		    pnode = dev_next_node_by_type(pnode, "model",
1487*5889Szk194757 		    "SUNW,sgsbbc")) {
14881708Sstevel 
14891708Sstevel 			char	fru_name[MAX_FRU_NAME_LEN] = "";
14901708Sstevel 
14911708Sstevel 			/*
14921708Sstevel 			 * We need to go to this node's parent to
14931708Sstevel 			 * get a portid to tell us what board it is on
14941708Sstevel 			 */
14951708Sstevel 			int_val = (int *)get_prop_val
1496*5889Szk194757 			    (find_prop(pnode->parent, "portid"));
14971708Sstevel 			if (int_val == NULL)
14981708Sstevel 				continue;
14991708Sstevel 
15001708Sstevel 			portid = *int_val;
15011708Sstevel 			/* get the node-id */
15021708Sstevel 			node_id =  SG_PORTID_TO_NODEID(portid);
15031708Sstevel 
15041708Sstevel 			/* model */
15051708Sstevel 			model = (char *)get_prop_val
1506*5889Szk194757 			    (find_prop(pnode, "model"));
15071708Sstevel 
15081708Sstevel 			/* status */
15091708Sstevel 			status = (char *)get_prop_val(find_prop
1510*5889Szk194757 			    (pnode, "status"));
15111708Sstevel 
15121708Sstevel 			/* revision */
15131708Sstevel 			int_val = (int *)get_prop_val
1514*5889Szk194757 			    (find_prop(pnode, "revision-id"));
15151708Sstevel 			if (int_val != NULL)
15161708Sstevel 				revision = *int_val;
15171708Sstevel 			else
15181708Sstevel 				revision = -1;
15191708Sstevel 
15201708Sstevel #ifdef DEBUG
15211708Sstevel 			value = (char *)get_prop_val(
1522*5889Szk194757 			    find_prop(pnode->parent, "slot-names"));
15231708Sstevel 			if (value != NULL) {
15241708Sstevel 				/* Skip the 4 byte bitmask */
15251708Sstevel 				slot_name = (char *)value + sizeof (int);
15261708Sstevel 			} else {
15271708Sstevel 				strcpy(slot_name, "not_found");
15281708Sstevel 			}
15291708Sstevel 			(void) sprintf(notes, "[%s] portid [%d]", slot_name,
1530*5889Szk194757 			    portid);
15311708Sstevel #endif
15321708Sstevel 			/*
15331708Sstevel 			 * Display the data
15341708Sstevel 			 */
15351708Sstevel 			/* FRU Name */
15361708Sstevel 			SG_SET_FRU_NAME_NODE(fru_name, node_id);
15371708Sstevel 			SG_SET_FRU_NAME_IO_BOARD(fru_name,
1538*5889Szk194757 			    SG_IO_BD_PORTID_TO_BD_NUM(portid));
15391708Sstevel 			SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
15401708Sstevel 			log_printf("%-12s", fru_name, 0);
15411708Sstevel 
15421708Sstevel 			/* model */
15431708Sstevel 			if (model != NULL)
15441708Sstevel 				log_printf("%-15s  ", model, 0);
15451708Sstevel 			else
15461708Sstevel 				log_printf("%-15s  ", "unknown", 0);
15471708Sstevel 			/* portid */
15481708Sstevel 			log_printf("%-3d ", portid, 0);
15491708Sstevel 			/* status */
15501708Sstevel 			if (status == (char *)NULL)
15511708Sstevel 				log_printf(" ok      ", 0);
15521708Sstevel 			else
15531708Sstevel 				log_printf(" fail    ", 0);
15541708Sstevel 			/* revision */
15551708Sstevel 			log_printf("     %-4d   ", revision, 0);
15561708Sstevel #ifdef DEBUG
15571708Sstevel 			log_printf("%s", notes, 0);
15581708Sstevel #endif
15591708Sstevel 			log_printf("\n", 0);
15601708Sstevel 		}
15611708Sstevel 		bnode = bnode->next;
15621708Sstevel 	}
15631708Sstevel }
15641708Sstevel 
15651708Sstevel /*ARGSUSED0*/
15661708Sstevel void
display_hp_fail_fault(Sys_tree * tree,struct system_kstat_data * kstats)15671708Sstevel display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
15681708Sstevel {
15691708Sstevel 	serengeti_display_board_info(ACTIVE);
15701708Sstevel 	serengeti_display_board_info(INACTIVE);
15711708Sstevel }
15721708Sstevel 
15731708Sstevel /*
15741708Sstevel  * display_failed_parts
15751708Sstevel  *
15761708Sstevel  * Display the failed parts in the system. This function looks for
15771708Sstevel  * the status property in all PROM nodes contained in the Sys_tree
15781708Sstevel  * passed in.
15791708Sstevel  */
15801708Sstevel int
display_failed_parts(Sys_tree * tree)15811708Sstevel display_failed_parts(Sys_tree *tree)
15821708Sstevel {
15831708Sstevel 	int system_failed = 0;
15841708Sstevel 	int bank_failed = 0;
15851708Sstevel 	int schizo_failed = FALSE;
15861708Sstevel 	int portid, nodeid, board;
15871708Sstevel 	Board_node *bnode = tree->bd_list;
15881708Sstevel 	Prom_node *pnode;
15891708Sstevel 	int *coreid, *impl;
15901708Sstevel 	print_flag = TRUE;
15911708Sstevel 
15921708Sstevel 	/*
15931708Sstevel 	 * go through all of the OBP nodes looking for
15941708Sstevel 	 * failed units.
15951708Sstevel 	 */
15961708Sstevel 	while (bnode != NULL) {
15971708Sstevel 
15981708Sstevel 		pnode = find_failed_node(bnode->nodes);
15991708Sstevel 		if ((pnode != NULL) && !system_failed) {
16001708Sstevel 			system_failed = TRUE;
16011708Sstevel 			log_printf("\n", 0);
16021708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
1603*5889Szk194757 			    "Failed Field Replaceable Units (FRU) in "
1604*5889Szk194757 			    "System:\n"), 0);
16051708Sstevel 			log_printf("=========================="
1606*5889Szk194757 			    "====================\n", 0);
16071708Sstevel 		}
16081708Sstevel 
16091708Sstevel 		while (pnode != NULL) {
16101708Sstevel 			void *status;
16111708Sstevel 			char *name, *type, *model;
16121708Sstevel 
16131708Sstevel 			char	fru_name[MAX_FRU_NAME_LEN] = "";
16141708Sstevel 
16151708Sstevel 			status = get_prop_val(find_prop(pnode, "status"));
16161708Sstevel 			name = get_node_name(pnode);
16171708Sstevel 
16181708Sstevel 			/* sanity check of data retreived from PROM */
16191708Sstevel 			if ((status == NULL) || (name == NULL)) {
16201708Sstevel 				pnode = next_failed_node(pnode);
16211708Sstevel 				continue;
16221708Sstevel 			}
16231708Sstevel 
16241708Sstevel 			type = get_node_type(pnode);
16251708Sstevel 			portid = get_id(pnode);
16261708Sstevel 			model = (char *)get_prop_val
16271708Sstevel 			    (find_prop(pnode, "model"));
16281708Sstevel 
16291708Sstevel 			/*
16301708Sstevel 			 * Determine whether FRU is CPU module, Mem Controller,
16311708Sstevel 			 * PCI card, schizo,xmits or sgsbbc.
16321708Sstevel 			 */
16331708Sstevel 			if ((model != NULL) && strstr(model, "sgsbbc")) {
16341708Sstevel 				/*
16351708Sstevel 				 * sgsbbc / bootbus-controller
16361708Sstevel 				 */
16371708Sstevel 				portid = get_id(pnode->parent);
16381708Sstevel 				nodeid = SG_PORTID_TO_NODEID(portid);
16391708Sstevel 				board = SG_PORTID_TO_BOARD_NUM(portid);
16401708Sstevel 
16411708Sstevel 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
16421708Sstevel 				SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
16431708Sstevel 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
16441708Sstevel 
16451708Sstevel 				log_printf("\tFailed Device : %s (%s)\n", model,
1646*5889Szk194757 				    name, 0);
16471708Sstevel 				log_printf("\tLocation : %s\n", fru_name, 0);
16481708Sstevel 
16491708Sstevel 			} else if (strstr(name, "pci") && (portid == -1)) {
16501708Sstevel 				/*
16511708Sstevel 				 * PCI Bridge if name = pci and it doesn't
16521708Sstevel 				 * have a portid.
16531708Sstevel 				 */
16541708Sstevel 				portid = get_id(pnode->parent);
16551708Sstevel 				nodeid = SG_PORTID_TO_NODEID(portid);
16561708Sstevel 				board = SG_PORTID_TO_BOARD_NUM(portid);
16571708Sstevel 
16581708Sstevel 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
16591708Sstevel 				SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
16601708Sstevel 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
16611708Sstevel 
16621708Sstevel 				log_printf("\tFRU type : ", 0);
16631708Sstevel 				log_printf("PCI Bridge Device\n", 0);
16641708Sstevel 				log_printf("\tLocation : %s\n", fru_name, 0);
16651708Sstevel 
16661708Sstevel 			} else if ((type != NULL) &&
16671708Sstevel 			    (strstr(type, "cpu") ||
16681708Sstevel 			    strstr(type, "memory-controller"))) {
16691708Sstevel 				/*
16701708Sstevel 				 * CPU or memory controller
16711708Sstevel 				 */
16721708Sstevel 				portid = get_id(pnode);
16731708Sstevel 				/*
16741708Sstevel 				 * For cpu nodes that belong to a CMP, the
16751708Sstevel 				 * portid is stored in the parent "cmp" node.
16761708Sstevel 				 */
16771708Sstevel 				if (portid == -1)
16781708Sstevel 					portid = get_id(pnode->parent);
16791708Sstevel 				nodeid = SG_PORTID_TO_NODEID(portid);
16801708Sstevel 				board = SG_PORTID_TO_BOARD_NUM(portid);
16811708Sstevel 
16821708Sstevel 				SG_SET_FRU_NAME_NODE(fru_name, nodeid);
16831708Sstevel 				SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
16841708Sstevel 				SG_SET_FRU_NAME_MODULE(fru_name, portid % 4);
16851708Sstevel 
16861708Sstevel 				log_printf("\tFRU type : ", 0);
16871708Sstevel 
16881708Sstevel 				if (strstr(type, "memory-controller"))
16891708Sstevel 					log_printf("Memory Controller on ", 0);
16901708Sstevel 
16911708Sstevel 				log_printf("UltraSPARC module\n", 0);
16921708Sstevel 
16931708Sstevel 				log_printf("\tLocation : %s\n", fru_name, 0);
16941708Sstevel 
16951708Sstevel 			} else {
16961708Sstevel 				/*
16971708Sstevel 				 * It should only be a PCI card if we get to
16981708Sstevel 				 * here but lets check to be sure.
16991708Sstevel 				 */
17001708Sstevel 				char *parents_model, *grandparents_model;
17011708Sstevel 				Prom_node *parent_pnode;
17021708Sstevel 				int pci_card_found = 0;
17031708Sstevel 
17041708Sstevel 				if (pnode->parent != NULL)
17051708Sstevel 					parent_pnode = pnode->parent;
17061708Sstevel 
17071708Sstevel 				/*
17081708Sstevel 				 * Is our parent a schizo or xmits
17091708Sstevel 				 */
17101708Sstevel 				parents_model = (char *)get_prop_val
17111708Sstevel 				    (find_prop(pnode->parent, "model"));
17121708Sstevel 				if ((parents_model != NULL) &&
17131708Sstevel 				    (strstr(parents_model, "SUNW,schizo") ||
17141708Sstevel 				    strstr(parents_model, "SUNW,xmits"))) {
17151708Sstevel 					portid = get_id(pnode->parent);
17161708Sstevel 					pci_card_found = TRUE;
17171708Sstevel 				}
17181708Sstevel 
17191708Sstevel 				/*
17201708Sstevel 				 * Is our grandparent a schizo xmits
17211708Sstevel 				 */
17221708Sstevel 				grandparents_model = (char *)get_prop_val
17231708Sstevel 				    (find_prop(parent_pnode->parent, "model"));
17241708Sstevel 				if ((grandparents_model != NULL) &&
17251708Sstevel 				    (strstr(grandparents_model,
17261708Sstevel 				    "SUNW,schizo") ||
17271708Sstevel 				    strstr(grandparents_model,
17281708Sstevel 				    "SUNW,xmits"))) {
17291708Sstevel 					portid = get_id(parent_pnode->parent);
17301708Sstevel 					pci_card_found = TRUE;
17311708Sstevel 				}
17321708Sstevel 
17331708Sstevel 				if (pci_card_found) {
17341708Sstevel 					nodeid = SG_PORTID_TO_NODEID(portid);
17351708Sstevel 					board = SG_PORTID_TO_BOARD_NUM(portid);
17361708Sstevel 
17371708Sstevel 					SG_SET_FRU_NAME_NODE(fru_name, nodeid);
17381708Sstevel 					SG_SET_FRU_NAME_IO_BOARD(fru_name,
1739*5889Szk194757 					    board);
17401708Sstevel 					SG_SET_FRU_NAME_MODULE(fru_name,
1741*5889Szk194757 					    portid % 2);
17421708Sstevel 
17431708Sstevel 					log_printf("\tFRU type :", 0);
17441708Sstevel 					log_printf(" PCI Card\n", 0);
17451708Sstevel 					log_printf("\tLocation : %s\n",
1746*5889Szk194757 					    fru_name, 0);
17471708Sstevel 				}
17481708Sstevel 			}
17491708Sstevel 			log_printf("\tPROM status: %s\n\n", status, 0);
17501708Sstevel 
17511708Sstevel 			pnode = next_failed_node(pnode);
17521708Sstevel 		}
17531708Sstevel 		bnode = bnode->next;
17541708Sstevel 
17551708Sstevel 	}
17561708Sstevel 
17571708Sstevel 	bank_failed = display_us3_failed_banks(system_failed);
17581708Sstevel 	schizo_failed = display_schizo_revisions(tree->bd_list,
1759*5889Szk194757 	    SG_SCHIZO_FAILED);
17601708Sstevel 	if (system_failed || bank_failed || schizo_failed)
17611708Sstevel 		return (1);
17621708Sstevel 	else
17631708Sstevel 		return (0);
17641708Sstevel }
17651708Sstevel 
17661708Sstevel 
17671708Sstevel /*
17681708Sstevel  * This routine displays the memory configuration for all boards in the
17691708Sstevel  * system.
17701708Sstevel  */
17711708Sstevel /*ARGSUSED0*/
17721708Sstevel void
display_memoryconf(Sys_tree * tree,struct grp_info * grps)17731708Sstevel display_memoryconf(Sys_tree *tree, struct grp_info *grps)
17741708Sstevel {
17751708Sstevel 	Board_node	*bnode = tree->bd_list;
17761708Sstevel 
17771708Sstevel 	log_printf("========================= Memory Configuration"
1778*5889Szk194757 	    " ===============================\n", 0);
17791708Sstevel 	log_printf("\n                     Logical  Logical  Logical ", 0);
17801708Sstevel 	log_printf("\n               Port  Bank     Bank     Bank         "
1781*5889Szk194757 	    "DIMM    Interleave  Interleave", 0);
17821708Sstevel 	log_printf("\nFRU Name        ID   Num      Size     Status       "
1783*5889Szk194757 	    "Size    Factor      Segment", 0);
17841708Sstevel 	log_printf("\n-------------  ----  ----     ------   -----------  "
1785*5889Szk194757 	    "------  ----------  ----------", 0);
17861708Sstevel 
17871708Sstevel 	while (bnode != NULL) {
17881708Sstevel 		if (get_us3_mem_regs(bnode)) {
17891708Sstevel 			log_printf(dgettext(TEXT_DOMAIN,
17901708Sstevel 			    "\nFailed to get memory information.\n"), 0);
17911708Sstevel 			return;
17921708Sstevel 		}
17931708Sstevel 		bnode = bnode->next;
17941708Sstevel 	}
17951708Sstevel 
17961708Sstevel 	/* Display what we have found */
17971708Sstevel 	display_us3_banks();
17981708Sstevel }
17991708Sstevel 
18001708Sstevel /*
18011708Sstevel  * This function provides Serengeti's formatting of the memory config
18021708Sstevel  * information that get_us3_mem_regs() and display_us3_banks() code has
18031708Sstevel  * gathered. It overrides the generic print_us3_memory_line() code
18041708Sstevel  * which prints an error message.
18051708Sstevel  */
18061708Sstevel 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)18071708Sstevel print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
18081708Sstevel 	char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
18091708Sstevel {
18101708Sstevel 	int		nodeid, board, mcid;
18111708Sstevel 	char		fru_name[MAX_FRU_NAME_LEN] = "";
18121708Sstevel 
18131708Sstevel 	mcid 		= SG_PORTID_TO_SAFARI_ID(portid);
18141708Sstevel 	nodeid 		= SG_PORTID_TO_NODEID(portid);
18151708Sstevel 	board 		= SG_PORTID_TO_BOARD_NUM(portid);
18161708Sstevel 
18171708Sstevel 	SG_SET_FRU_NAME_NODE(fru_name, nodeid);
18181708Sstevel 	SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
18191708Sstevel 	SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
18201708Sstevel 	SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
18211708Sstevel 
18221708Sstevel 	log_printf("\n%-13s   %2d   %2d      %4lldMB    %11-s  %4lldMB "
1823*5889Szk194757 	    "   %2d-way       %d",
1824*5889Szk194757 	    fru_name, mcid,
1825*5889Szk194757 	    (bank_id % 4), bank_size, bank_status, dimm_size,
1826*5889Szk194757 	    intlv, seg_id, 0);
18271708Sstevel }
18281708Sstevel 
18291708Sstevel void
print_us3_failed_memory_line(int portid,int bank_id,char * bank_status)18301708Sstevel print_us3_failed_memory_line(int portid, int bank_id, char *bank_status)
18311708Sstevel {
18321708Sstevel 	int		nodeid, board, mcid;
18331708Sstevel 	char		fru_name[MAX_FRU_NAME_LEN] = "";
18341708Sstevel 
18351708Sstevel 	mcid		= SG_PORTID_TO_SAFARI_ID(portid);
18361708Sstevel 	nodeid		= SG_PORTID_TO_NODEID(portid);
18371708Sstevel 	board		= SG_PORTID_TO_BOARD_NUM(portid);
18381708Sstevel 
18391708Sstevel 	SG_SET_FRU_NAME_NODE(fru_name, nodeid);
18401708Sstevel 	SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
18411708Sstevel 	SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
18421708Sstevel 	SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
18431708Sstevel 
18441708Sstevel 	log_printf("\tFRU type : ", 0);
18451708Sstevel 	log_printf("Physical Memory Bank\n", 0);
18461708Sstevel 	log_printf("\tLocation : %s (Logical Bank %2d)\n",
1847*5889Szk194757 	    fru_name, (bank_id %4), 0);
18481708Sstevel 	log_printf("\tPROM status: %s\n\n", bank_status, 0);
18491708Sstevel }
18501708Sstevel 
18511708Sstevel 
18521708Sstevel /*
18531708Sstevel  * Find the requested board struct in the system device tree.
18541708Sstevel  *
18551708Sstevel  * This function overrides the functionality of the generic find_board()
18561708Sstevel  * function in libprtdiag, but since we need to pass another parameter,
18571708Sstevel  * we cannot simply overlay the symbol table.
18581708Sstevel  */
18591708Sstevel static Board_node *
serengeti_find_board(Sys_tree * root,int board,int nodeid)18601708Sstevel serengeti_find_board(Sys_tree *root, int board, int nodeid)
18611708Sstevel {
18621708Sstevel 	Board_node *bnode = root->bd_list;
18631708Sstevel 
18641708Sstevel 	while ((bnode != NULL) &&
1865*5889Szk194757 	    ((board != bnode->board_num) || (nodeid != bnode->node_id))) {
18661708Sstevel 		bnode = bnode->next;
18671708Sstevel 	}
18681708Sstevel 	return (bnode);
18691708Sstevel }
18701708Sstevel 
18711708Sstevel 
18721708Sstevel /*
18731708Sstevel  * Add a board to the system list in order (sorted by NodeID then board#).
18741708Sstevel  * Initialize all pointer fields to NULL.
18751708Sstevel  */
18761708Sstevel static Board_node *
serengeti_insert_board(Sys_tree * root,int board,int nodeid)18771708Sstevel serengeti_insert_board(Sys_tree *root, int board, int nodeid)
18781708Sstevel {
18791708Sstevel 	Board_node *bnode;
18801708Sstevel 	Board_node *temp = root->bd_list;
18811708Sstevel 
18821708Sstevel 	if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
18831708Sstevel 		perror("malloc");
18841708Sstevel 		exit(1);
18851708Sstevel 	}
18861708Sstevel 
18871708Sstevel 	bnode->nodes = NULL;
18881708Sstevel 	bnode->next = NULL;
18891708Sstevel 	bnode->board_num = board;
18901708Sstevel 	bnode->node_id = nodeid;
18911708Sstevel 	bnode->board_type = UNKNOWN_BOARD;
18921708Sstevel 
18931708Sstevel 	if (temp == NULL)
18941708Sstevel 		root->bd_list = bnode;
18951708Sstevel 
18961708Sstevel 	else if ((temp->board_num > board) && (temp->node_id >= nodeid)) {
18971708Sstevel 		bnode->next = temp;
18981708Sstevel 		root->bd_list = bnode;
18991708Sstevel 
19001708Sstevel 	} else {
19011708Sstevel 		while ((temp->next != NULL) &&
1902*5889Szk194757 		    ((board > temp->next->board_num) ||
1903*5889Szk194757 		    (nodeid > temp->node_id)))
19041708Sstevel 			temp = temp->next;
19051708Sstevel 
19061708Sstevel 		bnode->next = temp->next;
19071708Sstevel 		temp->next = bnode;
19081708Sstevel 	}
19091708Sstevel 	root->board_cnt++;
19101708Sstevel 
19111708Sstevel 	return (bnode);
19121708Sstevel }
19131708Sstevel 
19141708Sstevel /*
19151708Sstevel  * We call do_devinfo() in order to use the libdevinfo device tree
19161708Sstevel  * instead of OBP's device tree.
19171708Sstevel  */
19181708Sstevel int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)19191708Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
19201708Sstevel {
19211708Sstevel 
19221708Sstevel 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
19231708Sstevel 
19241708Sstevel }
19251708Sstevel 
19261708Sstevel /*
19271708Sstevel  * return the property value for the Prop passed in depending on
19281708Sstevel  * which tree (OBP/DEVINFO) is being used.
19291708Sstevel  */
19301708Sstevel void *
get_prop_val(Prop * prop)19311708Sstevel get_prop_val(Prop *prop)
19321708Sstevel {
19331708Sstevel 	if (prop == NULL)
19341708Sstevel 		return (NULL);
19351708Sstevel 
19361708Sstevel 	/* Check which tree is being used. */
19371708Sstevel 	if (tree == DEVINFO_TREE)
19381708Sstevel 		return ((void *)(prop->value.val_ptr));
19391708Sstevel 	else {
19401708Sstevel 		if (prop->value.opp.holds_array)
19411708Sstevel 			return ((void *)(prop->value.opp.oprom_array));
19421708Sstevel 		else
19431708Sstevel 			return ((void *)(&prop->value.opp.oprom_node[0]));
19441708Sstevel 	}
19451708Sstevel }
19461708Sstevel 
19471708Sstevel /*
19481708Sstevel  * Search a Prom node and retrieve the property with the correct
19491708Sstevel  * name depending on which tree (OBP/DEVINFO) is being used.
19501708Sstevel  */
19511708Sstevel Prop *
find_prop(Prom_node * pnode,char * name)19521708Sstevel find_prop(Prom_node *pnode, char *name)
19531708Sstevel {
19541708Sstevel 	Prop *prop;
19551708Sstevel 
19561708Sstevel 	if (pnode  == NULL)
19571708Sstevel 		return (NULL);
19581708Sstevel 
19591708Sstevel 	if (pnode->props == NULL)
19601708Sstevel 		return (NULL);
19611708Sstevel 
19621708Sstevel 	prop = pnode->props;
19631708Sstevel 
19641708Sstevel 	/* Check which tree is being used. */
19651708Sstevel 	if (tree == DEVINFO_TREE) {
19661708Sstevel 		while ((prop != NULL) &&
19671708Sstevel 		    (strcmp((char *)(prop->name.val_ptr), name)))
19681708Sstevel 			prop = prop->next;
19691708Sstevel 	} else {
19701708Sstevel 		while ((prop != NULL) && (strcmp((char *)
19711708Sstevel 		    (prop->name.opp.oprom_array), name)))
19721708Sstevel 			prop = prop->next;
19731708Sstevel 	}
19741708Sstevel 	return (prop);
19751708Sstevel }
19761708Sstevel 
19771708Sstevel /*
19781708Sstevel  * This function searches through the properties of the node passed in
19791708Sstevel  * and returns a pointer to the value of the name property
19801708Sstevel  * depending on which tree (OBP/DEVINFO) is being used.
19811708Sstevel  */
19821708Sstevel char *
get_node_name(Prom_node * pnode)19831708Sstevel get_node_name(Prom_node *pnode)
19841708Sstevel {
19851708Sstevel 	Prop *prop;
19861708Sstevel 
19871708Sstevel 	if (pnode == NULL)
19881708Sstevel 		return (NULL);
19891708Sstevel 
19901708Sstevel 	prop = pnode->props;
19911708Sstevel 	while (prop != NULL) {
19921708Sstevel 		/* Check which tree is being used. */
19931708Sstevel 		if (tree == DEVINFO_TREE) {
19941708Sstevel 			if (strcmp("name", (char *)prop->name.val_ptr) == 0)
19951708Sstevel 				return ((char *)prop->value.val_ptr);
19961708Sstevel 		} else {
19971708Sstevel 			if (strcmp("name", prop->name.opp.oprom_array) == 0)
19981708Sstevel 				return (prop->value.opp.oprom_array);
19991708Sstevel 		}
20001708Sstevel 		prop = prop->next;
20011708Sstevel 	}
20021708Sstevel 	return (NULL);
20031708Sstevel }
20041708Sstevel 
20051708Sstevel /*
20061708Sstevel  * This function searches through the properties of the node passed in
20071708Sstevel  * and returns a pointer to the value of the device_type property
20081708Sstevel  * depending on which tree (OBP/DEVINFO) is being used.
20091708Sstevel  */
20101708Sstevel char *
get_node_type(Prom_node * pnode)20111708Sstevel get_node_type(Prom_node *pnode)
20121708Sstevel {
20131708Sstevel 	Prop *prop;
20141708Sstevel 
20151708Sstevel 	if (pnode == NULL)
20161708Sstevel 		return (NULL);
20171708Sstevel 
20181708Sstevel 	prop = pnode->props;
20191708Sstevel 	while (prop != NULL) {
20201708Sstevel 		/* Check which tree is being used. */
20211708Sstevel 		if (tree == DEVINFO_TREE) {
20221708Sstevel 			if (strcmp("device_type", (char *)prop->name.val_ptr)
20231708Sstevel 			    == 0)
20241708Sstevel 				return ((char *)prop->value.val_ptr);
20251708Sstevel 		} else {
20261708Sstevel 			if (strcmp("device_type", prop->name.opp.oprom_array)
20271708Sstevel 			    == 0)
20281708Sstevel 				return (prop->value.opp.oprom_array);
20291708Sstevel 		}
20301708Sstevel 		prop = prop->next;
20311708Sstevel 	}
20321708Sstevel 	return (NULL);
20331708Sstevel }
20341708Sstevel 
20351708Sstevel /*
20361708Sstevel  * Take a snapshot of the OBP device tree and walk this snapshot
20371708Sstevel  * to find all failed HW (ie. devices with a status property of
20381708Sstevel  * 'fail'). Call display_failed_parts() to display the failed HW.
20391708Sstevel  */
20401708Sstevel void
get_failed_parts(void)20411708Sstevel get_failed_parts(void)
20421708Sstevel {
20431708Sstevel 	int system_failed = 0;
20441708Sstevel 	Sys_tree obp_sys_tree;		/* system information */
20451708Sstevel 
20461708Sstevel 	/* set the the system tree fields */
20471708Sstevel 	obp_sys_tree.sys_mem = NULL;
20481708Sstevel 	obp_sys_tree.boards = NULL;
20491708Sstevel 	obp_sys_tree.bd_list = NULL;
20501708Sstevel 	obp_sys_tree.board_cnt = 0;
20511708Sstevel 
20521708Sstevel 	if (promopen(O_RDONLY)) {
20531708Sstevel 		(void) fprintf(stderr, "%s",
2054*5889Szk194757 		    dgettext(TEXT_DOMAIN, "openprom device "
2055*5889Szk194757 		    "open failed"));
20561708Sstevel 		return;
20571708Sstevel 	}
20581708Sstevel 
20591708Sstevel 	if ((is_openprom() == 0) || (next(0) == 0)) {
20601708Sstevel 		(void) fprintf(stderr, "%s",
2061*5889Szk194757 		    dgettext(TEXT_DOMAIN, "openprom device "
2062*5889Szk194757 		    "error encountered."));
20631708Sstevel 		return;
20641708Sstevel 	}
20651708Sstevel 
20661708Sstevel 	tree = OBP_TREE;	/* Switch to the OBP tree */
20671708Sstevel 
20681708Sstevel 	(void) walk(&obp_sys_tree, NULL, next(0));
20691708Sstevel 
20701708Sstevel 	system_failed = display_failed_parts(&obp_sys_tree);
20711708Sstevel 
20721708Sstevel 	if (!system_failed) {
20731708Sstevel 		log_printf(dgettext(TEXT_DOMAIN,
2074*5889Szk194757 		    "No Hardware failures found in System\n"), 0);
20751708Sstevel 	}
20761708Sstevel 	promclose();
20771708Sstevel 	tree = DEVINFO_TREE;	/* Switch back to the DEVINFO tree */
20781708Sstevel }
20791708Sstevel 
20801708Sstevel /*
20811708Sstevel  * get_slot_name figures out the slot no. for the card. In the case of
20821708Sstevel  * XMITS slots 2 & 3 and slots 6 & 7 are reversed in slot_name by OBP
20831708Sstevel  * so we need to cater for this to correctly identify the slot no.
20841708Sstevel  */
20851708Sstevel static void
get_slot_name(struct io_card * card,char * slot_name)20861708Sstevel get_slot_name(struct io_card *card, char *slot_name)
20871708Sstevel {
20881708Sstevel 	char tmp_ptr[2];
20891708Sstevel 
20901708Sstevel 	if (strlen(slot_name) != 0) {
20911708Sstevel 		if (strcmp(card->notes, XMITS_COMPATIBLE) == 0) {
20921708Sstevel 			(void) sprintf(tmp_ptr, "%c",
2093*5889Szk194757 			    slot_name[strlen(slot_name) -1]);
20941708Sstevel 			switch (tmp_ptr[0]) {
20951708Sstevel 			case '2':
20961708Sstevel 				(void) sprintf(card->slot_str, "%c", '3');
20971708Sstevel 				break;
20981708Sstevel 			case '3':
20991708Sstevel 				(void) sprintf(card->slot_str, "%c", '2');
21001708Sstevel 				break;
21011708Sstevel 			case '6':
21021708Sstevel 				(void) sprintf(card->slot_str, "%c", '7');
21031708Sstevel 				break;
21041708Sstevel 			case '7':
21051708Sstevel 				(void) sprintf(card->slot_str, "%c", '6');
21061708Sstevel 				break;
21071708Sstevel 			default:
21081708Sstevel 				(void) sprintf(card->slot_str, "%c",
2109*5889Szk194757 				    slot_name[strlen(slot_name) -1]);
21101708Sstevel 			}
21111708Sstevel 		} else
21121708Sstevel 			(void) sprintf(card->slot_str, "%c",
2113*5889Szk194757 			    slot_name[strlen(slot_name) -1]);
21141708Sstevel 	} else
21151708Sstevel 		(void) sprintf(card->slot_str, "-");
21161708Sstevel }
2117