xref: /onnv-gate/usr/src/lib/libprtdiag_psr/sparc/starcat/common/starcat.c (revision 5889:686e556a6c1d)
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  * Starcat Platform specific functions.
261708Sstevel  *
271708Sstevel  * 	called when :
281708Sstevel  *	machine_type == MTYPE_STARCAT
291708Sstevel  */
301708Sstevel 
311708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
321708Sstevel 
331708Sstevel #include <stdio.h>
341708Sstevel #include <stdlib.h>
351708Sstevel #include <unistd.h>
361708Sstevel #include <ctype.h>
371708Sstevel #include <string.h>
381708Sstevel #include <kvm.h>
391708Sstevel #include <varargs.h>
401708Sstevel #include <time.h>
411708Sstevel #include <dirent.h>
421708Sstevel #include <fcntl.h>
431708Sstevel #include <assert.h>
441708Sstevel #include <sys/param.h>
451708Sstevel #include <sys/stat.h>
461708Sstevel #include <sys/types.h>
471708Sstevel #include <sys/utsname.h>
481708Sstevel #include <sys/openpromio.h>
491708Sstevel #include <libintl.h>
501708Sstevel #include <syslog.h>
511708Sstevel #include <sys/dkio.h>
521708Sstevel #include <pdevinfo.h>
531708Sstevel #include <display.h>
541708Sstevel #include <pdevinfo_sun4u.h>
551708Sstevel #include <display_sun4u.h>
561708Sstevel #include <libprtdiag.h>
571708Sstevel 
581708Sstevel #define	HZ_TO_MHZ(x)		(((x) + 500000) / 1000000)
591708Sstevel #define	PORTID_TO_EXPANDER(p)	(((p) >> 5) & 0x1f)
601708Sstevel #define	PORTID_TO_SLOT(p)	(((p) >> 3) & 0x1)
611708Sstevel #define	PORTID_TO_INSTANCE(p)	((p) & 0x3)
621708Sstevel #define	SCHIZO_COMPATIBLE	"pci108e,8001"
631708Sstevel #define	XMITS_COMPATIBLE	"pci108e,8002"
641708Sstevel #define	SC_BOARD_TYPE(id)	(PORTID_TO_SLOT(id) ? "IO" : "SB")
651708Sstevel 
661708Sstevel #ifndef	TEXT_DOMAIN
671708Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
681708Sstevel #endif	/* TEXT_DOMAIN */
691708Sstevel 
701708Sstevel #define	DEFAULT_MAX_FREQ	66	/* 66 MHz */
711708Sstevel #define	PCIX_MAX_FREQ		90	/* 90 MHz */
721708Sstevel 
731708Sstevel /*
741708Sstevel  * these functions will overlay the symbol table of libprtdiag
751708Sstevel  * at runtime (Starcat systems only)
761708Sstevel  */
771708Sstevel 
781708Sstevel int	do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
791708Sstevel void	*get_prop_val(Prop *prop);
801708Sstevel Prop	*find_prop(Prom_node *pnode, char *name);
811708Sstevel char	*get_node_name(Prom_node *pnode);
821708Sstevel char	*get_node_type(Prom_node *pnode);
831708Sstevel void	add_node(Sys_tree *, Prom_node *);
841708Sstevel void	display_pci(Board_node *);
851708Sstevel void	display_ffb(Board_node *, int);
861708Sstevel void	display_io_cards(struct io_card *list);
871708Sstevel void	display_cpu_devices(Sys_tree *tree);
881708Sstevel void	display_cpus(Board_node *board);
891708Sstevel void	display_memoryconf(Sys_tree *tree, struct grp_info *grps);
901708Sstevel void	print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
911708Sstevel 	    char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
921708Sstevel void	display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
931708Sstevel 		struct system_kstat_data *kstats);
941708Sstevel 
951708Sstevel /* Local Functions */
961708Sstevel static void	starcat_disp_hw_revisions(Prom_node *root);
971708Sstevel static void display_io_max_bus_speed(struct io_card *p);
981708Sstevel static void display_io_slot_info(struct io_card *p);
991708Sstevel 
1001708Sstevel /* The bus max freq is determined based on board level in use */
1011708Sstevel int	board_bus_max_freq = DEFAULT_MAX_FREQ;	/* 66MHz default */
1021708Sstevel 
1031708Sstevel /*
1041708Sstevel  * display_pci
1051708Sstevel  * Display all the PCI IO cards on this board.
1061708Sstevel  */
1071708Sstevel void
display_pci(Board_node * board)1081708Sstevel display_pci(Board_node *board)
1091708Sstevel {
1101708Sstevel 	struct io_card *card_list = NULL;
1111708Sstevel 	struct io_card card;
1121708Sstevel 	void *value;
1131708Sstevel 	Prom_node *pci;
1141708Sstevel 	Prom_node *card_node;
1151708Sstevel 	Prom_node *pci_bridge_node = NULL;
1161708Sstevel 	char	*slot_name_arr[MAX_SLOTS_PER_IO_BD] = {NULL};
1171708Sstevel 	char	*slot_name = NULL;
1181708Sstevel 	int	slot_name_bits;
1191708Sstevel 	int	slot_name_offset = 0;
1201708Sstevel 	char	*child_name;
1211708Sstevel 	char	*name, *type;
1221708Sstevel 	char	buf[MAXSTRLEN];
1231708Sstevel 	int	*int_val;
1241708Sstevel 	int	pci_bus;
1251708Sstevel 	int	pci_bridge = 0;
1261708Sstevel 	int	pci_bridge_dev_no;
1271708Sstevel 	int	child_dev_no;
1281708Sstevel 	int	i;
1291708Sstevel 	int	portid;
1301708Sstevel 	int	version, *pversion;
1311708Sstevel 
1321708Sstevel 	if (board == NULL)
1331708Sstevel 		return;
1341708Sstevel 
1351708Sstevel 	/* Initialize all the common information */
1361708Sstevel 	card.display = TRUE;
1371708Sstevel 	card.board = board->board_num;
1381708Sstevel 	card.node_id = board->node_id;
1391708Sstevel 
1401708Sstevel 	/*
1411708Sstevel 	 * Search for each schizo, then find/display all nodes under
1421708Sstevel 	 * each schizo node found.  Since the model property "SUNW,schizo"
1431708Sstevel 	 * is not supported on Starcat, we must match on the compatible
1441708Sstevel 	 * property "pci108e,8001".
1451708Sstevel 	 */
1461708Sstevel 	for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
1471708Sstevel 	    pci != NULL;
1481708Sstevel 	    pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
1491708Sstevel 
1501708Sstevel 		/* set max freq for this board */
1511708Sstevel 		board_bus_max_freq = DEFAULT_MAX_FREQ;
1521708Sstevel 		/*
1531708Sstevel 		 * Find out if this is a PCI or cPCI IO Board.
1541708Sstevel 		 * If "enum-impl" property exists in pci node => cPCI.
1551708Sstevel 		 */
1561708Sstevel 		value = get_prop_val(find_prop(pci, "enum-impl"));
1571708Sstevel 		if (value == NULL) {
1581708Sstevel 			(void) sprintf(card.bus_type, "PCI");
1591708Sstevel 		} else {
1601708Sstevel 			(void) sprintf(card.bus_type, "cPCI");
1611708Sstevel 		}
1621708Sstevel 
1631708Sstevel 		if (strstr((char *)get_prop_val(
164*5889Szk194757 		    find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
165*5889Szk194757 			sprintf(card.notes, "%s", XMITS_COMPATIBLE);
1661708Sstevel 			/*
1671708Sstevel 			 * With XMITS 3.X and PCI-X mode, the bus speed
1681708Sstevel 			 * can be higher than 66MHZ.
1691708Sstevel 			 */
1701708Sstevel 			value = (int *)get_prop_val
171*5889Szk194757 			    (find_prop(pci, "module-revision#"));
1721708Sstevel 			if (value) {
1731708Sstevel 				pversion = (int *)value;
1741708Sstevel 				version = *pversion;
1751708Sstevel 				if (version >= 4)
1761708Sstevel 					board_bus_max_freq = PCIX_MAX_FREQ;
1771708Sstevel 			}
1781708Sstevel 		} else if (strstr((char *)get_prop_val(
179*5889Szk194757 		    find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
1801708Sstevel 			sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
1811708Sstevel 		else
1821708Sstevel 			sprintf(card.notes, " ");
1831708Sstevel 
1841708Sstevel 		/*
1851708Sstevel 		 * Get slot-names property from parent node and
1861708Sstevel 		 * store the individual slot names in an array.
1871708Sstevel 		 * This is more general than Starcat requires, but
1881708Sstevel 		 * it is correct, according to the slot-names property.
1891708Sstevel 		 */
1901708Sstevel 		value = (char *)get_prop_val(find_prop(pci, "slot-names"));
1911708Sstevel 		if (value == NULL) {
1921708Sstevel 			/*
1931708Sstevel 			 * No slot_names property.  This could be an Xmits
1941708Sstevel 			 * card, so check the child node for slot-names property
1951708Sstevel 			 */
1961708Sstevel 			value = (char *)get_prop_val(
197*5889Szk194757 			    find_prop(pci->child, "slot-names"));
1981708Sstevel 		}
1991708Sstevel 
2001708Sstevel 		if (value != NULL) {
2011708Sstevel 			/* Get the 4 byte bitmask and pointer to first name */
2021708Sstevel 			slot_name_bits = *(int *)value;
2031708Sstevel 			if (slot_name_bits > 0)
2041708Sstevel 				slot_name_offset = slot_name_bits - 1;
2051708Sstevel 			slot_name = (char *)value + sizeof (int);
2061708Sstevel 
2071708Sstevel 			for (i = 0; i < MAX_SLOTS_PER_IO_BD; i++) {
2081708Sstevel 				if (! (slot_name_bits & (1 << i))) {
2091708Sstevel 					slot_name_arr[i] = (char *)NULL;
2101708Sstevel 					continue;
2111708Sstevel 				}
2121708Sstevel 
2131708Sstevel 				/*
2141708Sstevel 				 * Save the name pointer into the array
2151708Sstevel 				 * and advance it past the end of this
2161708Sstevel 				 * slot name
2171708Sstevel 				 */
2181708Sstevel 				slot_name_arr[i] = slot_name;
2191708Sstevel 				slot_name += strlen(slot_name) + 1;
2201708Sstevel 			}
2211708Sstevel 			slot_name = (char *)NULL;
2221708Sstevel 		}
2231708Sstevel 
2241708Sstevel 		/*
2251708Sstevel 		 * Search for Children of this node ie. Cards.
2261708Sstevel 		 * Note: any of these cards can be a pci-bridge
2271708Sstevel 		 *	that itself has children. If we find a
2281708Sstevel 		 *	pci-bridge we need to handle it specially.
2291708Sstevel 		 */
2301708Sstevel 		card_node = pci->child;
2311708Sstevel 		while (card_node != NULL) {
2321708Sstevel 			pci_bridge = 0;
2331708Sstevel 
2341708Sstevel 			/* If it doesn't have a name, skip it */
2351708Sstevel 			name = (char *)get_prop_val(
236*5889Szk194757 			    find_prop(card_node, "name"));
2371708Sstevel 			if (name == NULL) {
2381708Sstevel 				card_node = card_node->sibling;
2391708Sstevel 				continue;
2401708Sstevel 			}
2411708Sstevel 
2421708Sstevel 			/*
2431708Sstevel 			 * get dev# and func# for this card from the
2441708Sstevel 			 * 'reg' property.
2451708Sstevel 			 */
2461708Sstevel 			int_val = (int *)get_prop_val(
247*5889Szk194757 			    find_prop(card_node, "reg"));
2481708Sstevel 			if (int_val != NULL) {
2491708Sstevel 				card.dev_no = (((*int_val) & 0xF800) >> 11);
2501708Sstevel 				card.func_no = (((*int_val) & 0x700) >> 8);
2511708Sstevel 			} else {
2521708Sstevel 				card.dev_no = -1;
2531708Sstevel 				card.func_no = -1;
2541708Sstevel 			}
2551708Sstevel 
2561708Sstevel 			/*
2571708Sstevel 			 * If this is a pci-bridge, then store it's dev#
2581708Sstevel 			 * as its children nodes need this to get their slot#.
2591708Sstevel 			 * We set the pci_bridge flag so that we know we are
2601708Sstevel 			 * looking at a pci-bridge node. This flag gets reset
2611708Sstevel 			 * every time we enter this while loop.
2621708Sstevel 			 */
2631708Sstevel 
2641708Sstevel 			/*
2651708Sstevel 			 * Check for a PCI-PCI Bridge for PCI and cPCI
2661708Sstevel 			 * IO Boards using the name and type properties.
2671708Sstevel 			 */
2681708Sstevel 			type = (char *)get_prop_val(
269*5889Szk194757 			    find_prop(card_node, "device_type"));
2701708Sstevel 			if ((type != NULL) &&
271*5889Szk194757 			    (strncmp(name, "pci", 3) == 0) &&
272*5889Szk194757 			    (strcmp(type, "pci") == 0)) {
2731708Sstevel 				pci_bridge_dev_no = card.dev_no;
2741708Sstevel 				pci_bridge_node = card_node;
2751708Sstevel 				pci_bridge = TRUE;
2761708Sstevel 			}
2771708Sstevel 
2781708Sstevel 			/*
2791708Sstevel 			 * Get slot-names property from slot_names_arr.
2801708Sstevel 			 * If we are the child of a pci_bridge we use the
2811708Sstevel 			 * dev# of the pci_bridge as an index to get
2821708Sstevel 			 * the slot number. We know that we are a child of
2831708Sstevel 			 * a pci-bridge if our parent is the same as the last
2841708Sstevel 			 * pci_bridge node found above.
2851708Sstevel 			 */
2861708Sstevel 			if (card.dev_no != -1) {
2871708Sstevel 				/*
2881708Sstevel 				 * We compare this card's parent node with the
2891708Sstevel 				 * pci_bridge_node to see if it's a child.
2901708Sstevel 				 */
2911708Sstevel 				if (card_node->parent == pci_bridge_node) {
2921708Sstevel 					/* use dev_no of pci_bridge */
2931708Sstevel 					child_dev_no = pci_bridge_dev_no - 1;
2941708Sstevel 				} else {
2951708Sstevel 					/* use card's own dev_no */
2961708Sstevel 					child_dev_no = card.dev_no - 1;
2971708Sstevel 				}
2981708Sstevel 
2991708Sstevel 				if (child_dev_no < MAX_SLOTS_PER_IO_BD &&
3001708Sstevel 				    child_dev_no >= 0 &&
3011708Sstevel 				    slot_name_arr
3021708Sstevel 				    [child_dev_no + slot_name_offset] != NULL) {
3031708Sstevel 
3041708Sstevel 					slot_name = slot_name_arr[
3051708Sstevel 					    child_dev_no + slot_name_offset];
3061708Sstevel 				} else
3071708Sstevel 					slot_name = (char *)NULL;
3081708Sstevel 
3091708Sstevel 				if (slot_name != NULL && slot_name[0] != '\0') {
3101708Sstevel 					(void) sprintf(card.slot_str, "%s",
3111708Sstevel 					    slot_name);
3121708Sstevel 				} else {
3131708Sstevel 					(void) sprintf(card.slot_str, "-");
3141708Sstevel 				}
3151708Sstevel 			} else {
3161708Sstevel 				(void) sprintf(card.slot_str, "%c", '-');
3171708Sstevel 			}
3181708Sstevel 
3191708Sstevel 			/*
3201708Sstevel 			 * Get the portid of the schizo that this card
3211708Sstevel 			 * lives under.
3221708Sstevel 			 */
3231708Sstevel 			portid = -1;
3241708Sstevel 			value = get_prop_val(find_prop(pci, "portid"));
3251708Sstevel 			if (value != NULL) {
3261708Sstevel 				portid = *(int *)value;
3271708Sstevel 			}
3281708Sstevel 			card.schizo_portid = portid;
3291708Sstevel 
3301708Sstevel #ifdef	DEBUG
3311708Sstevel 			(void) sprintf(card.notes, "%s portid [%d]"
332*5889Szk194757 			    " dev_no [%d] slot_name[%s] name_bits[%#x]",
333*5889Szk194757 			    card.notes, portid, card.dev_no,
334*5889Szk194757 			    ((slot_name != NULL) ? slot_name : "NULL"),
335*5889Szk194757 			    slot_name_bits);
3361708Sstevel #endif	/* DEBUG */
3371708Sstevel 
3381708Sstevel 			/*
3391708Sstevel 			 * Find out whether this is PCI bus A or B
3401708Sstevel 			 * using the 'reg' property.
3411708Sstevel 			 */
3421708Sstevel 			int_val = (int *)get_prop_val
343*5889Szk194757 			    (find_prop(pci, "reg"));
3441708Sstevel 
3451708Sstevel 			if (int_val != NULL) {
3461708Sstevel 				int_val ++; /* skip over first integer */
3471708Sstevel 				pci_bus = ((*int_val) & 0x7f0000);
3481708Sstevel 				if (pci_bus == 0x600000)
3491708Sstevel 					card.pci_bus = 'A';
3501708Sstevel 				else if (pci_bus == 0x700000)
3511708Sstevel 					card.pci_bus = 'B';
3521708Sstevel 				else
3531708Sstevel 					card.pci_bus = '-';
3541708Sstevel 			} else {
3551708Sstevel 				card.pci_bus = '-';
3561708Sstevel 			}
3571708Sstevel 
3581708Sstevel 
3591708Sstevel 			/*
3601708Sstevel 			 * Check for failed status.
3611708Sstevel 			 */
3621708Sstevel 			if (node_failed(card_node))
3631708Sstevel 				strcpy(card.status, "fail");
3641708Sstevel 			else
3651708Sstevel 				strcpy(card.status, "ok");
3661708Sstevel 
3671708Sstevel 			/* Get the model of this card */
3681708Sstevel 			value = get_prop_val(find_prop(card_node, "model"));
3691708Sstevel 			if (value == NULL)
3701708Sstevel 				card.model[0] = '\0';
3711708Sstevel 			else {
3721708Sstevel 				(void) sprintf(card.model, "%s", (char *)value);
3731708Sstevel 				/*
3741708Sstevel 				 * If we wish to exclude onboard devices
3751708Sstevel 				 * (such as SBBC) then this is the place
3761708Sstevel 				 * and here is how to do it:
3771708Sstevel 				 *
3781708Sstevel 				 * if (strcmp(card.model, "SUNW,sbbc") == 0) {
3791708Sstevel 				 *	card_node = card_node->sibling;
3801708Sstevel 				 *	continue;
3811708Sstevel 				 * }
3821708Sstevel 				 */
3831708Sstevel 			}
3841708Sstevel 
3851708Sstevel 			/*
3861708Sstevel 			 * The card may have a "clock-frequency" but we
3871708Sstevel 			 * are not interested in that. Instead we get the
3881708Sstevel 			 * "clock-frequency" of the PCI Bus that the card
3891708Sstevel 			 * resides on. PCI-A can operate at 33Mhz or 66Mhz
3901708Sstevel 			 * depending on what card is plugged into the Bus.
3911708Sstevel 			 * PCI-B always operates at 33Mhz.
3921708Sstevel 			 *
3931708Sstevel 			 */
3941708Sstevel 			int_val = get_prop_val(find_prop(pci,
395*5889Szk194757 			    "clock-frequency"));
3961708Sstevel 			if (int_val != NULL) {
3971708Sstevel 				card.freq = HZ_TO_MHZ(*int_val);
3981708Sstevel 			} else {
3991708Sstevel 				card.freq = -1;
4001708Sstevel 			}
4011708Sstevel 
4021708Sstevel 			/*
4031708Sstevel 			 * Figure out how we want to display the name
4041708Sstevel 			 */
4051708Sstevel 			value = get_prop_val(find_prop(card_node,
406*5889Szk194757 			    "compatible"));
4071708Sstevel 			if (value != NULL) {
4081708Sstevel 				/* use 'name'-'compatible' */
4091708Sstevel 				(void) sprintf(buf, "%s-%s", name,
410*5889Szk194757 				    (char *)value);
4111708Sstevel 			} else {
4121708Sstevel 				/* just use 'name' */
4131708Sstevel 				(void) sprintf(buf, "%s", name);
4141708Sstevel 			}
4151708Sstevel 			name = buf;
4161708Sstevel 
4171708Sstevel 			/*
4181708Sstevel 			 * If this node has children, add the device_type
4191708Sstevel 			 * of the child to the name value of this card.
4201708Sstevel 			 */
4211708Sstevel 			child_name = (char *)get_node_name(card_node->child);
4221708Sstevel 			if ((card_node->child != NULL) &&
423*5889Szk194757 			    (child_name != NULL)) {
4241708Sstevel 				value = get_prop_val(find_prop(card_node->child,
425*5889Szk194757 				    "device_type"));
4261708Sstevel 				if (value != NULL) {
4271708Sstevel 					/* add device_type of child to name */
4281708Sstevel 					(void) sprintf(card.name, "%s/%s (%s)",
429*5889Szk194757 					    name, child_name,
430*5889Szk194757 					    (char *)value);
4311708Sstevel 				} else {
4321708Sstevel 					/* just add child's name */
4331708Sstevel 					(void) sprintf(card.name, "%s/%s",
434*5889Szk194757 					    name, child_name);
4351708Sstevel 				}
4361708Sstevel 			} else {
4371708Sstevel 				/* childless, just the card's name */
4381708Sstevel 				(void) sprintf(card.name, "%s", (char *)name);
4391708Sstevel 			}
4401708Sstevel 
4411708Sstevel 			/*
4421708Sstevel 			 * If this is a pci-bridge, then add the word
4431708Sstevel 			 * 'pci-bridge' to its model.
4441708Sstevel 			 */
4451708Sstevel 			if (pci_bridge) {
4461708Sstevel 				if (card.model[0] == '\0')
4471708Sstevel 					(void) sprintf(card.model,
448*5889Szk194757 					    "%s", "pci-bridge");
4491708Sstevel 				else
4501708Sstevel 					(void) strcat(card.model,
451*5889Szk194757 					    "/pci-bridge");
4521708Sstevel 			}
4531708Sstevel 
4541708Sstevel 			/* insert this card in the list to be displayed later */
4551708Sstevel 			card_list = insert_io_card(card_list, &card);
4561708Sstevel 
4571708Sstevel 			/*
4581708Sstevel 			 * If we are dealing with a pci-bridge, we need to move
4591708Sstevel 			 * down to the children of this bridge, if there are
4601708Sstevel 			 * any, otherwise its siblings.
4611708Sstevel 			 *
4621708Sstevel 			 * If not a bridge, we are either dealing with a regular
4631708Sstevel 			 * card (in which case we move onto the sibling of this
4641708Sstevel 			 * card) or we are dealing with a child of a pci-bridge
4651708Sstevel 			 * (in which case we move onto the child's siblings or
4661708Sstevel 			 * if there are no more siblings for this child, we
4671708Sstevel 			 * move onto the parent's siblings).  I hope you're
4681708Sstevel 			 * getting all this, there will be an exam later.
4691708Sstevel 			 */
4701708Sstevel 			if (pci_bridge) {
4711708Sstevel 				if (card_node->child != NULL)
4721708Sstevel 					card_node = card_node->child;
4731708Sstevel 				else
4741708Sstevel 					card_node = card_node->sibling;
4751708Sstevel 			} else {
4761708Sstevel 				/*
4771708Sstevel 				 * If our parent is a pci-bridge but there
4781708Sstevel 				 * are no more of its children to process we
4791708Sstevel 				 * move back up to our parent's sibling,
4801708Sstevel 				 * otherwise we move onto our own sibling.
4811708Sstevel 				 */
4821708Sstevel 				if ((card_node->parent == pci_bridge_node) &&
483*5889Szk194757 				    (card_node->sibling == NULL))
4841708Sstevel 					card_node =
4851708Sstevel 					    pci_bridge_node->sibling;
4861708Sstevel 				else
4871708Sstevel 					card_node = card_node->sibling;
4881708Sstevel 			}
4891708Sstevel 
4901708Sstevel 		} /* end while (card_node ...) loop */
4911708Sstevel 
4921708Sstevel 	} /* end for (pci ...) loop */
4931708Sstevel 
4941708Sstevel 	display_io_cards(card_list);
4951708Sstevel 	free_io_cards(card_list);
4961708Sstevel }
4971708Sstevel 
4981708Sstevel /*
4991708Sstevel  * display_ffb
5001708Sstevel  *
5011708Sstevel  * There are no FFB's on a Starcat, however in the generic library,
5021708Sstevel  * the display_ffb() function is implemented so we have to define an
5031708Sstevel  * empty function here.
5041708Sstevel  */
5051708Sstevel /*ARGSUSED0*/
5061708Sstevel void
display_ffb(Board_node * board,int table)5071708Sstevel display_ffb(Board_node *board, int table)
5081708Sstevel {
5091708Sstevel }
5101708Sstevel 
5111708Sstevel /*
5121708Sstevel  * add_node
5131708Sstevel  *
5141708Sstevel  * This function adds a board node to the board structure where that
5151708Sstevel  * that node's physical component lives.
5161708Sstevel  */
5171708Sstevel void
add_node(Sys_tree * root,Prom_node * pnode)5181708Sstevel add_node(Sys_tree *root, Prom_node *pnode)
5191708Sstevel {
5201708Sstevel 	int	portid = -1;
5211708Sstevel 	int	nodeid = -1;
5221708Sstevel 	void	*value;
5231708Sstevel 	Board_node	*bnode;
5241708Sstevel 	Prom_node	*p;
5251708Sstevel 	char	*type;
5261708Sstevel 
5271708Sstevel 	/* Get the board number of this board from the portid prop */
5281708Sstevel 	if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
5291708Sstevel 		if (type = get_node_type(pnode))
5301708Sstevel 			if (strcmp(type, "cpu") == 0)
5311708Sstevel 				value = get_prop_val(find_prop(pnode->parent,
5321708Sstevel 				    "portid"));
5331708Sstevel 	}
5341708Sstevel 	if (value != NULL) {
5351708Sstevel 		portid = *(int *)value;
5361708Sstevel 		nodeid = PORTID_TO_EXPANDER(portid);
5371708Sstevel 	}
5381708Sstevel 
5391708Sstevel 	/* find the board node with the same board number */
5401708Sstevel 	if ((bnode = find_board(root, portid)) == NULL) {
5411708Sstevel 		bnode = insert_board(root, portid);
5421708Sstevel 		bnode->board_type = UNKNOWN_BOARD;
5431708Sstevel 		bnode->node_id = nodeid;
5441708Sstevel 	}
5451708Sstevel 
5461708Sstevel 	/* now attach this prom node to the board list */
5471708Sstevel 	/* Insert this node at the end of the list */
5481708Sstevel 	pnode->sibling = NULL;
5491708Sstevel 	if (bnode->nodes == NULL)
5501708Sstevel 		bnode->nodes = pnode;
5511708Sstevel 	else {
5521708Sstevel 		p = bnode->nodes;
5531708Sstevel 		while (p->sibling != NULL)
5541708Sstevel 			p = p->sibling;
5551708Sstevel 		p->sibling = pnode;
5561708Sstevel 	}
5571708Sstevel }
5581708Sstevel 
5591708Sstevel 
5601708Sstevel 
5611708Sstevel /*
5621708Sstevel  * Print out all the io cards in the list.  Also print the column
5631708Sstevel  * headers if told to do so.
5641708Sstevel  */
5651708Sstevel void
display_io_cards(struct io_card * list)5661708Sstevel display_io_cards(struct io_card *list)
5671708Sstevel {
5681708Sstevel 	char	*hdrfmt = "%-10.10s  %-4.4s %-4.4s %-4.4s %-4.4s %-4.4s"
569*5889Szk194757 	    " %-4.4s %-5.5s %-32.32s  %-22.22s"
5701708Sstevel #ifdef	DEBUG
571*5889Szk194757 	    "  %-22.22s"
5721708Sstevel #endif	/* DEBUG */
573*5889Szk194757 	    "\n";
5741708Sstevel 
5751708Sstevel 	static int banner = FALSE; /* Have we printed the column headings? */
5761708Sstevel 	struct io_card *p;
5771708Sstevel 
5781708Sstevel 	if (list == NULL)
5791708Sstevel 		return;
5801708Sstevel 
5811708Sstevel 	(void) textdomain(TEXT_DOMAIN);
5821708Sstevel 
5831708Sstevel 	if (banner == FALSE) {
5841708Sstevel 		log_printf(hdrfmt,
5851708Sstevel 		    "", "", "", "",
5861708Sstevel 		    gettext("Bus"),
5871708Sstevel 		    gettext("Max"),
5881708Sstevel 		    "", "", "", "",
5891708Sstevel #ifdef	DEBUG
5901708Sstevel 		    "",
5911708Sstevel #endif	/* DEBUG */
5921708Sstevel 		    0);
5931708Sstevel 
5941708Sstevel 		log_printf(hdrfmt,
5951708Sstevel 		    "",
5961708Sstevel 		    gettext("IO"),
5971708Sstevel 		    gettext("Port"),
5981708Sstevel 		    gettext("Bus"),
5991708Sstevel 		    gettext("Freq"),
6001708Sstevel 		    gettext("Bus"),
6011708Sstevel 		    gettext("Dev,"),
6021708Sstevel 		    "", "", "",
6031708Sstevel #ifdef	DEBUG
6041708Sstevel 		    "",
6051708Sstevel #endif	/* DEBUG */
6061708Sstevel 		    0);
6071708Sstevel 
6081708Sstevel 		log_printf(hdrfmt,
6091708Sstevel 		    gettext("Slot ID"),
6101708Sstevel 		    gettext("Type"),
6111708Sstevel 		    gettext(" ID"),
6121708Sstevel 		    gettext("Side"),
6131708Sstevel 		    gettext("MHz"),
6141708Sstevel 		    gettext("Freq"),
6151708Sstevel 		    gettext("Func"),
6161708Sstevel 		    gettext("State"),
6171708Sstevel 		    gettext("Name"),
6181708Sstevel 		    gettext("Model"),
6191708Sstevel #ifdef	DEBUG
6201708Sstevel 		    gettext("Notes"),
6211708Sstevel #endif	/* DEBUG */
6221708Sstevel 		    0);
6231708Sstevel 
6241708Sstevel 		log_printf(hdrfmt,
6251708Sstevel 		    "----------", "----", "----", "----", "----", "----",
6261708Sstevel 		    "----", "-----", "--------------------------------",
6271708Sstevel 		    "----------------------",
6281708Sstevel #ifdef	DEBUG
6291708Sstevel 		    "----------------------",
6301708Sstevel #endif	/* DEBUG */
6311708Sstevel 		    0);
6321708Sstevel 
6331708Sstevel 		banner = TRUE;
6341708Sstevel 	}
6351708Sstevel 
6361708Sstevel 	for (p = list; p != NULL; p = p -> next) {
6371708Sstevel 
6381708Sstevel 		display_io_slot_info(p);
6391708Sstevel 
6401708Sstevel 		display_io_max_bus_speed(p);
6411708Sstevel 
6421708Sstevel 		log_printf("\n", 0);
6431708Sstevel 	}
6441708Sstevel }
6451708Sstevel 
6461708Sstevel 
6471708Sstevel static void
display_io_slot_info(struct io_card * p)6481708Sstevel display_io_slot_info(struct io_card *p)
6491708Sstevel {
6501708Sstevel 	/*
6511708Sstevel 	 * Onboard devices are distinguished by Slot IDs that
6521708Sstevel 	 * indicate only the I/O board.  Plug-in cards indicate
6531708Sstevel 	 * their leaf and Schizo.
6541708Sstevel 	 */
6551708Sstevel 
6561708Sstevel 	if (p->slot_str[0] == '-') {
6571708Sstevel 		log_printf("/%-2s%02d       ",
658*5889Szk194757 		    SC_BOARD_TYPE(p->board),
659*5889Szk194757 		    PORTID_TO_EXPANDER(p->board), 0);
6601708Sstevel 	} else {
6611708Sstevel 		char	c;
6621708Sstevel 		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
6631708Sstevel 			log_printf("/%-2s%02d/%s  ",
664*5889Szk194757 			    SC_BOARD_TYPE(p->board),
665*5889Szk194757 			    PORTID_TO_EXPANDER(p->board),
666*5889Szk194757 			    p->slot_str, 0);
6671708Sstevel 		} else {
6681708Sstevel 			if (p->pci_bus == 'A')
6691708Sstevel 				c = '3';
6701708Sstevel 			else if (p->pci_bus == 'B') {
6711708Sstevel 				c = '5';
6721708Sstevel 			} else
6731708Sstevel 				c = '-';
6741708Sstevel 			log_printf("/%-2s%02d/C%cV%1d  ",
675*5889Szk194757 			    SC_BOARD_TYPE(p->board),
676*5889Szk194757 			    PORTID_TO_EXPANDER(p->board), c,
677*5889Szk194757 			    PORTID_TO_INSTANCE(p->schizo_portid),
678*5889Szk194757 			    0);
6791708Sstevel 		}
6801708Sstevel 	}
6811708Sstevel 	log_printf("%-4.4s ", gettext(p->bus_type), 0);
6821708Sstevel 	log_printf("%3d  ", p->schizo_portid, 0);
6831708Sstevel 	log_printf(" %c  ", p->pci_bus, 0);
6841708Sstevel 	log_printf(" %3d  ", p->freq, 0);
6851708Sstevel }
6861708Sstevel 
6871708Sstevel #define	BUS_SPEED_PRINT(speed)	log_printf(" %d  ", speed, 0)
6881708Sstevel 
6891708Sstevel static void
display_io_max_bus_speed(struct io_card * p)6901708Sstevel display_io_max_bus_speed(struct io_card *p)
6911708Sstevel {
6921708Sstevel 	int speed = board_bus_max_freq;
6931708Sstevel 
6941708Sstevel 	switch (p->pci_bus) {
6951708Sstevel 	case 'A':
6961708Sstevel 		BUS_SPEED_PRINT(speed);
6971708Sstevel 		break;
6981708Sstevel 	case 'B':
6991708Sstevel 		if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
7001708Sstevel 			if (PORTID_TO_INSTANCE(p->schizo_portid) == 0)
7011708Sstevel 				BUS_SPEED_PRINT(33);
7021708Sstevel 			else
7031708Sstevel 				BUS_SPEED_PRINT(speed);
7041708Sstevel 		} else
7051708Sstevel 			BUS_SPEED_PRINT(33);
7061708Sstevel 		break;
7071708Sstevel 	default:
7081708Sstevel 		log_printf("  -  ", 0);
7091708Sstevel 		break;
7101708Sstevel 	}
7111708Sstevel 
7121708Sstevel 	log_printf("%-1d,%-1d  ", p->dev_no, p->func_no, 0);
7131708Sstevel 	log_printf("%-5.5s ", gettext(p->status), 0);
7141708Sstevel 	log_printf("%-32.32s%c ", p->name,
715*5889Szk194757 	    ((strlen(p->name) > 32) ? '+' : ' '), 0);
7161708Sstevel 	log_printf("%-22.22s%c", p->model,
717*5889Szk194757 	    ((strlen(p->model) > 22) ? '+' : ' '), 0);
7181708Sstevel #ifdef	DEBUG
7191708Sstevel 	log_printf(" %s", p->notes, 0);
7201708Sstevel #endif	/* DEBUG */
7211708Sstevel }
7221708Sstevel 
7231708Sstevel void
display_cpu_devices(Sys_tree * tree)7241708Sstevel display_cpu_devices(Sys_tree *tree)
7251708Sstevel {
7261708Sstevel 	Board_node *bnode;
7271708Sstevel 	char	*hdrfmt = "%-8.8s  %-7.7s  %-4.4s  %-4.4s  %-7.7s  %-4.4s\n";
7281708Sstevel 
7291708Sstevel 	(void) textdomain(TEXT_DOMAIN);
7301708Sstevel 
7311708Sstevel 	/*
7321708Sstevel 	 * Display the table header for CPUs . Then display the CPU
7331708Sstevel 	 * frequency, cache size, and processor revision of all cpus.
7341708Sstevel 	 */
7351708Sstevel 	log_printf("\n", 0);
7361708Sstevel 	log_printf("=========================", 0);
7371708Sstevel 	log_printf(gettext(" CPUs "), 0);
7381708Sstevel 	log_printf("=========================", 0);
7391708Sstevel 	log_printf("\n\n", 0);
7401708Sstevel 
7411708Sstevel 	log_printf(hdrfmt,
7421708Sstevel 	    "",
7431708Sstevel 	    gettext("CPU "),
7441708Sstevel 	    gettext("Run"),
7451708Sstevel 	    gettext(" E$"),
7461708Sstevel 	    gettext(" CPU"),
7471708Sstevel 	    gettext("CPU"), 0);
7481708Sstevel 
7491708Sstevel 	log_printf(hdrfmt,
7501708Sstevel 	    gettext("Slot ID"),
7511708Sstevel 	    gettext("ID "),
7521708Sstevel 	    gettext("MHz"),
7531708Sstevel 	    gettext(" MB"),
7541708Sstevel 	    gettext("Impl."),
7551708Sstevel 	    gettext("Mask"), 0);
7561708Sstevel 
7571708Sstevel 	log_printf(hdrfmt,
7581708Sstevel 	    "--------", "-------", "----", "----", "-------",  "----", 0);
7591708Sstevel 
7601708Sstevel 	/* Now display all of the cpus on each board */
7611708Sstevel 	bnode = tree->bd_list;
7621708Sstevel 	while (bnode != NULL) {
7631708Sstevel 		display_cpus(bnode);
7641708Sstevel 		bnode = bnode->next;
7651708Sstevel 	}
7661708Sstevel 
7671708Sstevel 	log_printf("\n", 0);
7681708Sstevel }
7691708Sstevel 
7701708Sstevel /*
7711708Sstevel  * Display the CPUs present on this board.
7721708Sstevel  */
7731708Sstevel void
display_cpus(Board_node * board)7741708Sstevel display_cpus(Board_node *board)
7751708Sstevel {
7761708Sstevel 	Prom_node *cpu;
777*5889Szk194757 	uint_t freq;		/* CPU clock frequency */
7781708Sstevel 	int ecache_size;	/* External cache size */
7791708Sstevel 	int *impl;
7801708Sstevel 	int *mask;
7811708Sstevel 	int decoded_mask;
7821708Sstevel 	int *cpuid;
7831708Sstevel 	int *coreid;
7841708Sstevel 	int cpuid_prev = -1;
7851708Sstevel 	int ecache_size_prev = 0;
7861708Sstevel 
7871708Sstevel 	(void) textdomain(TEXT_DOMAIN);
7881708Sstevel 	/*
7891708Sstevel 	 * display the CPUs' operating frequency, cache size, impl. field
7901708Sstevel 	 * and mask revision.
7911708Sstevel 	 */
7921708Sstevel 	for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
7931708Sstevel 	    cpu = dev_next_type(cpu, "cpu")) {
7941708Sstevel 
7951708Sstevel 		freq = HZ_TO_MHZ(get_cpu_freq(cpu));
7961708Sstevel 		ecache_size = get_ecache_size(cpu);
7971708Sstevel 		impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
7981708Sstevel 		mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
7991708Sstevel 		cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
8001708Sstevel 		if (cpuid == NULL)
8011708Sstevel 			cpuid = &board->board_num;
8021708Sstevel 
8031708Sstevel 		/* Do not display a failed CPU node */
8041708Sstevel 		if ((freq == 0) || (impl == 0) || (node_failed(cpu)))
8051708Sstevel 			continue;
8061708Sstevel 
8071708Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
8081708Sstevel 			coreid = (int *)get_prop_val(find_prop(cpu,
809*5889Szk194757 			    "reg"));
8101708Sstevel 			if (coreid == NULL) {
8111708Sstevel 				continue;
8121708Sstevel 			}
8131708Sstevel 
8141708Sstevel 			/*
8151708Sstevel 			 * The assumption is made that 2 cores will always be
8161708Sstevel 			 * listed together in the device tree. If either core
8171708Sstevel 			 * is "bad" then the FRU will not be listed.
8181708Sstevel 			 */
8191708Sstevel 			if (cpuid_prev == -1) {
8201708Sstevel 				cpuid_prev = *cpuid;
8211708Sstevel 				ecache_size_prev = ecache_size;
8221708Sstevel 				continue;
8231708Sstevel 			} else {
8241708Sstevel 				/*
8251708Sstevel 				 * Jaguar has a split E$, so the size for both
8261708Sstevel 				 * cores must be added together to get the total
8271708Sstevel 				 * size for the entire chip.
8281708Sstevel 				 *
8291708Sstevel 				 * Panther E$ (L3) is logically shared, so the
8301708Sstevel 				 * total size is equal to the core size.
8311708Sstevel 				 */
8321708Sstevel 				if (IS_JAGUAR(*impl)) {
8331708Sstevel 					ecache_size += ecache_size_prev;
8341708Sstevel 				}
8351708Sstevel 
8361708Sstevel 				ecache_size_prev = 0;
8371708Sstevel 			}
8381708Sstevel 		}
8391708Sstevel 
8401708Sstevel 		/*
8411708Sstevel 		 * Print out cpu data.
8421708Sstevel 		 *
8431708Sstevel 		 * Slot ID
8441708Sstevel 		 */
8451708Sstevel 		log_printf("/%-2s%02d/P%1d  ",
8461708Sstevel 		    SC_BOARD_TYPE(*cpuid),
8471708Sstevel 		    PORTID_TO_EXPANDER(*cpuid),
8481708Sstevel 		    PORTID_TO_INSTANCE(*cpuid), 0);
8491708Sstevel 
8501708Sstevel 		/* CPU ID */
8511708Sstevel 		if (CPU_IMPL_IS_CMP(*impl)) {
8521708Sstevel 			log_printf("%3d,%3d  ", cpuid_prev,
8531708Sstevel 			    *cpuid, 0);
8541708Sstevel 			cpuid_prev = -1;
8551708Sstevel 		} else
8561708Sstevel 			log_printf("%3d      ", *cpuid, 0);
8571708Sstevel 
8581708Sstevel 		/* Running frequency */
859*5889Szk194757 		log_printf("%4u  ", freq, 0);
8601708Sstevel 
8611708Sstevel 		/* Ecache size */
8621708Sstevel 		if (ecache_size == 0)
8631708Sstevel 			log_printf("%-4.4s  ", gettext("N/A"), 0);
8641708Sstevel 		else
8651708Sstevel 			log_printf("%4.1f  ",
866*5889Szk194757 			    (float)ecache_size / (float)(1<<20),
867*5889Szk194757 			    0);
8681708Sstevel 
8691708Sstevel 		/* Implementation */
8701708Sstevel 		switch (*impl) {
8711708Sstevel 		case CHEETAH_IMPL:
8721708Sstevel 			log_printf("%-7.7s  ",
873*5889Szk194757 			    gettext("US-III"), 0);
8741708Sstevel 			break;
8751708Sstevel 		case CHEETAH_PLUS_IMPL:
8761708Sstevel 			log_printf("%-7.7s  ",
877*5889Szk194757 			    gettext("US-III+"), 0);
8781708Sstevel 			break;
8791708Sstevel 		case JAGUAR_IMPL:
8801708Sstevel 			log_printf("%-7.7s  ",
881*5889Szk194757 			    gettext("US-IV"), 0);
8821708Sstevel 			break;
8831708Sstevel 		case PANTHER_IMPL:
8841708Sstevel 			log_printf("%-7.7s  ",
885*5889Szk194757 			    gettext("US-IV+"), 0);
8861708Sstevel 			break;
8871708Sstevel 		default:
8881708Sstevel 			log_printf("%-7x  ", *impl, 0);
8891708Sstevel 			break;
8901708Sstevel 		}
8911708Sstevel 
8921708Sstevel 		/* CPU Mask */
8931708Sstevel 		if (mask == NULL) {
8941708Sstevel 			log_printf("%-4.4s", gettext("N/A"), 0);
8951708Sstevel 		} else {
8961708Sstevel 			if (IS_CHEETAH(*impl))
8971708Sstevel 				decoded_mask = REMAP_CHEETAH_MASK(*mask);
8981708Sstevel 			else
8991708Sstevel 				decoded_mask = *mask;
9001708Sstevel 
9011708Sstevel 			log_printf("%d.%d",
902*5889Szk194757 			    (decoded_mask >> 4) & 0xf,
903*5889Szk194757 			    decoded_mask & 0xf, 0);
9041708Sstevel 		}
9051708Sstevel 
9061708Sstevel 		log_printf("\n", 0);
9071708Sstevel 	}
9081708Sstevel }
9091708Sstevel 
9101708Sstevel 
9111708Sstevel /*ARGSUSED1*/
9121708Sstevel void
display_memoryconf(Sys_tree * tree,struct grp_info * grps)9131708Sstevel display_memoryconf(Sys_tree *tree, struct grp_info *grps)
9141708Sstevel {
9151708Sstevel 	Board_node	*bnode = tree->bd_list;
9161708Sstevel 	char	*hdrfmt = "\n%-11.11s  %-4.4s  %-7.7s  %-7.7s  %-8.8s  %-6.6s"
917*5889Szk194757 	    "  %-10.10s  %-10.10s";
9181708Sstevel 
9191708Sstevel 	(void) textdomain(TEXT_DOMAIN);
9201708Sstevel 
9211708Sstevel 	log_printf("=========================", 0);
9221708Sstevel 	log_printf(gettext(" Memory Configuration "), 0);
9231708Sstevel 	log_printf("=========================", 0);
9241708Sstevel 	log_printf("\n", 0);
9251708Sstevel 
9261708Sstevel 	log_printf(hdrfmt,
9271708Sstevel 	    "", "",
9281708Sstevel 	    gettext("Logical"),
9291708Sstevel 	    gettext("Logical"),
9301708Sstevel 	    gettext("Logical"),
9311708Sstevel 	    "", "", "", 0);
9321708Sstevel 
9331708Sstevel 	log_printf(hdrfmt,
9341708Sstevel 	    "",
9351708Sstevel 	    gettext("Port"),
9361708Sstevel 	    gettext("Bank"),
9371708Sstevel 	    gettext("Bank"),
9381708Sstevel 	    gettext("Bank"),
9391708Sstevel 	    gettext(" DIMM"),
9401708Sstevel 	    gettext("Interleave"),
9411708Sstevel 	    gettext("Interleave"), 0);
9421708Sstevel 
9431708Sstevel 	log_printf(hdrfmt,
9441708Sstevel 	    gettext("Slot ID"),
9451708Sstevel 	    gettext(" ID"),
9461708Sstevel 	    gettext("Number"),
9471708Sstevel 	    gettext("Size"),
9481708Sstevel 	    gettext("Status"),
9491708Sstevel 	    gettext(" Size"),
9501708Sstevel 	    gettext("Factor"),
9511708Sstevel 	    gettext("Segment"), 0);
9521708Sstevel 
9531708Sstevel 	log_printf(hdrfmt,
9541708Sstevel 	    "-----------", "----", "-------", "-------", "--------",
9551708Sstevel 	    "------", "----------", "----------", 0);
9561708Sstevel 
9571708Sstevel 	while (bnode != NULL) {
9581708Sstevel 		if (get_us3_mem_regs(bnode)) {
9591708Sstevel 			log_printf(
960*5889Szk194757 			    gettext(
961*5889Szk194757 			    "\nFailed to get memory information.\n"),
962*5889Szk194757 			    0);
9631708Sstevel 			return;
9641708Sstevel 		}
9651708Sstevel 		bnode = bnode->next;
9661708Sstevel 	}
9671708Sstevel 
9681708Sstevel 	/* Display what we have found */
9691708Sstevel 	display_us3_banks();
9701708Sstevel }
9711708Sstevel 
9721708Sstevel 
9731708Sstevel /*
9741708Sstevel  * This function provides Starcat's formatting of the memory config
9751708Sstevel  * information that get_us3_mem_regs() and display_us3_banks() code has
9761708Sstevel  * gathered. It overrides the generic print_us3_memory_line() code
9771708Sstevel  * which prints an error message.
9781708Sstevel  */
9791708Sstevel 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)9801708Sstevel print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
9811708Sstevel 	char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
9821708Sstevel {
9831708Sstevel 	(void) textdomain(TEXT_DOMAIN);
9841708Sstevel 
9851708Sstevel 	/* Slot ID */
9861708Sstevel 	log_printf("\n/%-2s%02d/P%1d/B%1d  ",
9871708Sstevel 	    SC_BOARD_TYPE(portid), PORTID_TO_EXPANDER(portid),
9881708Sstevel 	    PORTID_TO_INSTANCE(portid), (bank_id & 0x1), 0);
9891708Sstevel 
9901708Sstevel 	/* Port ID */
9911708Sstevel 	log_printf("%3d   ", portid, 0);
9921708Sstevel 
9931708Sstevel 	/* Logical Bank Number */
9941708Sstevel 	log_printf("   %1d     ", (bank_id & 0x3), 0);
9951708Sstevel 
9961708Sstevel 	/* Logical Bank Size */
9971708Sstevel 	log_printf("%4lldMB   ", bank_size, 0);
9981708Sstevel 
9991708Sstevel 	/* Logical Bank Status */
10001708Sstevel 	log_printf("%-8.8s  ", gettext(bank_status), 0);
10011708Sstevel 
10021708Sstevel 	/* DIMM Size */
10031708Sstevel 	log_printf("%4lldMB  ", dimm_size, 0);
10041708Sstevel 
10051708Sstevel 	/* Interleave Factor */
10061708Sstevel 	log_printf("  %2d-%-3.3s    ", intlv, gettext("way"), 0);
10071708Sstevel 
10081708Sstevel 	/* Interleave Segment */
10091708Sstevel 	log_printf("   %3d", seg_id, 0);
10101708Sstevel }
10111708Sstevel 
10121708Sstevel /*ARGSUSED2*/
10131708Sstevel void
display_diaginfo(int flag,Prom_node * root,Sys_tree * tree,struct system_kstat_data * kstats)10141708Sstevel display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
10151708Sstevel 	struct system_kstat_data *kstats)
10161708Sstevel {
10171708Sstevel 	if (flag) {
10181708Sstevel 		/*
10191708Sstevel 		 * display time of latest powerfail. Not all systems
10201708Sstevel 		 * have this capability. For those that do not, this
10211708Sstevel 		 * is just a no-op.
10221708Sstevel 		 */
10231708Sstevel 		disp_powerfail(root);
10241708Sstevel 
10251708Sstevel 		(void) textdomain(TEXT_DOMAIN);
10261708Sstevel 
10271708Sstevel 		/* Print the header */
10281708Sstevel 		log_printf("\n", 0);
10291708Sstevel 		log_printf("=========================", 0);
10301708Sstevel 		log_printf(gettext(" Diagnostic Information "), 0);
10311708Sstevel 		log_printf("=========================", 0);
10321708Sstevel 		log_printf("\n\n", 0);
10331708Sstevel 		log_printf(gettext("For diagnostic information,"), 0);
10341708Sstevel 		log_printf("\n", 0);
10351708Sstevel 		log_printf(gettext(
1036*5889Szk194757 		    "see /var/opt/SUNWSMS/adm/[A-R]/messages on the SC."),
1037*5889Szk194757 		    0);
10381708Sstevel 		log_printf("\n", 0);
10391708Sstevel 
10401708Sstevel 		/* Print the PROM revisions here */
10411708Sstevel 		starcat_disp_hw_revisions(root);
10421708Sstevel 	}
10431708Sstevel }
10441708Sstevel 
10451708Sstevel /*
10461708Sstevel  * local functions -  functions that are only needed inside this library
10471708Sstevel  */
10481708Sstevel 
10491708Sstevel static void
starcat_disp_hw_revisions(Prom_node * root)10501708Sstevel starcat_disp_hw_revisions(Prom_node *root)
10511708Sstevel {
10521708Sstevel 	Prom_node	*pnode;
10531708Sstevel 	char		*version;
10541708Sstevel 
10551708Sstevel 	(void) textdomain(TEXT_DOMAIN);
10561708Sstevel 
10571708Sstevel 	/* Print the header */
10581708Sstevel 	log_printf("\n", 0);
10591708Sstevel 	log_printf("=========================", 0);
10601708Sstevel 	log_printf(gettext(" Hardware Revisions "), 0);
10611708Sstevel 	log_printf("=========================", 0);
10621708Sstevel 	log_printf("\n\n", 0);
10631708Sstevel 
10641708Sstevel 	/* Display Prom revision header */
10651708Sstevel 	log_printf(gettext("OpenBoot firmware revision:"), 0);
10661708Sstevel 	log_printf("\n---------------------------\n", 0);
10671708Sstevel 
10681708Sstevel 	/*
10691708Sstevel 	 * Display OBP version info
10701708Sstevel 	 */
10711708Sstevel 	pnode = dev_find_node(root, "openprom");
10721708Sstevel 	if (pnode != NULL) {
10731708Sstevel 		version = (char *)get_prop_val(find_prop(pnode, "version"));
10741708Sstevel 		log_printf("%s\n\n", version, 0);
10751708Sstevel 	}
10761708Sstevel }
10771708Sstevel 
10781708Sstevel /*
10791708Sstevel  * We call do_devinfo() in order to use the libdevinfo device tree
10801708Sstevel  * instead of OBP's device tree.
10811708Sstevel  */
10821708Sstevel int
do_prominfo(int syserrlog,char * pgname,int log_flag,int prt_flag)10831708Sstevel do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
10841708Sstevel {
10851708Sstevel 
10861708Sstevel 	return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
10871708Sstevel 
10881708Sstevel }
10891708Sstevel 
10901708Sstevel /*
10911708Sstevel  * return the property value for the Prop
10921708Sstevel  * passed in. (When using libdevinfo)
10931708Sstevel  */
10941708Sstevel void *
get_prop_val(Prop * prop)10951708Sstevel get_prop_val(Prop *prop)
10961708Sstevel {
10971708Sstevel 	if (prop == NULL)
10981708Sstevel 		return (NULL);
10991708Sstevel 
11001708Sstevel 	return ((void *)(prop->value.val_ptr));
11011708Sstevel }
11021708Sstevel 
11031708Sstevel /*
11041708Sstevel  * Search a Prom node and retrieve the property with the correct
11051708Sstevel  * name. (When using libdevinfo)
11061708Sstevel  */
11071708Sstevel Prop *
find_prop(Prom_node * pnode,char * name)11081708Sstevel find_prop(Prom_node *pnode, char *name)
11091708Sstevel {
11101708Sstevel 	Prop *prop;
11111708Sstevel 
11121708Sstevel 	if (pnode == NULL)
11131708Sstevel 		return (NULL);
11141708Sstevel 
11151708Sstevel 	for (prop = pnode->props; prop != NULL; prop = prop->next) {
11161708Sstevel 		if (prop->name.val_ptr != NULL &&
11171708Sstevel 		    strcmp((char *)(prop->name.val_ptr), name) == 0)
11181708Sstevel 			break;
11191708Sstevel 	}
11201708Sstevel 
11211708Sstevel 	return (prop);
11221708Sstevel }
11231708Sstevel 
11241708Sstevel /*
11251708Sstevel  * This function searches through the properties of the node passed in
11261708Sstevel  * and returns a pointer to the value of the name property.
11271708Sstevel  * (When using libdevinfo)
11281708Sstevel  */
11291708Sstevel char *
get_node_name(Prom_node * pnode)11301708Sstevel get_node_name(Prom_node *pnode)
11311708Sstevel {
11321708Sstevel 	Prop *prop;
11331708Sstevel 
11341708Sstevel 	if (pnode == NULL) {
11351708Sstevel 		return (NULL);
11361708Sstevel 	}
11371708Sstevel 
11381708Sstevel 	prop = pnode->props;
11391708Sstevel 	while (prop != NULL) {
11401708Sstevel 		if (strcmp("name", (char *)prop->name.val_ptr) == 0)
11411708Sstevel 			return (prop->value.val_ptr);
11421708Sstevel 		prop = prop->next;
11431708Sstevel 	}
11441708Sstevel 	return (NULL);
11451708Sstevel }
11461708Sstevel 
11471708Sstevel /*
11481708Sstevel  * This function searches through the properties of the node passed in
11491708Sstevel  * and returns a pointer to the value of the device_type property.
11501708Sstevel  * (When using libdevinfo)
11511708Sstevel  */
11521708Sstevel char *
get_node_type(Prom_node * pnode)11531708Sstevel get_node_type(Prom_node *pnode)
11541708Sstevel {
11551708Sstevel 	Prop *prop;
11561708Sstevel 
11571708Sstevel 	if (pnode == NULL) {
11581708Sstevel 		return (NULL);
11591708Sstevel 	}
11601708Sstevel 
11611708Sstevel 	prop = pnode->props;
11621708Sstevel 	while (prop != NULL) {
11631708Sstevel 		if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
11641708Sstevel 			return (prop->value.val_ptr);
11651708Sstevel 		prop = prop->next;
11661708Sstevel 	}
11671708Sstevel 	return (NULL);
11681708Sstevel }
1169