xref: /onnv-gate/usr/src/lib/libprtdiag/common/display_sun4v.c (revision 13019:b11dd158cab1)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
53941Svenki  * Common Development and Distribution License (the "License").
63941Svenki  * 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 /*
2212046SMichael.Bergknoff@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
231708Sstevel  */
241708Sstevel 
251708Sstevel #include <stdio.h>
261708Sstevel #include <stdlib.h>
275436Sfw157321 #include <alloca.h>
281708Sstevel #include <unistd.h>
291708Sstevel #include <ctype.h>
301708Sstevel #include <string.h>
311708Sstevel #include <kvm.h>
321708Sstevel #include <varargs.h>
331708Sstevel #include <time.h>
341708Sstevel #include <dirent.h>
351708Sstevel #include <fcntl.h>
361708Sstevel #include <sys/param.h>
371708Sstevel #include <sys/stat.h>
381708Sstevel #include <sys/types.h>
391708Sstevel #include <sys/utsname.h>
401708Sstevel #include <sys/openpromio.h>
411708Sstevel #include <libintl.h>
421708Sstevel #include <syslog.h>
431708Sstevel #include <sys/dkio.h>
443941Svenki #include <sys/systeminfo.h>
453941Svenki #include <picldefs.h>
464802Sfw157321 #include <math.h>
474802Sfw157321 #include <errno.h>
481708Sstevel #include "pdevinfo.h"
491708Sstevel #include "display.h"
501708Sstevel #include "display_sun4v.h"
511708Sstevel #include "libprtdiag.h"
521708Sstevel 
531708Sstevel #if !defined(TEXT_DOMAIN)
541708Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
551708Sstevel #endif
561708Sstevel 
574669Sfw157321 #define	MOTHERBOARD			"MB"
583941Svenki #define	NETWORK				"network"
593941Svenki #define	SUN4V_MACHINE			"sun4v"
603941Svenki #define	PARENT_NAMES			10
613941Svenki 
623941Svenki /*
633941Svenki  * Additional OBP properties
643941Svenki  */
653941Svenki #define	OBP_PROP_COMPATIBLE		"compatible"
663941Svenki #define	OBP_PROP_MODEL			"model"
673941Svenki #define	OBP_PROP_SLOT_NAMES		"slot-names"
685436Sfw157321 #define	OBP_PROP_VERSION		"version"
693941Svenki 
703941Svenki #define	PICL_NODE_PHYSICAL_PLATFORM	"physical-platform"
713941Svenki #define	PICL_NODE_CHASSIS		"chassis"
723941Svenki #define	MEMORY_SIZE_FIELD		11
733941Svenki #define	INVALID_THRESHOLD		1000000
743941Svenki 
753941Svenki /*
763941Svenki  * Additional picl classes
773941Svenki  */
783941Svenki #ifndef	PICL_CLASS_SUN4V
793941Svenki #define	PICL_CLASS_SUN4V		"sun4v"
803941Svenki #endif
813941Svenki 
823941Svenki #ifndef	PICL_PROP_NAC
833941Svenki #define	PICL_PROP_NAC			"nac"
843941Svenki #endif
853941Svenki 
863941Svenki extern int sys_clk;
873941Svenki extern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *,
883941Svenki 	picl_nodehdl_t *);
893941Svenki 
903941Svenki static picl_nodehdl_t rooth = 0, phyplatformh = 0;
913941Svenki static picl_nodehdl_t chassish = 0;
923941Svenki static int class_node_found;
933941Svenki static int syserrlog;
943941Svenki static int all_status_ok;
953941Svenki 
963941Svenki /* local functions */
973941Svenki static int sun4v_get_first_compatible_value(picl_nodehdl_t, char **);
983941Svenki static void sun4v_display_memory_conf(picl_nodehdl_t);
995547Smb158278 static int sun4v_disp_env_status();
1003941Svenki static void sun4v_env_print_fan_sensors();
1013941Svenki static void sun4v_env_print_fan_indicators();
1023941Svenki static void sun4v_env_print_temp_sensors();
1033941Svenki static void sun4v_env_print_temp_indicators();
1043941Svenki static void sun4v_env_print_current_sensors();
1053941Svenki static void sun4v_env_print_current_indicators();
1063941Svenki static void sun4v_env_print_voltage_sensors();
1073941Svenki static void sun4v_env_print_voltage_indicators();
1083941Svenki static void sun4v_env_print_LEDs();
1093941Svenki static void sun4v_print_fru_status();
11010070SBirva.Shah@Sun.COM static int is_fru_absent(picl_nodehdl_t);
1113941Svenki static void sun4v_print_fw_rev();
1123941Svenki static void sun4v_print_chassis_serial_no();
1135436Sfw157321 static int openprom_callback(picl_nodehdl_t openpromh, void *arg);
1145436Sfw157321 static void sun4v_print_openprom_rev();
1151708Sstevel 
1161708Sstevel int
sun4v_display(Sys_tree * tree,Prom_node * root,int log,picl_nodehdl_t plafh)1173941Svenki sun4v_display(Sys_tree *tree, Prom_node *root, int log,
1183941Svenki 	picl_nodehdl_t plafh)
1191708Sstevel {
1201708Sstevel 	void *value;		/* used for opaque PROM data */
1211708Sstevel 	struct mem_total memory_total;	/* Total memory in system */
1221708Sstevel 	struct grp_info grps;	/* Info on all groups in system */
1233941Svenki 	char machine[MAXSTRLEN];
1245547Smb158278 	int	exit_code = 0;
1253941Svenki 
1263941Svenki 	if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1)
1273941Svenki 		return (1);
1283941Svenki 	if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0)
1293941Svenki 		return (1);
1301708Sstevel 
1311708Sstevel 	sys_clk = -1;  /* System clock freq. (in MHz) */
1321708Sstevel 
1331708Sstevel 	/*
1341708Sstevel 	 * Now display the machine's configuration. We do this if we
1351708Sstevel 	 * are not logging.
1361708Sstevel 	 */
1371708Sstevel 	if (!logging) {
1381708Sstevel 		struct utsname uts_buf;
1391708Sstevel 
1401708Sstevel 		/*
1411708Sstevel 		 * Display system banner
1421708Sstevel 		 */
1431708Sstevel 		(void) uname(&uts_buf);
1441708Sstevel 
1453941Svenki 		log_printf(dgettext(TEXT_DOMAIN, "System Configuration:  "
146*13019SMichael.Bergknoff@Oracle.COM 		    "Oracle Corporation  %s %s\n"), uts_buf.machine,
1474669Sfw157321 		    get_prop_val(find_prop(root, "banner-name")), 0);
1481708Sstevel 
1491708Sstevel 		/* display system clock frequency */
1501708Sstevel 		value = get_prop_val(find_prop(root, "clock-frequency"));
1511708Sstevel 		if (value != NULL) {
1521708Sstevel 			sys_clk = ((*((int *)value)) + 500000) / 1000000;
1531708Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "System clock "
1544669Sfw157321 			    "frequency: %d MHz\n"), sys_clk, 0);
1551708Sstevel 		}
1561708Sstevel 
1571708Sstevel 		/* Display the Memory Size */
1581708Sstevel 		display_memorysize(tree, NULL, &grps, &memory_total);
1591708Sstevel 
1601708Sstevel 		/* Display the CPU devices */
1611708Sstevel 		sun4v_display_cpu_devices(plafh);
1621708Sstevel 
1631708Sstevel 		/* Display the Memory configuration */
1643941Svenki 		class_node_found = 0;
1653941Svenki 		sun4v_display_memory_conf(plafh);
1661708Sstevel 
1671708Sstevel 		/* Display all the IO cards. */
1681708Sstevel 		(void) sun4v_display_pci(plafh);
1693941Svenki 		sun4v_display_diaginfo((log || (logging)), root, plafh);
1701708Sstevel 
1713941Svenki 		if (picl_get_root(&rooth) != PICL_SUCCESS)
1723941Svenki 			return (1);
1735547Smb158278 
1745547Smb158278 		/*
1755547Smb158278 		 * The physical-platform node may be missing on systems with
1765547Smb158278 		 * older firmware so don't consider that an error.
1775547Smb158278 		 */
1783941Svenki 		if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM,
1794669Sfw157321 		    &phyplatformh) != PICL_SUCCESS)
1805547Smb158278 			return (0);
1813941Svenki 
1823941Svenki 		if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME,
1834669Sfw157321 		    PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS,
1844669Sfw157321 		    strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS)
1853941Svenki 			return (1);
1863941Svenki 
1873941Svenki 		syserrlog = log;
1885547Smb158278 		exit_code = sun4v_disp_env_status();
1893941Svenki 	}
1905547Smb158278 	return (exit_code);
1913941Svenki }
1923941Svenki 
1935819Sfw157321 /*
1945819Sfw157321  * The binding-name property encodes the bus type.
1955819Sfw157321  */
1963941Svenki static void
get_bus_type(picl_nodehdl_t nodeh,struct io_card * card)1973941Svenki get_bus_type(picl_nodehdl_t nodeh, struct io_card *card)
1983941Svenki {
1995819Sfw157321 	char val[PICL_PROPNAMELEN_MAX], *p, *q;
2005819Sfw157321 
2015819Sfw157321 	card->bus_type[0] = '\0';
2023941Svenki 
2035819Sfw157321 	if (picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, val,
2045819Sfw157321 	    sizeof (val)) == PICL_SUCCESS) {
2055819Sfw157321 		if (strstr(val, PICL_CLASS_PCIEX))
2064003Svivek 			(void) strlcpy(card->bus_type, "PCIE",
2074669Sfw157321 			    sizeof (card->bus_type));
2085819Sfw157321 		else if (strstr(val, PICL_CLASS_PCI))
2095819Sfw157321 			(void) strlcpy(card->bus_type, "PCIX",
2105819Sfw157321 			    sizeof (card->bus_type));
2115819Sfw157321 		else {
2125819Sfw157321 			/*
2135819Sfw157321 			 * Not perfect: process the binding-name until
2145819Sfw157321 			 * we encounter something that we don't think would
2155819Sfw157321 			 * be part of a bus type.  This may get confused a bit
2165819Sfw157321 			 * if a device or vendor id is encoded right after
2175819Sfw157321 			 * the bus class since there's no delimiter.  If the
2185819Sfw157321 			 * id number begins with a hex digit [abcdef] then
2195819Sfw157321 			 * this will become part of the bus type string
2205819Sfw157321 			 * reported by prtdiag.  This is all an effort to
2215819Sfw157321 			 * print something potentially useful for bus types
2225819Sfw157321 			 * other than PCI/PCIe.
2235819Sfw157321 			 *
2245819Sfw157321 			 * We do this because this code will get called for
2255819Sfw157321 			 * non-PCI class devices like the xaui (class sun4v.)
2265819Sfw157321 			 */
2275819Sfw157321 			if (strstr(val, "SUNW,") != NULL)
2285819Sfw157321 				p = strchr(val, ',') + 1;
2295819Sfw157321 			else
2305819Sfw157321 				p = val;
2315819Sfw157321 			q = p;
2325819Sfw157321 			while (*p != '\0') {
2335819Sfw157321 				if (isdigit((char)*p) || ispunct((char)*p)) {
2345819Sfw157321 					*p = '\0';
2355819Sfw157321 					break;
2365819Sfw157321 				}
2375819Sfw157321 				*p = (char)_toupper((int)*p);
2385819Sfw157321 				++p;
2395819Sfw157321 			}
2405819Sfw157321 			(void) strlcpy(card->bus_type, q,
2415819Sfw157321 			    sizeof (card->bus_type));
2425819Sfw157321 		}
2433941Svenki 	}
2443941Svenki }
2453941Svenki 
2465819Sfw157321 /*
2475819Sfw157321  * Fetch the Label property for this device.  If none is found then
2485819Sfw157321  * search all the siblings with the same device ID for a
2495819Sfw157321  * Label and return that Label.  The plug-in can only match the canonical
2505819Sfw157321  * path from the PRI with a specific devfs path.  So we take care of
2515819Sfw157321  * devices with multiple functions here.  A leaf device downstream of
2525819Sfw157321  * a bridge should fall out of here with PICL_PROPNOTFOUND, and the
2535819Sfw157321  * caller can walk back up the tree in search of the slot's Label.
2545819Sfw157321  */
2553941Svenki static picl_errno_t
get_slot_label(picl_nodehdl_t nodeh,struct io_card * card)2563941Svenki get_slot_label(picl_nodehdl_t nodeh, struct io_card *card)
2573941Svenki {
2583941Svenki 	char val[PICL_PROPNAMELEN_MAX];
2593941Svenki 	picl_errno_t err;
2605436Sfw157321 	picl_nodehdl_t pnodeh;
2615819Sfw157321 	uint32_t devid, sib_devid;
2625819Sfw157321 	int32_t instance;
2633941Svenki 
2645436Sfw157321 	/*
2655819Sfw157321 	 * If there's a Label at this node then return it - we're
2665819Sfw157321 	 * done.
2675436Sfw157321 	 */
2683941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
2694669Sfw157321 	    sizeof (val));
2705819Sfw157321 	if (err == PICL_SUCCESS) {
2715819Sfw157321 		(void) strlcpy(card->slot_str, val, sizeof (card->slot_str));
2725819Sfw157321 		return (err);
2735819Sfw157321 	} else if (err != PICL_PROPNOTFOUND)
2745819Sfw157321 		return (err);
2755819Sfw157321 
2765819Sfw157321 	/*
2775819Sfw157321 	 * At this point we're starting to extrapolate what the Label
2785819Sfw157321 	 * should be since there is none at this specific node.
2795819Sfw157321 	 * Note that until the value of "err" is overwritten in the
2805819Sfw157321 	 * loop below, its value should be PICL_PROPNOTFOUND.
2815819Sfw157321 	 */
2825819Sfw157321 
2835819Sfw157321 	/*
2845819Sfw157321 	 * The device must be attached, and we can figure that out if
2855819Sfw157321 	 * the instance number is present and is not equal to -1.
2865819Sfw157321 	 * This will prevent is from returning a Label for a sibling
2875819Sfw157321 	 * node when the node passed in would have a unique Label if the
2885819Sfw157321 	 * device were attached.  But if the device is downstream of a
2895819Sfw157321 	 * node with a Label then pci_callback() will still find that
2905819Sfw157321 	 * and use it.
2915819Sfw157321 	 */
2925819Sfw157321 	if (picl_get_propval_by_name(nodeh, PICL_PROP_INSTANCE, &instance,
2935819Sfw157321 	    sizeof (instance)) != PICL_SUCCESS)
2945819Sfw157321 		return (err);
2955819Sfw157321 	if (instance == -1)
2965819Sfw157321 		return (err);
2973941Svenki 
2985819Sfw157321 	/*
2995819Sfw157321 	 * Narrow the search to just the one device ID.
3005819Sfw157321 	 */
3015819Sfw157321 	if (picl_get_propval_by_name(nodeh, PICL_PROP_DEVICE_ID, &devid,
3025819Sfw157321 	    sizeof (devid)) != PICL_SUCCESS)
3035819Sfw157321 		return (err);
3045819Sfw157321 
3055819Sfw157321 	/*
3065819Sfw157321 	 * Go find the first child of the parent so we can search
3075819Sfw157321 	 * all of the siblings.
3085819Sfw157321 	 */
3095819Sfw157321 	if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
3105819Sfw157321 	    sizeof (pnodeh)) != PICL_SUCCESS)
3115819Sfw157321 		return (err);
3125819Sfw157321 	if (picl_get_propval_by_name(pnodeh, PICL_PROP_CHILD, &pnodeh,
3135819Sfw157321 	    sizeof (pnodeh)) != PICL_SUCCESS)
3145819Sfw157321 		return (err);
3155436Sfw157321 
3165819Sfw157321 	/*
3175819Sfw157321 	 * If the child's device ID matches, then fetch the Label and
3185819Sfw157321 	 * return it.  The first child/device ID should have a Label
3195819Sfw157321 	 * associated with it.
3205819Sfw157321 	 */
3215819Sfw157321 	do {
3225819Sfw157321 		if (picl_get_propval_by_name(pnodeh, PICL_PROP_DEVICE_ID,
3235819Sfw157321 		    &sib_devid, sizeof (sib_devid)) == PICL_SUCCESS) {
3245819Sfw157321 			if (sib_devid == devid) {
3255819Sfw157321 				if ((err = picl_get_propval_by_name(pnodeh,
3265819Sfw157321 				    PICL_PROP_LABEL, val, sizeof (val))) ==
3275819Sfw157321 				    PICL_SUCCESS) {
3285819Sfw157321 					(void) strlcpy(card->slot_str, val,
3295819Sfw157321 					    sizeof (card->slot_str));
3305819Sfw157321 					break;
3315819Sfw157321 				}
3325819Sfw157321 			}
3335819Sfw157321 		}
3345819Sfw157321 	} while (picl_get_propval_by_name(pnodeh, PICL_PROP_PEER, &pnodeh,
3355819Sfw157321 	    sizeof (pnodeh)) == PICL_SUCCESS);
3365819Sfw157321 
3375436Sfw157321 	return (err);
3383941Svenki }
3393941Svenki 
3403941Svenki static void
get_slot_number(picl_nodehdl_t nodeh,struct io_card * card)3413941Svenki get_slot_number(picl_nodehdl_t nodeh, struct io_card *card)
3423941Svenki {
3433941Svenki 	picl_errno_t err;
3443941Svenki 	picl_prophdl_t proph;
3453941Svenki 	picl_propinfo_t pinfo;
3463941Svenki 	picl_nodehdl_t pnodeh;
3473941Svenki 	uint8_t *pval;
3483941Svenki 	uint32_t dev_mask;
3493941Svenki 	char uaddr[MAXSTRLEN];
3503941Svenki 	int i;
3513941Svenki 
3523941Svenki 	err = PICL_SUCCESS;
3533941Svenki 	while (err == PICL_SUCCESS) {
3543941Svenki 		if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
3554669Sfw157321 		    sizeof (pnodeh)) != PICL_SUCCESS) {
3564669Sfw157321 			(void) strlcpy(card->slot_str, MOTHERBOARD,
3574669Sfw157321 			    sizeof (card->slot_str));
3583941Svenki 			card->slot = -1;
3593941Svenki 			return;
3603941Svenki 		}
3613941Svenki 		if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES,
3624669Sfw157321 		    &pinfo, &proph) == PICL_SUCCESS) {
3633941Svenki 			break;
3643941Svenki 		}
3653941Svenki 		nodeh = pnodeh;
3663941Svenki 	}
3673941Svenki 	if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr,
3684669Sfw157321 	    sizeof (uaddr)) != PICL_SUCCESS) {
3694669Sfw157321 		(void) strlcpy(card->slot_str, MOTHERBOARD,
3704669Sfw157321 		    sizeof (card->slot_str));
3713941Svenki 		card->slot = -1;
3723941Svenki 		return;
3733941Svenki 	}
3743941Svenki 	pval = (uint8_t *)malloc(pinfo.size);
3753941Svenki 	if (!pval) {
3764669Sfw157321 		(void) strlcpy(card->slot_str, MOTHERBOARD,
3774669Sfw157321 		    sizeof (card->slot_str));
3783941Svenki 		card->slot = -1;
3793941Svenki 		return;
3803941Svenki 	}
3813941Svenki 	if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) {
3824669Sfw157321 		(void) strlcpy(card->slot_str, MOTHERBOARD,
3834669Sfw157321 		    sizeof (card->slot_str));
3843941Svenki 		card->slot = -1;
3853941Svenki 		free(pval);
3863941Svenki 		return;
3871708Sstevel 	}
3881708Sstevel 
3893941Svenki 	dev_mask = 0;
3903941Svenki 	for (i = 0; i < sizeof (dev_mask); i++)
3913941Svenki 		dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i));
3923941Svenki 	for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) {
3933941Svenki 		if (uaddr[i] == ',') {
3943941Svenki 			uaddr[i] = '\0';
3953941Svenki 			break;
3963941Svenki 		}
3973941Svenki 	}
3983941Svenki 	card->slot = atol(uaddr);
3993941Svenki 	if (((1 << card->slot) & dev_mask) == 0) {
4004669Sfw157321 		(void) strlcpy(card->slot_str, MOTHERBOARD,
4014669Sfw157321 		    sizeof (card->slot_str));
4023941Svenki 		card->slot = -1;
4033941Svenki 	} else {
4043941Svenki 		char *p = (char *)(pval+sizeof (dev_mask));
4053941Svenki 		int shift = sizeof (uint32_t)*8-1-card->slot;
4063941Svenki 		uint32_t x = (dev_mask << shift) >> shift;
4073941Svenki 		int count = 0;	/* count # of 1's in x */
4083941Svenki 		int i = 0;
4093941Svenki 		while (x != 0) {
4103941Svenki 			count++;
4113941Svenki 			x &= x-1;
4123941Svenki 		}
4133941Svenki 		while (count > 1) {
4144669Sfw157321 			while (p[i++] != '\0')
4154669Sfw157321 				;
4163941Svenki 			count--;
4173941Svenki 		}
4184003Svivek 		(void) strlcpy(card->slot_str, (char *)(p+i),
4194669Sfw157321 		    sizeof (card->slot_str));
4203941Svenki 	}
4213941Svenki 	free(pval);
4223941Svenki }
4233941Svenki 
4243941Svenki /*
4253941Svenki  * add all io devices under pci in io list
4263941Svenki  */
4273941Svenki /* ARGSUSED */
4283941Svenki static int
sun4v_pci_callback(picl_nodehdl_t pcih,void * args)4293941Svenki sun4v_pci_callback(picl_nodehdl_t pcih, void *args)
4303941Svenki {
4313941Svenki 	char path[PICL_PROPNAMELEN_MAX];
4323941Svenki 	char class[PICL_CLASSNAMELEN_MAX];
4333941Svenki 	char name[PICL_PROPNAMELEN_MAX];
4343941Svenki 	char model[PICL_PROPNAMELEN_MAX];
4353941Svenki 	char binding_name[PICL_PROPNAMELEN_MAX];
4363941Svenki 	char val[PICL_PROPNAMELEN_MAX];
4373941Svenki 	char *compatible;
4383941Svenki 	picl_errno_t err;
4395819Sfw157321 	picl_nodehdl_t nodeh, pnodeh;
4403941Svenki 	struct io_card pci_card;
4413941Svenki 
4423941Svenki 	/* Walk through the children */
4433941Svenki 
4443941Svenki 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
4454669Sfw157321 	    sizeof (picl_nodehdl_t));
4463941Svenki 
4473941Svenki 	while (err == PICL_SUCCESS) {
4483941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
4494669Sfw157321 		    class, sizeof (class));
4503941Svenki 		if (err !=  PICL_SUCCESS)
4513941Svenki 			return (err);
4523941Svenki 
4533941Svenki 		if (args) {
4543941Svenki 			char *val = args;
4553941Svenki 			if (strcmp(class, val) == 0) {
4563941Svenki 				err = picl_get_propval_by_name(nodeh,
4574669Sfw157321 				    PICL_PROP_PEER, &nodeh,
4584669Sfw157321 				    sizeof (picl_nodehdl_t));
4593941Svenki 				continue;
4603941Svenki 			} else if (strcmp(val, PICL_CLASS_PCIEX) == 0 &&
4614669Sfw157321 			    strcmp(class, PICL_CLASS_PCI) == 0) {
4623941Svenki 				err = picl_get_propval_by_name(nodeh,
4634669Sfw157321 				    PICL_PROP_PEER, &nodeh,
4644669Sfw157321 				    sizeof (picl_nodehdl_t));
4653941Svenki 				continue;
4663941Svenki 			} else if (strcmp(val, PICL_CLASS_PCI) == 0 &&
4674669Sfw157321 			    strcmp(class, PICL_CLASS_PCIEX) == 0) {
4683941Svenki 				err = picl_get_propval_by_name(nodeh,
4694669Sfw157321 				    PICL_PROP_PEER, &nodeh,
4704669Sfw157321 				    sizeof (picl_nodehdl_t));
4713941Svenki 				continue;
4723941Svenki 			}
4733941Svenki 		}
4743941Svenki 
4753941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
4764669Sfw157321 		    path, sizeof (path));
4773941Svenki 		if (err != PICL_SUCCESS)
4783941Svenki 			return (err);
4793941Svenki 
4803941Svenki 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
4813941Svenki 
4825819Sfw157321 		pnodeh = nodeh;
4835819Sfw157321 		err = get_slot_label(nodeh, &pci_card);
4845819Sfw157321 
4855819Sfw157321 		/*
4865819Sfw157321 		 * No Label at this node, maybe we're looking at a device
4875819Sfw157321 		 * downstream of a bridge.  Walk back up and find a Label and
4885819Sfw157321 		 * record that node in "pnodeh".
4895819Sfw157321 		 */
4905819Sfw157321 		while (err != PICL_SUCCESS) {
4915819Sfw157321 			if (err != PICL_PROPNOTFOUND)
4925819Sfw157321 				break;
4935819Sfw157321 			else if (picl_get_propval_by_name(pnodeh,
4945819Sfw157321 			    PICL_PROP_PARENT, &pnodeh, sizeof (pnodeh)) ==
4955819Sfw157321 			    PICL_SUCCESS)
4965819Sfw157321 				err = get_slot_label(pnodeh, &pci_card);
4975819Sfw157321 			else
4985819Sfw157321 				break;
4995819Sfw157321 		}
5005819Sfw157321 
5015819Sfw157321 		/*
5025819Sfw157321 		 * Can't find a Label for this device in the PCI heirarchy.
5035819Sfw157321 		 * Try to synthesize a slot name from atoms.  This depends
5045819Sfw157321 		 * on the OBP slot_names property being implemented, and this
5055819Sfw157321 		 * so far doesn't seem to be on sun4v.  But just in case that
5065819Sfw157321 		 * is resurrected, the code is here.
5075819Sfw157321 		 */
5085819Sfw157321 		if (err != PICL_SUCCESS) {
5095819Sfw157321 			pnodeh = nodeh;
5105819Sfw157321 			get_slot_number(nodeh, &pci_card);
5115819Sfw157321 		}
5125819Sfw157321 
5135819Sfw157321 		/*
5145819Sfw157321 		 * Passing in pnodeh instead of nodeh will cause prtdiag
5155819Sfw157321 		 * to display the type of IO slot for the leaf node.  For
5165819Sfw157321 		 * built-in devices and a lot of IO cards these will be
5175819Sfw157321 		 * the same thing.  But for IO cards with bridge chips or
5185819Sfw157321 		 * for things like expansion chassis, prtdiag will report
5195819Sfw157321 		 * the bus type of the IO slot and not the leaf, which
5205819Sfw157321 		 * could be different things.
5215819Sfw157321 		 */
5225819Sfw157321 		get_bus_type(pnodeh, &pci_card);
5233941Svenki 
5243941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
5254669Sfw157321 		    sizeof (name));
5263941Svenki 		if (err == PICL_PROPNOTFOUND)
5274003Svivek 			(void) strlcpy(name, "", sizeof (name));
5283941Svenki 		else if (err != PICL_SUCCESS)
5293941Svenki 			return (err);
5303941Svenki 
5313941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val,
5324669Sfw157321 		    sizeof (val));
5333941Svenki 		if (err == PICL_PROPNOTFOUND)
5344003Svivek 			(void) strlcpy(val, "", sizeof (val));
5353941Svenki 		else if (err != PICL_SUCCESS)
5363941Svenki 			return (err);
5373941Svenki 
5385436Sfw157321 		(void) snprintf(pci_card.status, sizeof (pci_card.status),
5395436Sfw157321 		    "%s", pci_card.slot_str);
5403941Svenki 
5413941Svenki 		/*
5423941Svenki 		 * Get the name of this card. If binding_name is found,
5433941Svenki 		 * name will be <nodename>-<binding_name>.
5443941Svenki 		 */
5453941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
5464669Sfw157321 		    binding_name, sizeof (binding_name));
5473941Svenki 		if (err == PICL_SUCCESS) {
5483941Svenki 			if (strcmp(name, binding_name) != 0) {
5493941Svenki 				(void) strlcat(name, "-", sizeof (name));
5503941Svenki 				(void) strlcat(name, binding_name,
5514669Sfw157321 				    sizeof (name));
5523941Svenki 			}
5533941Svenki 		} else if (err == PICL_PROPNOTFOUND) {
5543941Svenki 			/*
5553941Svenki 			 * if compatible prop is not found, name will be
5563941Svenki 			 * <nodename>-<compatible>
5573941Svenki 			 */
5583941Svenki 			err = sun4v_get_first_compatible_value(nodeh,
5594669Sfw157321 			    &compatible);
5603941Svenki 			if (err == PICL_SUCCESS) {
5613941Svenki 				(void) strlcat(name, "-", sizeof (name));
5624003Svivek 				(void) strlcat(name, compatible,
5634669Sfw157321 				    sizeof (name));
5643941Svenki 				free(compatible);
5653941Svenki 			}
5663941Svenki 		} else
5673941Svenki 			return (err);
5683941Svenki 
5693941Svenki 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
5703941Svenki 
5713941Svenki 		/* Get the model of this card */
5723941Svenki 
5733941Svenki 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
5744669Sfw157321 		    model, sizeof (model));
5753941Svenki 		if (err == PICL_PROPNOTFOUND)
5764003Svivek 			(void) strlcpy(model, "", sizeof (model));
5773941Svenki 		else if (err != PICL_SUCCESS)
5783941Svenki 			return (err);
5793941Svenki 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
5803941Svenki 
5813941Svenki 		/* Print NAC name */
5824802Sfw157321 		log_printf("%-18s", pci_card.status);
5833941Svenki 		/* Print IO Type */
5843941Svenki 		log_printf("%-6s", pci_card.bus_type);
5853941Svenki 		/* Printf Card Name */
5865544Sfw157321 		log_printf("%-34s", pci_card.name);
5873941Svenki 		/* Print Card Model */
5883941Svenki 		log_printf("%-8s", pci_card.model);
5893941Svenki 		log_printf("\n");
5903941Svenki 		/* Print Status */
5914802Sfw157321 		log_printf("%-18s", val);
5923941Svenki 		/* Print IO Type */
5933941Svenki 		log_printf("%-6s", "");
5943941Svenki 		/* Print Parent Path */
5954802Sfw157321 		log_printf("%-44s", pci_card.notes);
5963941Svenki 		log_printf("\n");
5973941Svenki 
5983941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
5994669Sfw157321 		    sizeof (picl_nodehdl_t));
6003941Svenki 	}
6013941Svenki 	return (PICL_WALK_CONTINUE);
6021708Sstevel }
6031708Sstevel 
6041708Sstevel /*
6051708Sstevel  * display_pci
6061708Sstevel  * Display all the PCI IO cards on this board.
6071708Sstevel  */
6081708Sstevel void
sun4v_display_pci(picl_nodehdl_t plafh)6091708Sstevel sun4v_display_pci(picl_nodehdl_t plafh)
6101708Sstevel {
6115544Sfw157321 	char *fmt = "%-17s %-5s %-33s %-8s";
6123941Svenki 	/* Have we printed the column headings? */
6133941Svenki 	static int banner = FALSE;
6143941Svenki 
6153941Svenki 	if (banner == FALSE) {
6163941Svenki 		log_printf("\n");
6174802Sfw157321 		log_printf("================================");
6183941Svenki 		log_printf(" IO Devices ");
6194802Sfw157321 		log_printf("================================");
6203941Svenki 		log_printf("\n");
6213941Svenki 		log_printf(fmt, "Slot +", "Bus", "Name +", "Model", 0);
6223941Svenki 		log_printf("\n");
6233941Svenki 		log_printf(fmt, "Status", "Type", "Path", "", 0);
6243941Svenki 		log_printf("\n");
6253941Svenki 		log_printf("---------------------------------"
6264802Sfw157321 		    "-------------------------------------------\n");
6273941Svenki 		banner = TRUE;
6283941Svenki 	}
6293941Svenki 
6303941Svenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
6314669Sfw157321 	    PICL_CLASS_PCIEX, sun4v_pci_callback);
6323941Svenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
6334669Sfw157321 	    PICL_CLASS_PCI, sun4v_pci_callback);
6343941Svenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V,
6354669Sfw157321 	    PICL_CLASS_SUN4V, sun4v_pci_callback);
6363941Svenki }
6373941Svenki 
6383941Svenki /*
6393941Svenki  * return the first compatible value
6403941Svenki  */
6413941Svenki static int
sun4v_get_first_compatible_value(picl_nodehdl_t nodeh,char ** outbuf)6423941Svenki sun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
6433941Svenki {
6443941Svenki 	picl_errno_t err;
6453941Svenki 	picl_prophdl_t proph;
6463941Svenki 	picl_propinfo_t pinfo;
6473941Svenki 	picl_prophdl_t tblh;
6483941Svenki 	picl_prophdl_t rowproph;
6493941Svenki 	char *pval;
6503941Svenki 
6513941Svenki 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
6524669Sfw157321 	    &pinfo, &proph);
6533941Svenki 	if (err != PICL_SUCCESS)
6543941Svenki 		return (err);
6553941Svenki 
6563941Svenki 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
6573941Svenki 		pval = malloc(pinfo.size);
6583941Svenki 		if (pval == NULL)
6593941Svenki 			return (PICL_FAILURE);
6603941Svenki 		err = picl_get_propval(proph, pval, pinfo.size);
6613941Svenki 		if (err != PICL_SUCCESS) {
6623941Svenki 			free(pval);
6633941Svenki 			return (err);
6643941Svenki 		}
6653941Svenki 		*outbuf = pval;
6663941Svenki 		return (PICL_SUCCESS);
6673941Svenki 	}
6683941Svenki 
6693941Svenki 	if (pinfo.type != PICL_PTYPE_TABLE)
6703941Svenki 		return (PICL_FAILURE);
6713941Svenki 
6723941Svenki 	/* get first string from table */
6733941Svenki 	err = picl_get_propval(proph, &tblh, pinfo.size);
6743941Svenki 	if (err != PICL_SUCCESS)
6753941Svenki 		return (err);
6763941Svenki 
6773941Svenki 	err = picl_get_next_by_row(tblh, &rowproph);
6783941Svenki 	if (err != PICL_SUCCESS)
6793941Svenki 		return (err);
6803941Svenki 
6813941Svenki 	err = picl_get_propinfo(rowproph, &pinfo);
6823941Svenki 	if (err != PICL_SUCCESS)
6833941Svenki 		return (err);
6843941Svenki 
6853941Svenki 	pval = malloc(pinfo.size);
6863941Svenki 	if (pval == NULL)
6873941Svenki 		return (PICL_FAILURE);
6883941Svenki 
6893941Svenki 	err = picl_get_propval(rowproph, pval, pinfo.size);
6903941Svenki 	if (err != PICL_SUCCESS) {
6913941Svenki 		free(pval);
6923941Svenki 		return (err);
6933941Svenki 	}
6943941Svenki 
6953941Svenki 	*outbuf = pval;
6963941Svenki 	return (PICL_SUCCESS);
6971708Sstevel }
6981708Sstevel 
6993941Svenki /*
7003941Svenki  * print size of a memory segment
7013941Svenki  */
7023941Svenki static void
print_memory_segment_size(uint64_t size)7033941Svenki print_memory_segment_size(uint64_t size)
7043941Svenki {
7053941Svenki 	uint64_t kbyte = 1024;
7063941Svenki 	uint64_t mbyte = kbyte * kbyte;
7073941Svenki 	uint64_t gbyte = kbyte * mbyte;
7085544Sfw157321 	uint64_t tbyte = kbyte * gbyte;
7093941Svenki 	char buf[MEMORY_SIZE_FIELD];
7103941Svenki 
7115544Sfw157321 	if (size >= tbyte) {
7125544Sfw157321 		if (size % tbyte == 0)
7135544Sfw157321 			(void) snprintf(buf, sizeof (buf), "%d TB",
7145544Sfw157321 			    (int)(size / tbyte));
7155544Sfw157321 		else
7165544Sfw157321 			(void) snprintf(buf, sizeof (buf), "%.2f TB",
7175544Sfw157321 			    (float)size / tbyte);
7185544Sfw157321 	} else if (size >= gbyte) {
7193941Svenki 		if (size % gbyte == 0)
7203941Svenki 			(void) snprintf(buf, sizeof (buf), "%d GB",
7214669Sfw157321 			    (int)(size / gbyte));
7223941Svenki 		else
7233941Svenki 			(void) snprintf(buf, sizeof (buf), "%.2f GB",
7244669Sfw157321 			    (float)size / gbyte);
7253941Svenki 	} else if (size >= mbyte) {
7263941Svenki 		if (size % mbyte == 0)
7273941Svenki 			(void) snprintf(buf, sizeof (buf), "%d MB",
7284669Sfw157321 			    (int)(size / mbyte));
7293941Svenki 		else
7303941Svenki 			(void) snprintf(buf, sizeof (buf), "%.2f MB",
7314669Sfw157321 			    (float)size / mbyte);
7323941Svenki 	} else {
7333941Svenki 		if (size % kbyte == 0)
7343941Svenki 			(void) snprintf(buf, sizeof (buf), "%d KB",
7354669Sfw157321 			    (int)(size / kbyte));
7363941Svenki 		else
7373941Svenki 			(void) snprintf(buf, sizeof (buf), "%.2f KB",
7384669Sfw157321 			    (float)size / kbyte);
7393941Svenki 	}
7405544Sfw157321 	log_printf("%-9s", buf);
7413941Svenki }
7423941Svenki 
7433941Svenki /*
7444669Sfw157321  * Enumerate banks and dimms within a memory segment.  We're handed
7454669Sfw157321  * the first bank within the segment - we assume there are dimms
7464669Sfw157321  * (memory-module) nodes underneath.
7473941Svenki  */
7483941Svenki static void
print_memory_segment_contain(picl_nodehdl_t bank_nodeh)7494669Sfw157321 print_memory_segment_contain(picl_nodehdl_t bank_nodeh)
7501708Sstevel {
7513941Svenki 	char val[PICL_PROPNAMELEN_MAX];
7524669Sfw157321 	picl_nodehdl_t module_nodeh;
7534669Sfw157321 	int flag = 0;
7545544Sfw157321 	uint64_t size;
7554669Sfw157321 
7564669Sfw157321 	do {
7574669Sfw157321 		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_CHILD,
7584669Sfw157321 		    &module_nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
7594669Sfw157321 			continue;
7605544Sfw157321 		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_SIZE,
7615544Sfw157321 		    &size, sizeof (size)) == PICL_SUCCESS) {
7625544Sfw157321 			if (!flag) {
7635544Sfw157321 				print_memory_segment_size(size);
7645544Sfw157321 			} else {
7655544Sfw157321 				log_printf("                "
7665544Sfw157321 				    "                    ");
7675544Sfw157321 				print_memory_segment_size(size);
7685544Sfw157321 				flag = 0;
7695544Sfw157321 			}
7705544Sfw157321 		}
7714669Sfw157321 		do {
7724669Sfw157321 			if (picl_get_propval_by_name(module_nodeh,
7734669Sfw157321 			    PICL_PROP_NAC, val, sizeof (val)) !=
7744669Sfw157321 			    PICL_SUCCESS)
7754669Sfw157321 				continue;
7764669Sfw157321 			else {
7774669Sfw157321 				if (!flag) {
7785544Sfw157321 					log_printf("%s\n", val);
7794669Sfw157321 					flag = 1;
7805544Sfw157321 				} else {
7815544Sfw157321 					log_printf("%s%s\n",
7825544Sfw157321 					    "                       "
7835544Sfw157321 					    "                      ",
7845544Sfw157321 					    val);
7855544Sfw157321 				}
7864669Sfw157321 			}
7874669Sfw157321 		} while (picl_get_propval_by_name(module_nodeh, PICL_PROP_PEER,
7884669Sfw157321 		    &module_nodeh, sizeof (picl_nodehdl_t)) ==
7894669Sfw157321 		    PICL_SUCCESS);
7904669Sfw157321 	} while (picl_get_propval_by_name(bank_nodeh, PICL_PROP_PEER,
7914669Sfw157321 	    &bank_nodeh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS);
7923941Svenki }
7933941Svenki 
7943941Svenki /*
7953941Svenki  * Search node where _class=="memory-segment"
7963941Svenki  * print "Base Address", "Size", etc
7973941Svenki  */
7983941Svenki /*ARGSUSED*/
7993941Svenki static int
sun4v_memory_conf_callback(picl_nodehdl_t nodeh,void * args)8003941Svenki sun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args)
8013941Svenki {
8023941Svenki 	uint64_t base;
8033941Svenki 	uint64_t size;
8043941Svenki 	uint64_t ifactor;
8053941Svenki 	picl_errno_t err = PICL_SUCCESS;
8063941Svenki 
8073941Svenki 	if (class_node_found == 0) {
8083941Svenki 		class_node_found = 1;
8093941Svenki 		return (PICL_WALK_TERMINATE);
8103941Svenki 	}
8113941Svenki 	while (err == PICL_SUCCESS) {
8123941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS,
8134669Sfw157321 		    &base, sizeof (base));
8143941Svenki 		if (err !=  PICL_SUCCESS)
8153941Svenki 			break;
8163941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE,
8174669Sfw157321 		    &size, sizeof (size));
8183941Svenki 		if (err !=  PICL_SUCCESS)
8193941Svenki 			break;
8203941Svenki 		err = picl_get_propval_by_name(nodeh,
8214669Sfw157321 		    PICL_PROP_INTERLEAVE_FACTOR, &ifactor,
8224669Sfw157321 		    sizeof (ifactor));
8233941Svenki 		if (err !=  PICL_SUCCESS)
8243941Svenki 			break;
8255544Sfw157321 		log_printf("0x%-13llx", base);
8263941Svenki 		print_memory_segment_size(size);
8275544Sfw157321 		log_printf("%-12lld", ifactor);
8284669Sfw157321 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
8294669Sfw157321 		    &nodeh, sizeof (nodeh));
8304669Sfw157321 		if (err ==  PICL_SUCCESS)
8314669Sfw157321 			print_memory_segment_contain(nodeh);
8323941Svenki 		log_printf("\n");
8333941Svenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
8344669Sfw157321 		    sizeof (picl_nodehdl_t));
8353941Svenki 	}
8363941Svenki 
8373941Svenki 	return (PICL_WALK_CONTINUE);
8383941Svenki }
8393941Svenki 
8403941Svenki /*ARGSUSED*/
8413941Svenki void
sun4v_display_memory_conf(picl_nodehdl_t plafh)8423941Svenki sun4v_display_memory_conf(picl_nodehdl_t plafh)
8433941Svenki {
8445544Sfw157321 	char *fmt = "%-14s %-8s %-11s %-8s %-s";
8453941Svenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
8464669Sfw157321 	    NULL, sun4v_memory_conf_callback);
8473941Svenki 	if (class_node_found == 0)
8483941Svenki 		return;
8493941Svenki 	log_printf("\n");
8505544Sfw157321 	log_printf("=======================");
8515544Sfw157321 	log_printf(" Physical Memory Configuration ");
8525544Sfw157321 	log_printf("========================");
8533941Svenki 	log_printf("\n");
8543941Svenki 	log_printf("Segment Table:\n");
8554669Sfw157321 	log_printf(
8565544Sfw157321 	    "--------------------------------------------------------------\n");
8575544Sfw157321 	log_printf(fmt, "Base", "Segment", "Interleave", "Bank", "Contains", 0);
8585544Sfw157321 	log_printf("\n");
8595544Sfw157321 	log_printf(fmt, "Address", "Size", "Factor", "Size", "Modules", 0);
8603941Svenki 	log_printf("\n");
8614669Sfw157321 	log_printf(
8625544Sfw157321 	    "--------------------------------------------------------------\n");
8633941Svenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
8644669Sfw157321 	    NULL, sun4v_memory_conf_callback);
8651708Sstevel }
8661708Sstevel 
8671708Sstevel void
sun4v_display_cpu_devices(picl_nodehdl_t plafh)8681708Sstevel sun4v_display_cpu_devices(picl_nodehdl_t plafh)
8691708Sstevel {
8705544Sfw157321 	char *fmt = "%-6s %-9s %-22s %-6s";
8711708Sstevel 
8721708Sstevel 	/*
8731708Sstevel 	 * Display the table header for CPUs . Then display the CPU
8741708Sstevel 	 * frequency, cache size, and processor revision of all cpus.
8751708Sstevel 	 */
8761708Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
8774669Sfw157321 	    "\n"
8785544Sfw157321 	    "================================"
8795544Sfw157321 	    " Virtual CPUs "
8805544Sfw157321 	    "================================"
8814669Sfw157321 	    "\n"
8824669Sfw157321 	    "\n"));
8831708Sstevel 	log_printf("\n");
8845544Sfw157321 	log_printf(fmt, "CPU ID", "Frequency", "Implementation",
8855544Sfw157321 	    "Status", 0);
8861708Sstevel 	log_printf("\n");
8875544Sfw157321 	log_printf(fmt, "------", "---------",
8885544Sfw157321 	    "----------------------", "-------", 0);
8891708Sstevel 	log_printf("\n");
8901708Sstevel 
8915544Sfw157321 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
8925544Sfw157321 	    sun4v_display_cpus);
8931708Sstevel }
8941708Sstevel 
8951708Sstevel /*
8961708Sstevel  * Display the CPUs present on this board.
8971708Sstevel  */
8981708Sstevel /*ARGSUSED*/
8991708Sstevel int
sun4v_display_cpus(picl_nodehdl_t cpuh,void * args)9001708Sstevel sun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
9011708Sstevel {
9021708Sstevel 	int status;
9033941Svenki 	picl_prophdl_t proph;
9043941Svenki 	picl_prophdl_t tblh;
9053941Svenki 	picl_prophdl_t rowproph;
9061708Sstevel 	picl_propinfo_t propinfo;
9073941Svenki 	int *int_value;
9085028Sfw157321 	int cpuid;
9093941Svenki 	char *comp_value;
9103941Svenki 	char *no_prop_value = "   ";
9113941Svenki 	char freq_str[MAXSTRLEN];
9125028Sfw157321 	char state[MAXSTRLEN];
9131708Sstevel 
9141708Sstevel 	/*
9151708Sstevel 	 * Get cpuid property and print it and the NAC name
9161708Sstevel 	 */
9175544Sfw157321 	status = picl_get_propinfo_by_name(cpuh, OBP_PROP_CPUID, &propinfo,
9185544Sfw157321 	    &proph);
9191708Sstevel 	if (status == PICL_SUCCESS) {
9201708Sstevel 		status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
9211708Sstevel 		if (status != PICL_SUCCESS) {
9225544Sfw157321 			log_printf("%-7s", no_prop_value);
9231708Sstevel 		} else {
9245544Sfw157321 			log_printf("%-7d", cpuid);
9251708Sstevel 		}
9261708Sstevel 	} else {
9275544Sfw157321 		log_printf("%-7s", no_prop_value);
9281708Sstevel 	}
9291708Sstevel 
9301708Sstevel clock_freq:
9311708Sstevel 	status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
9324669Sfw157321 	    &proph);
9331708Sstevel 	if (status == PICL_SUCCESS) {
9341708Sstevel 		int_value = malloc(propinfo.size);
9351708Sstevel 		if (int_value == NULL) {
9365544Sfw157321 			log_printf("%-10s", no_prop_value);
9371708Sstevel 			goto compatible;
9381708Sstevel 		}
9391708Sstevel 		status = picl_get_propval(proph, int_value, propinfo.size);
9401708Sstevel 		if (status != PICL_SUCCESS) {
9415544Sfw157321 			log_printf("%-10s", no_prop_value);
9421708Sstevel 		} else {
9431708Sstevel 			/* Running frequency */
9441708Sstevel 			(void) snprintf(freq_str, sizeof (freq_str), "%d MHz",
9451708Sstevel 			    CLK_FREQ_TO_MHZ(*int_value));
9465544Sfw157321 			log_printf("%-10s", freq_str);
9471708Sstevel 		}
9481708Sstevel 		free(int_value);
9491708Sstevel 	} else
9505544Sfw157321 		log_printf("%-10s", no_prop_value);
9511708Sstevel 
9521708Sstevel compatible:
9531708Sstevel 	status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
9544669Sfw157321 	    &proph);
9551708Sstevel 	if (status == PICL_SUCCESS) {
9561708Sstevel 		if (propinfo.type == PICL_PTYPE_CHARSTRING) {
9571708Sstevel 			/*
9581708Sstevel 			 * Compatible Property only has 1 value
9591708Sstevel 			 */
9601708Sstevel 			comp_value = malloc(propinfo.size);
9611708Sstevel 			if (comp_value == NULL) {
9625544Sfw157321 				log_printf("%-23s", no_prop_value, 0);
9635028Sfw157321 				goto state;
9641708Sstevel 			}
9651708Sstevel 			status = picl_get_propval(proph, comp_value,
9664669Sfw157321 			    propinfo.size);
9673941Svenki 			if (status != PICL_SUCCESS)
9685544Sfw157321 				log_printf("%-23s", no_prop_value, 0);
9693941Svenki 			else
9705544Sfw157321 				log_printf("%-23s", comp_value, 0);
9713941Svenki 			free(comp_value);
9721708Sstevel 		} else if (propinfo.type == PICL_PTYPE_TABLE) {
9731708Sstevel 			/*
9741708Sstevel 			 * Compatible Property has multiple values
9751708Sstevel 			 */
9761708Sstevel 			status = picl_get_propval(proph, &tblh, propinfo.size);
9771708Sstevel 			if (status != PICL_SUCCESS) {
9785544Sfw157321 				log_printf("%-23s", no_prop_value, 0);
9795028Sfw157321 				goto state;
9801708Sstevel 			}
9811708Sstevel 			status = picl_get_next_by_row(tblh, &rowproph);
9821708Sstevel 			if (status != PICL_SUCCESS) {
9835544Sfw157321 				log_printf("%-23s", no_prop_value, 0);
9845028Sfw157321 				goto state;
9851708Sstevel 			}
9861708Sstevel 
9871708Sstevel 			status = picl_get_propinfo(rowproph, &propinfo);
9881708Sstevel 			if (status != PICL_SUCCESS) {
9895544Sfw157321 				log_printf("%-23s", no_prop_value, 0);
9905028Sfw157321 				goto state;
9911708Sstevel 			}
9921708Sstevel 
9931708Sstevel 			comp_value = malloc(propinfo.size);
9941708Sstevel 			if (comp_value == NULL) {
9955544Sfw157321 				log_printf("%-23s", no_prop_value, 0);
9965028Sfw157321 				goto state;
9971708Sstevel 			}
9981708Sstevel 			status = picl_get_propval(rowproph, comp_value,
9994669Sfw157321 			    propinfo.size);
10003941Svenki 			if (status != PICL_SUCCESS)
10015544Sfw157321 				log_printf("%-23s", no_prop_value, 0);
10023941Svenki 			else
10035544Sfw157321 				log_printf("%-23s", comp_value, 0);
10041708Sstevel 			free(comp_value);
10051708Sstevel 		}
10061708Sstevel 	} else
10075544Sfw157321 		log_printf("%-23s", no_prop_value, 0);
10081708Sstevel 
10095028Sfw157321 state:
10105028Sfw157321 	status = picl_get_propinfo_by_name(cpuh, PICL_PROP_STATE,
10115028Sfw157321 	    &propinfo, &proph);
10121708Sstevel 	if (status == PICL_SUCCESS) {
10135028Sfw157321 		status = picl_get_propval(proph, state, sizeof (state));
10141708Sstevel 		if (status != PICL_SUCCESS) {
10153941Svenki 			log_printf("%-9s", no_prop_value);
10161708Sstevel 		} else {
10175028Sfw157321 			log_printf("%-9s", state);
10181708Sstevel 		}
10191708Sstevel 	} else
10203941Svenki 		log_printf("%-9s", no_prop_value);
10211708Sstevel 
10221708Sstevel done:
10231708Sstevel 	log_printf("\n");
10241708Sstevel 	return (PICL_WALK_CONTINUE);
10251708Sstevel }
10261708Sstevel 
10271708Sstevel void
sun4v_display_diaginfo(int flag,Prom_node * root,picl_nodehdl_t plafh)10281708Sstevel sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
10291708Sstevel {
10301708Sstevel #ifdef	lint
10311708Sstevel 	flag = flag;
10321708Sstevel 	root = root;
10331708Sstevel 	plafh = plafh;
10341708Sstevel #endif
10351708Sstevel 	/*
10361708Sstevel 	 * This function is intentionally empty
10371708Sstevel 	 */
10381708Sstevel }
10391708Sstevel 
10401708Sstevel void
display_boardnum(int num)10411708Sstevel display_boardnum(int num)
10421708Sstevel {
10431708Sstevel 	log_printf("%2d   ", num, 0);
10441708Sstevel }
10453941Svenki 
10465547Smb158278 static int
sun4v_disp_env_status()10473941Svenki sun4v_disp_env_status()
10483941Svenki {
10495547Smb158278 	int	exit_code = 0;
10505547Smb158278 
10513941Svenki 	if (phyplatformh == 0)
10525547Smb158278 		return (0);
10533941Svenki 	log_printf("\n");
10543941Svenki 	log_printf("============================");
10553941Svenki 	log_printf(" Environmental Status ");
10563941Svenki 	log_printf("============================");
10573941Svenki 	log_printf("\n");
10583941Svenki 
10593941Svenki 	class_node_found = 0;
10603941Svenki 	all_status_ok = 1;
10613941Svenki 	sun4v_env_print_fan_sensors();
10625547Smb158278 	exit_code |= (!all_status_ok);
10633941Svenki 
10643941Svenki 	class_node_found = 0;
10653941Svenki 	all_status_ok = 1;
10663941Svenki 	sun4v_env_print_fan_indicators();
10675547Smb158278 	exit_code |= (!all_status_ok);
10683941Svenki 
10693941Svenki 	class_node_found = 0;
10703941Svenki 	all_status_ok = 1;
10713941Svenki 	sun4v_env_print_temp_sensors();
10725547Smb158278 	exit_code |= (!all_status_ok);
10733941Svenki 
10743941Svenki 	class_node_found = 0;
10753941Svenki 	all_status_ok = 1;
10763941Svenki 	sun4v_env_print_temp_indicators();
10775547Smb158278 	exit_code |= (!all_status_ok);
10783941Svenki 
10793941Svenki 	class_node_found = 0;
10803941Svenki 	all_status_ok = 1;
10813941Svenki 	sun4v_env_print_current_sensors();
10825547Smb158278 	exit_code |= (!all_status_ok);
10833941Svenki 
10843941Svenki 	class_node_found = 0;
10853941Svenki 	all_status_ok = 1;
10863941Svenki 	sun4v_env_print_current_indicators();
10875547Smb158278 	exit_code |= (!all_status_ok);
10883941Svenki 
10893941Svenki 	class_node_found = 0;
10903941Svenki 	all_status_ok = 1;
10913941Svenki 	sun4v_env_print_voltage_sensors();
10925547Smb158278 	exit_code |= (!all_status_ok);
10933941Svenki 
10943941Svenki 	class_node_found = 0;
10953941Svenki 	all_status_ok = 1;
10963941Svenki 	sun4v_env_print_voltage_indicators();
10975547Smb158278 	exit_code |= (!all_status_ok);
10983941Svenki 
10993941Svenki 	class_node_found = 0;
11005547Smb158278 	all_status_ok = 1;
11013941Svenki 	sun4v_env_print_LEDs();
11025547Smb158278 	exit_code |= (!all_status_ok);
11033941Svenki 
11043941Svenki 	class_node_found = 0;
11053941Svenki 	all_status_ok = 1;
11063941Svenki 	sun4v_print_fru_status();
11075547Smb158278 	exit_code |= (!all_status_ok);
11083941Svenki 
11093941Svenki 	class_node_found = 0;
11103941Svenki 	sun4v_print_fw_rev();
11113941Svenki 
11125436Sfw157321 	class_node_found = 0;
11135436Sfw157321 	sun4v_print_openprom_rev();
11145436Sfw157321 
11153941Svenki 	sun4v_print_chassis_serial_no();
11165547Smb158278 
11175547Smb158278 	return (exit_code);
11183941Svenki }
11193941Svenki 
11203941Svenki /*ARGSUSED*/
11213941Svenki static int
sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh,void * args)11223941Svenki sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args)
11233941Svenki {
11243941Svenki 	char val[PICL_PROPNAMELEN_MAX];
11253941Svenki 	picl_nodehdl_t parenth;
11263941Svenki 	char *names[PARENT_NAMES];
11274802Sfw157321 	char *base_units[PICL_PROPNAMELEN_MAX];
11283941Svenki 	char *loc;
11293941Svenki 	int i;
11303941Svenki 	char *prop;
11313941Svenki 	picl_errno_t err;
11325436Sfw157321 	int32_t lo_warning, lo_shutdown, lo_poweroff;
11335436Sfw157321 	int32_t hi_warning, hi_shutdown, hi_poweroff;
11343941Svenki 	int32_t current_val;
11354802Sfw157321 	int32_t exponent;
11364802Sfw157321 	double display_val;
11374928Sfw157321 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
11384928Sfw157321 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
11394928Sfw157321 	sensor_status_t sensor_status = SENSOR_OK;
11403941Svenki 
11413941Svenki 	if (class_node_found == 0) {
11423941Svenki 		class_node_found = 1;
11433941Svenki 		return (PICL_WALK_TERMINATE);
11443941Svenki 	}
11453941Svenki 
11464928Sfw157321 	prop = (char *)args;
11474928Sfw157321 	if (!prop) {
11484928Sfw157321 		sensor_status = SENSOR_UNKNOWN;
11494928Sfw157321 		all_status_ok = 0;
11504928Sfw157321 	} else {
11513941Svenki 		err = picl_get_propval_by_name(nodeh,
11524669Sfw157321 		    PICL_PROP_OPERATIONAL_STATUS, val,
11534669Sfw157321 		    sizeof (val));
11543941Svenki 		if (err == PICL_SUCCESS) {
11553941Svenki 			if (strcmp(val, "disabled") == 0) {
11564928Sfw157321 				sensor_status = SENSOR_DISABLED;
11574928Sfw157321 			}
11584928Sfw157321 		}
11594928Sfw157321 	}
11604928Sfw157321 
11614928Sfw157321 	if (sensor_status != SENSOR_DISABLED &&
11624928Sfw157321 	    sensor_status != SENSOR_UNKNOWN) {
11634928Sfw157321 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
11644928Sfw157321 		    sizeof (current_val)) != PICL_SUCCESS) {
11654928Sfw157321 			sensor_status = SENSOR_UNKNOWN;
11665436Sfw157321 		} else {
11675436Sfw157321 			if (picl_get_propval_by_name(nodeh,
11685436Sfw157321 			    PICL_PROP_LOW_WARNING,
11695436Sfw157321 			    &lo_warning, sizeof (lo_warning)) != PICL_SUCCESS)
11705436Sfw157321 				lo_warning = INVALID_THRESHOLD;
11715436Sfw157321 			if (picl_get_propval_by_name(nodeh,
11725436Sfw157321 			    PICL_PROP_LOW_SHUTDOWN,
11735436Sfw157321 			    &lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS)
11745436Sfw157321 				lo_shutdown = INVALID_THRESHOLD;
11755436Sfw157321 			if (picl_get_propval_by_name(nodeh,
11765436Sfw157321 			    PICL_PROP_LOW_POWER_OFF,
11775436Sfw157321 			    &lo_poweroff, sizeof (lo_poweroff)) != PICL_SUCCESS)
11785436Sfw157321 				lo_poweroff = INVALID_THRESHOLD;
11795436Sfw157321 			if (picl_get_propval_by_name(nodeh,
11805436Sfw157321 			    PICL_PROP_HIGH_WARNING,
11815436Sfw157321 			    &hi_warning, sizeof (hi_warning)) != PICL_SUCCESS)
11825436Sfw157321 				hi_warning = INVALID_THRESHOLD;
11835436Sfw157321 			if (picl_get_propval_by_name(nodeh,
11845436Sfw157321 			    PICL_PROP_HIGH_SHUTDOWN,
11855436Sfw157321 			    &hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS)
11865436Sfw157321 				hi_shutdown = INVALID_THRESHOLD;
11875436Sfw157321 			if (picl_get_propval_by_name(nodeh,
11885436Sfw157321 			    PICL_PROP_HIGH_POWER_OFF,
11895436Sfw157321 			    &hi_poweroff, sizeof (hi_poweroff)) != PICL_SUCCESS)
11905436Sfw157321 				hi_poweroff = INVALID_THRESHOLD;
11914928Sfw157321 
11925436Sfw157321 			if ((lo_poweroff != INVALID_THRESHOLD &&
11935436Sfw157321 			    current_val <= lo_poweroff) ||
11945436Sfw157321 			    (hi_poweroff != INVALID_THRESHOLD &&
11955436Sfw157321 			    current_val >= hi_poweroff)) {
11965436Sfw157321 				sensor_status = SENSOR_FAILED;
11975436Sfw157321 			} else if ((lo_shutdown != INVALID_THRESHOLD &&
11985436Sfw157321 			    current_val <= lo_shutdown) ||
11995436Sfw157321 			    (hi_shutdown != INVALID_THRESHOLD &&
12005436Sfw157321 			    current_val >= hi_shutdown)) {
12015436Sfw157321 				sensor_status = SENSOR_FAILED;
12025436Sfw157321 			} else if ((lo_warning != INVALID_THRESHOLD &&
12035436Sfw157321 			    current_val <= lo_warning) ||
12045436Sfw157321 			    (hi_warning != INVALID_THRESHOLD &&
12055436Sfw157321 			    current_val >= hi_warning)) {
12065436Sfw157321 				sensor_status = SENSOR_WARN;
12075436Sfw157321 			} else {
12085436Sfw157321 				sensor_status = SENSOR_OK;
12095436Sfw157321 			}
12104928Sfw157321 		}
12114928Sfw157321 	}
12124928Sfw157321 
12134928Sfw157321 	if (syserrlog == 0) {
12144928Sfw157321 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
12153941Svenki 			all_status_ok = 0;
12163941Svenki 			return (PICL_WALK_TERMINATE);
12173941Svenki 		}
12184928Sfw157321 		if (sensor_status == SENSOR_OK) {
12194928Sfw157321 			return (PICL_WALK_CONTINUE);
12204928Sfw157321 		}
122112046SMichael.Bergknoff@Sun.COM 	} else {
122212046SMichael.Bergknoff@Sun.COM 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
122312046SMichael.Bergknoff@Sun.COM 			all_status_ok = 0;
122412046SMichael.Bergknoff@Sun.COM 		}
12253941Svenki 	}
12264928Sfw157321 
12274928Sfw157321 	/*
12284928Sfw157321 	 * If we're here then prtdiag was invoked with "-v" or we have
12294928Sfw157321 	 * a sensor that is beyond a threshold, so give them a book to
12304928Sfw157321 	 * read instead of the Cliff Notes.
12314928Sfw157321 	 */
12323941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
12334669Sfw157321 	    sizeof (parenth));
12343941Svenki 	if (err != PICL_SUCCESS) {
12353941Svenki 		log_printf("\n");
12363941Svenki 		return (PICL_WALK_CONTINUE);
12373941Svenki 	}
12384003Svivek 
12394928Sfw157321 	/* gather up the path name for the sensor */
12404928Sfw157321 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
12414928Sfw157321 		for (i = 0; i < PARENT_NAMES; i++) {
12424928Sfw157321 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
12434928Sfw157321 			    NULL) {
12444928Sfw157321 				while (--i > -1)
12454928Sfw157321 					free(names[i]);
12464928Sfw157321 				free(loc);
12474928Sfw157321 				loc = NULL;
12484928Sfw157321 			}
12493941Svenki 		}
12504003Svivek 	}
12514928Sfw157321 	i = 0;
12524928Sfw157321 	if (loc != 0) {
12534928Sfw157321 		while (err == PICL_SUCCESS) {
12544928Sfw157321 			if (parenth == phyplatformh)
12554928Sfw157321 				break;
12564928Sfw157321 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
12574928Sfw157321 			    names[i++], PICL_PROPNAMELEN_MAX);
12584928Sfw157321 			if (err != PICL_SUCCESS) {
12594928Sfw157321 				i--;
12604928Sfw157321 				break;
12614928Sfw157321 			}
12624928Sfw157321 			if (i == PARENT_NAMES)
12634928Sfw157321 				break;
12644928Sfw157321 			err = picl_get_propval_by_name(parenth,
12654928Sfw157321 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
12664928Sfw157321 		}
12674928Sfw157321 		loc[0] = '\0';
12684928Sfw157321 		if (--i > -1) {
12694928Sfw157321 			(void) strlcat(loc, names[i],
12704928Sfw157321 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
12714928Sfw157321 		}
12724928Sfw157321 		while (--i > -1) {
12734928Sfw157321 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
12744928Sfw157321 			    PARENT_NAMES);
12754928Sfw157321 			(void) strlcat(loc, names[i],
12764928Sfw157321 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
12774928Sfw157321 		}
12785028Sfw157321 		log_printf("%-35s", loc);
12794928Sfw157321 		for (i = 0; i < PARENT_NAMES; i++)
12804928Sfw157321 			free(names[i]);
12814928Sfw157321 		free(loc);
12824928Sfw157321 	} else {
12835028Sfw157321 		log_printf("%-35s", " ");
12843941Svenki 	}
12853941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
12864669Sfw157321 	    sizeof (val));
12873941Svenki 	if (err == PICL_SUCCESS)
128811659SSree.Vemuri@Sun.COM 		log_printf("%-19s", val);
12893941Svenki 
12904928Sfw157321 	/*
12914928Sfw157321 	 * Get the exponent if present, and do a little math so that
12924928Sfw157321 	 * if we need to we can print a normalized value for the
12934928Sfw157321 	 * sensor reading.
12944928Sfw157321 	 */
12954802Sfw157321 	if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPONENT,
12964802Sfw157321 	    &exponent, sizeof (exponent)) != PICL_SUCCESS)
12974802Sfw157321 		exponent = 0;
12984802Sfw157321 	if (exponent == 0)
12994802Sfw157321 		display_val = (double)current_val;
13005436Sfw157321 	else {
13014802Sfw157321 		display_val = (double)current_val *
13024802Sfw157321 		    pow((double)10, (double)exponent);
13035436Sfw157321 
13045436Sfw157321 		/*
13055436Sfw157321 		 * Sometimes ILOM will scale a sensor reading but
13065436Sfw157321 		 * there will be nothing to the right of the decimal
13075436Sfw157321 		 * once that value is normalized.  Setting the
13085436Sfw157321 		 * exponent to zero will prevent the printf below
13095436Sfw157321 		 * from printing extraneous zeros.  Otherwise a
13105436Sfw157321 		 * negative exponent is used to set the precision
13115436Sfw157321 		 * for the printf.
13125436Sfw157321 		 */
13135436Sfw157321 		if ((int)display_val == display_val || exponent > 0)
13145436Sfw157321 			exponent = 0;
13155436Sfw157321 	}
13165436Sfw157321 
13174928Sfw157321 	err = picl_get_propval_by_name(nodeh, PICL_PROP_BASE_UNITS,
13184928Sfw157321 	    base_units, sizeof (base_units));
13194802Sfw157321 	if (err != PICL_SUCCESS)
13204802Sfw157321 		base_units[0] = '\0';
13213941Svenki 
13224928Sfw157321 	switch (sensor_status) {
13234928Sfw157321 	case SENSOR_FAILED:
13243941Svenki 		log_printf("%-s", "failed (");
13254802Sfw157321 		log_printf("%-.*f", abs(exponent), display_val);
13264802Sfw157321 		log_printf("%-s %s", base_units, ")");
13274928Sfw157321 		break;
13284928Sfw157321 	case SENSOR_WARN:
13293941Svenki 		log_printf("%-s", "warning (");
13304802Sfw157321 		log_printf("%-.*f", abs(exponent), display_val);
13314802Sfw157321 		log_printf("%-s %s", base_units, ")");
13324928Sfw157321 		break;
13334928Sfw157321 	case SENSOR_DISABLED:
13344928Sfw157321 		log_printf("%-s", "disabled");
13354928Sfw157321 		break;
13364928Sfw157321 	case SENSOR_OK:
13373941Svenki 		log_printf("%-s", "ok");
13384928Sfw157321 		break;
13394928Sfw157321 	default:
13404928Sfw157321 		log_printf("%-s", "unknown");
13414928Sfw157321 		break;
13424928Sfw157321 	}
13433941Svenki 
13443941Svenki 	log_printf("\n");
13453941Svenki 	return (PICL_WALK_CONTINUE);
13463941Svenki }
13473941Svenki 
13483941Svenki /*ARGSUSED*/
13493941Svenki static int
sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh,void * args)13503941Svenki sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args)
13513941Svenki {
13524928Sfw157321 	char current_val[PICL_PROPNAMELEN_MAX];
13534928Sfw157321 	char expected_val[PICL_PROPNAMELEN_MAX];
13544928Sfw157321 	char label[PICL_PROPNAMELEN_MAX];
13553941Svenki 	picl_nodehdl_t parenth;
13563941Svenki 	char *names[PARENT_NAMES];
13573941Svenki 	char *loc;
13583941Svenki 	int i = 0;
13593941Svenki 	char *prop = (char *)args;
13603941Svenki 	picl_errno_t err = PICL_SUCCESS;
13614928Sfw157321 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
13624928Sfw157321 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
13634928Sfw157321 	sensor_status_t sensor_status = SENSOR_OK;
13643941Svenki 
13653941Svenki 	if (class_node_found == 0) {
13663941Svenki 		class_node_found = 1;
13673941Svenki 		return (PICL_WALK_TERMINATE);
13683941Svenki 	}
13694928Sfw157321 
13704928Sfw157321 	prop = (char *)args;
13714928Sfw157321 	if (!prop) {
13724928Sfw157321 		sensor_status = SENSOR_UNKNOWN;
13734928Sfw157321 		all_status_ok = 0;
13744928Sfw157321 	} else {
13753941Svenki 		err = picl_get_propval_by_name(nodeh,
13764928Sfw157321 		    PICL_PROP_OPERATIONAL_STATUS, current_val,
13774928Sfw157321 		    sizeof (current_val));
13783941Svenki 		if (err == PICL_SUCCESS) {
13794928Sfw157321 			if (strcmp(current_val, "disabled") == 0) {
13804928Sfw157321 				sensor_status = SENSOR_DISABLED;
13814928Sfw157321 			}
13824928Sfw157321 		}
13834928Sfw157321 	}
13844928Sfw157321 
13854928Sfw157321 	if (sensor_status != SENSOR_DISABLED &&
13864928Sfw157321 	    sensor_status != SENSOR_UNKNOWN) {
13874928Sfw157321 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
13884928Sfw157321 		    sizeof (current_val)) != PICL_SUCCESS) {
13894928Sfw157321 			(void) strlcpy(current_val, "unknown",
13904928Sfw157321 			    sizeof (current_val));
13914928Sfw157321 			sensor_status = SENSOR_UNKNOWN;
13924928Sfw157321 		} else {
13934928Sfw157321 			if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPECTED,
139412046SMichael.Bergknoff@Sun.COM 			    &expected_val, sizeof (expected_val)) ==
13954928Sfw157321 			    PICL_SUCCESS) {
13964928Sfw157321 				if (strncmp(current_val, expected_val,
13974928Sfw157321 				    sizeof (current_val)) == 0) {
13984928Sfw157321 					sensor_status = SENSOR_OK;
13994928Sfw157321 				} else {
14004928Sfw157321 					sensor_status = SENSOR_FAILED;
14013941Svenki 				}
14024928Sfw157321 			}
14034928Sfw157321 		}
14044928Sfw157321 	}
14054928Sfw157321 
14064928Sfw157321 	if (syserrlog == 0) {
14074928Sfw157321 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
14083941Svenki 			all_status_ok = 0;
14093941Svenki 			return (PICL_WALK_TERMINATE);
14103941Svenki 		}
14114928Sfw157321 		if (sensor_status == SENSOR_OK) {
14124928Sfw157321 			return (PICL_WALK_CONTINUE);
14134928Sfw157321 		}
141412046SMichael.Bergknoff@Sun.COM 	} else {
141512046SMichael.Bergknoff@Sun.COM 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
141612046SMichael.Bergknoff@Sun.COM 			all_status_ok = 0;
141712046SMichael.Bergknoff@Sun.COM 		}
14183941Svenki 	}
14194928Sfw157321 
14204928Sfw157321 	/*
14214928Sfw157321 	 * If we're here then prtdiag was invoked with "-v" or we have
14224928Sfw157321 	 * a sensor that is beyond a threshold, so give them a book to
14234928Sfw157321 	 * read instead of the Cliff Notes.
14244928Sfw157321 	 */
14253941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
14264669Sfw157321 	    sizeof (parenth));
14273941Svenki 	if (err != PICL_SUCCESS) {
14283941Svenki 		log_printf("\n");
14293941Svenki 		return (PICL_WALK_CONTINUE);
14303941Svenki 	}
14314928Sfw157321 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
14324928Sfw157321 		for (i = 0; i < PARENT_NAMES; i++) {
14334928Sfw157321 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
14344928Sfw157321 			    NULL) {
14354928Sfw157321 				while (--i > -1)
14364928Sfw157321 					free(names[i]);
14374928Sfw157321 				free(loc);
14384928Sfw157321 				loc = NULL;
14394928Sfw157321 			}
14403941Svenki 		}
14413941Svenki 	}
14424928Sfw157321 	i = 0;
14434928Sfw157321 	if (loc) {
14444928Sfw157321 		while (err == PICL_SUCCESS) {
14454928Sfw157321 			if (parenth == phyplatformh)
14464928Sfw157321 				break;
14474928Sfw157321 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
14484928Sfw157321 			    names[i++], PICL_PROPNAMELEN_MAX);
14494928Sfw157321 			if (err != PICL_SUCCESS) {
14504928Sfw157321 				i--;
14514928Sfw157321 				break;
14524928Sfw157321 			}
14534928Sfw157321 			if (i == PARENT_NAMES)
14544928Sfw157321 				break;
14554928Sfw157321 			err = picl_get_propval_by_name(parenth,
14564928Sfw157321 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
14574928Sfw157321 		}
14584928Sfw157321 		loc[0] = '\0';
14594928Sfw157321 		if (--i > -1) {
14604928Sfw157321 			(void) strlcat(loc, names[i],
14614928Sfw157321 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
14624928Sfw157321 		}
14634928Sfw157321 		while (--i > -1) {
14644928Sfw157321 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
14654928Sfw157321 			    PARENT_NAMES);
14664928Sfw157321 			(void) strlcat(loc, names[i],
14674928Sfw157321 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
14684928Sfw157321 		}
14695028Sfw157321 		log_printf("%-35s", loc);
14704928Sfw157321 		for (i = 0; i < PARENT_NAMES; i++)
14714928Sfw157321 			free(names[i]);
14724928Sfw157321 		free(loc);
14734928Sfw157321 	} else {
14745028Sfw157321 		log_printf("%-35s", "");
14753941Svenki 	}
14764928Sfw157321 
14774928Sfw157321 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
14784928Sfw157321 	    sizeof (label));
14794928Sfw157321 	if (err != PICL_SUCCESS)
14804928Sfw157321 		(void) strlcpy(label, "", sizeof (label));
148111659SSree.Vemuri@Sun.COM 	log_printf("%-19s", label);
14824928Sfw157321 
14834928Sfw157321 	log_printf("%-8s", current_val);
14844928Sfw157321 
14853941Svenki 	log_printf("\n");
14863941Svenki 	return (PICL_WALK_CONTINUE);
14873941Svenki }
14883941Svenki 
14893941Svenki static void
sun4v_env_print_fan_sensors()14903941Svenki sun4v_env_print_fan_sensors()
14913941Svenki {
149211659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-10s\n";
14933941Svenki 	/*
14943941Svenki 	 * If there isn't any fan sensor node, return now.
14953941Svenki 	 */
14963941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
14974928Sfw157321 	    PICL_CLASS_RPM_SENSOR, (void *)PICL_PROP_SPEED,
14984669Sfw157321 	    sun4v_env_print_sensor_callback);
14993941Svenki 	if (!class_node_found)
15003941Svenki 		return;
15013941Svenki 	log_printf("Fan sensors:\n");
15023941Svenki 	if (syserrlog == 0) {
15033941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
15044669Sfw157321 		    PICL_CLASS_RPM_SENSOR,
15054928Sfw157321 		    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
15063941Svenki 		if (all_status_ok) {
15073941Svenki 			log_printf("All fan sensors are OK.\n");
15083941Svenki 			return;
15093941Svenki 		}
15103941Svenki 	}
15115028Sfw157321 	log_printf("-------------------------------------------------"
151211659SSree.Vemuri@Sun.COM 	    "---------------\n");
15133941Svenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
15145028Sfw157321 	log_printf("-------------------------------------------------"
151511659SSree.Vemuri@Sun.COM 	    "---------------\n");
15163941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR,
15174669Sfw157321 	    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
15183941Svenki }
15193941Svenki 
15203941Svenki static void
sun4v_env_print_fan_indicators()15213941Svenki sun4v_env_print_fan_indicators()
15223941Svenki {
152311659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-10s\n";
15243941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
15254928Sfw157321 	    PICL_CLASS_RPM_INDICATOR, (void *)PICL_PROP_CONDITION,
15264669Sfw157321 	    sun4v_env_print_indicator_callback);
15273941Svenki 	if (!class_node_found)
15283941Svenki 		return;
15293941Svenki 	log_printf("\nFan indicators:\n");
15303941Svenki 	if (syserrlog == 0) {
15313941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
15324669Sfw157321 		    PICL_CLASS_RPM_INDICATOR,
15334928Sfw157321 		    (void *)PICL_PROP_CONDITION,
15344928Sfw157321 		    sun4v_env_print_indicator_callback);
15353941Svenki 		if (all_status_ok) {
15363941Svenki 			log_printf("All fan indicators are OK.\n");
15373941Svenki 			return;
15383941Svenki 		}
15393941Svenki 	}
15405028Sfw157321 	log_printf("-------------------------------------------------"
154111659SSree.Vemuri@Sun.COM 	    "---------------\n");
15423941Svenki 	log_printf(fmt, "Location", "Sensor", "Condition", 0);
15435028Sfw157321 	log_printf("-------------------------------------------------"
154411659SSree.Vemuri@Sun.COM 	    "---------------\n");
15453941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR,
15464802Sfw157321 	    (void *)PICL_PROP_CONDITION, sun4v_env_print_indicator_callback);
15473941Svenki }
15483941Svenki 
15493941Svenki static void
sun4v_env_print_temp_sensors()15503941Svenki sun4v_env_print_temp_sensors()
15513941Svenki {
155211659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-10s\n";
15533941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
15544669Sfw157321 	    PICL_CLASS_TEMPERATURE_SENSOR,
15554669Sfw157321 	    (void *)PICL_PROP_TEMPERATURE,
15564669Sfw157321 	    sun4v_env_print_sensor_callback);
15573941Svenki 	if (!class_node_found)
15583941Svenki 		return;
15593941Svenki 
15603941Svenki 	log_printf("\nTemperature sensors:\n");
15613941Svenki 	if (syserrlog == 0) {
15623941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
15634669Sfw157321 		    PICL_CLASS_TEMPERATURE_SENSOR,
15644928Sfw157321 		    PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
15653941Svenki 		if (all_status_ok) {
15663941Svenki 			log_printf("All temperature sensors are OK.\n");
15673941Svenki 			return;
15683941Svenki 		}
15693941Svenki 	}
15705028Sfw157321 	log_printf("-------------------------------------------------"
157111659SSree.Vemuri@Sun.COM 	    "---------------\n");
15723941Svenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
15735028Sfw157321 	log_printf("-------------------------------------------------"
157411659SSree.Vemuri@Sun.COM 	    "---------------\n");
15753941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
15764669Sfw157321 	    PICL_CLASS_TEMPERATURE_SENSOR,
15774669Sfw157321 	    (void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
15783941Svenki }
15793941Svenki 
15803941Svenki static void
sun4v_env_print_temp_indicators()15813941Svenki sun4v_env_print_temp_indicators()
15823941Svenki {
158311659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-8s\n";
15843941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
15854669Sfw157321 	    PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION,
15864669Sfw157321 	    sun4v_env_print_indicator_callback);
15873941Svenki 	if (!class_node_found)
15883941Svenki 		return;
15893941Svenki 	log_printf("\nTemperature indicators:\n");
15903941Svenki 	if (syserrlog == 0) {
15913941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
15924928Sfw157321 		    PICL_CLASS_TEMPERATURE_INDICATOR,
15934928Sfw157321 		    (void *)PICL_PROP_CONDITION,
15944669Sfw157321 		    sun4v_env_print_indicator_callback);
15953941Svenki 		if (all_status_ok) {
15963941Svenki 			log_printf("All temperature indicators are OK.\n");
15973941Svenki 			return;
15983941Svenki 		}
15993941Svenki 	}
16005028Sfw157321 	log_printf("-------------------------------------------------"
160111659SSree.Vemuri@Sun.COM 	    "---------------\n");
16023941Svenki 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
16035028Sfw157321 	log_printf("-------------------------------------------------"
160411659SSree.Vemuri@Sun.COM 	    "---------------\n");
16053941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
16064669Sfw157321 	    PICL_CLASS_TEMPERATURE_INDICATOR,
16074669Sfw157321 	    (void *)PICL_PROP_CONDITION,
16084669Sfw157321 	    sun4v_env_print_indicator_callback);
16093941Svenki }
16103941Svenki 
16113941Svenki static void
sun4v_env_print_current_sensors()16123941Svenki sun4v_env_print_current_sensors()
16133941Svenki {
161411659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-10s\n";
16153941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR,
16164669Sfw157321 	    (void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
16173941Svenki 	if (!class_node_found)
16183941Svenki 		return;
16193941Svenki 	log_printf("\nCurrent sensors:\n");
16203941Svenki 	if (syserrlog == 0) {
16213941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
16224669Sfw157321 		    PICL_CLASS_CURRENT_SENSOR,
16234928Sfw157321 		    PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
16243941Svenki 		if (all_status_ok) {
16253941Svenki 			log_printf("All current sensors are OK.\n");
16263941Svenki 			return;
16273941Svenki 		}
16283941Svenki 	}
16295028Sfw157321 	log_printf("-------------------------------------------------"
163011659SSree.Vemuri@Sun.COM 	    "---------------\n");
16313941Svenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
16325028Sfw157321 	log_printf("-------------------------------------------------"
163311659SSree.Vemuri@Sun.COM 	    "---------------\n");
16343941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
16354669Sfw157321 	    PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT,
16364669Sfw157321 	    sun4v_env_print_sensor_callback);
16373941Svenki }
16383941Svenki 
16393941Svenki static void
sun4v_env_print_current_indicators()16403941Svenki sun4v_env_print_current_indicators()
16413941Svenki {
164211659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-8s\n";
16433941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
16444669Sfw157321 	    PICL_CLASS_CURRENT_INDICATOR,
16454669Sfw157321 	    (void *)PICL_PROP_CONDITION,
16464669Sfw157321 	    sun4v_env_print_indicator_callback);
16473941Svenki 	if (!class_node_found)
16483941Svenki 		return;
16493941Svenki 	log_printf("\nCurrent indicators:\n");
16503941Svenki 	if (syserrlog == 0) {
16513941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
16524928Sfw157321 		    PICL_CLASS_CURRENT_INDICATOR, (void *)PICL_PROP_CONDITION,
16534669Sfw157321 		    sun4v_env_print_indicator_callback);
16543941Svenki 		if (all_status_ok) {
16553941Svenki 			log_printf("All current indicators are OK.\n");
16563941Svenki 			return;
16573941Svenki 		}
16583941Svenki 	}
16595028Sfw157321 	log_printf("-------------------------------------------------"
166011659SSree.Vemuri@Sun.COM 	    "---------------\n");
16613941Svenki 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
16625028Sfw157321 	log_printf("-------------------------------------------------"
166311659SSree.Vemuri@Sun.COM 	    "---------------\n");
16643941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
16654669Sfw157321 	    PICL_CLASS_CURRENT_INDICATOR,
16664669Sfw157321 	    (void *)PICL_PROP_CONDITION,
16674669Sfw157321 	    sun4v_env_print_indicator_callback);
16683941Svenki }
16693941Svenki 
16703941Svenki static void
sun4v_env_print_voltage_sensors()16713941Svenki sun4v_env_print_voltage_sensors()
16723941Svenki {
167311659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-10s\n";
16743941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
16754669Sfw157321 	    PICL_CLASS_VOLTAGE_SENSOR,
16764669Sfw157321 	    PICL_PROP_VOLTAGE,
16774669Sfw157321 	    sun4v_env_print_sensor_callback);
16783941Svenki 	if (!class_node_found)
16793941Svenki 		return;
16803941Svenki 	log_printf("\nVoltage sensors:\n");
16813941Svenki 	if (syserrlog == 0) {
16823941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
16834669Sfw157321 		    PICL_CLASS_VOLTAGE_SENSOR,
16844928Sfw157321 		    PICL_PROP_VOLTAGE, sun4v_env_print_sensor_callback);
16853941Svenki 		if (all_status_ok) {
16863941Svenki 			log_printf("All voltage sensors are OK.\n");
16873941Svenki 			return;
16883941Svenki 		}
16893941Svenki 	}
16905028Sfw157321 	log_printf("-------------------------------------------------"
169111659SSree.Vemuri@Sun.COM 	    "---------------\n");
16923941Svenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
16935028Sfw157321 	log_printf("-------------------------------------------------"
169411659SSree.Vemuri@Sun.COM 	    "---------------\n");
16953941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
16964669Sfw157321 	    PICL_CLASS_VOLTAGE_SENSOR,
16974669Sfw157321 	    (void *)PICL_PROP_VOLTAGE,
16984669Sfw157321 	    sun4v_env_print_sensor_callback);
16993941Svenki }
17003941Svenki 
17013941Svenki static void
sun4v_env_print_voltage_indicators()17023941Svenki sun4v_env_print_voltage_indicators()
17033941Svenki {
170411659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-8s\n";
17053941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
17064669Sfw157321 	    PICL_CLASS_VOLTAGE_INDICATOR,
17074669Sfw157321 	    (void *)PICL_PROP_CONDITION,
17084669Sfw157321 	    sun4v_env_print_indicator_callback);
17093941Svenki 	if (!class_node_found)
17103941Svenki 		return;
17113941Svenki 	log_printf("\nVoltage indicators:\n");
17123941Svenki 	if (syserrlog == 0) {
17133941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
17144928Sfw157321 		    PICL_CLASS_VOLTAGE_INDICATOR, (void *)PICL_PROP_CONDITION,
17154669Sfw157321 		    sun4v_env_print_indicator_callback);
17163941Svenki 		if (all_status_ok) {
17173941Svenki 			log_printf("All voltage indicators are OK.\n");
17183941Svenki 			return;
17193941Svenki 		}
17203941Svenki 	}
17215028Sfw157321 	log_printf("-------------------------------------------------"
172211659SSree.Vemuri@Sun.COM 	    "---------------\n");
17233941Svenki 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
17245028Sfw157321 	log_printf("-------------------------------------------------"
172511659SSree.Vemuri@Sun.COM 	    "---------------\n");
17263941Svenki 	(void) picl_walk_tree_by_class(phyplatformh,
17274669Sfw157321 	    PICL_CLASS_VOLTAGE_INDICATOR,
17284669Sfw157321 	    (void *)PICL_PROP_CONDITION,
17294669Sfw157321 	    sun4v_env_print_indicator_callback);
17303941Svenki }
17313941Svenki 
17323941Svenki static void
sun4v_env_print_LEDs()17333941Svenki sun4v_env_print_LEDs()
17343941Svenki {
173511659SSree.Vemuri@Sun.COM 	char *fmt = "%-34s %-18s %-8s\n";
17363941Svenki 	if (syserrlog == 0)
17373941Svenki 		return;
17383941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
17394669Sfw157321 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
17403941Svenki 	if (!class_node_found)
17413941Svenki 		return;
17423941Svenki 	log_printf("\nLEDs:\n");
17435028Sfw157321 	log_printf("-------------------------------------------------"
174411659SSree.Vemuri@Sun.COM 	    "---------------\n");
17453941Svenki 	log_printf(fmt, "Location", "LED", "State", 0);
17465028Sfw157321 	log_printf("-------------------------------------------------"
174711659SSree.Vemuri@Sun.COM 	    "---------------\n");
17483941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
17494669Sfw157321 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
17503941Svenki }
17513941Svenki 
17523941Svenki /*ARGSUSED*/
17533941Svenki static int
sun4v_print_fru_status_callback(picl_nodehdl_t nodeh,void * args)17543941Svenki sun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args)
17553941Svenki {
17563941Svenki 	char label[PICL_PROPNAMELEN_MAX];
17573941Svenki 	char status[PICL_PROPNAMELEN_MAX];
17583941Svenki 	picl_errno_t err;
17593941Svenki 	picl_prophdl_t proph;
17603941Svenki 	picl_nodehdl_t parenth;
17613941Svenki 	char *names[PARENT_NAMES];
17623941Svenki 	char *loc;
17633941Svenki 	int i;
17643941Svenki 
17653941Svenki 	if (!class_node_found) {
17663941Svenki 		class_node_found = 1;
17673941Svenki 		return (PICL_WALK_TERMINATE);
17683941Svenki 	}
17693941Svenki 	err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph);
17703941Svenki 	if (err != PICL_SUCCESS)
17713941Svenki 		return (PICL_WALK_CONTINUE);
17723941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
17734669Sfw157321 	    sizeof (label));
17743941Svenki 	if (err != PICL_SUCCESS)
17753941Svenki 		return (PICL_WALK_CONTINUE);
17763941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
17774669Sfw157321 	    status, sizeof (status));
17783941Svenki 	if (err != PICL_SUCCESS)
17793941Svenki 		return (PICL_WALK_CONTINUE);
17803941Svenki 	if (syserrlog == 0) {
17813941Svenki 		if (strcmp(status, "disabled") == 0) {
17823941Svenki 			if (all_status_ok) {
17833941Svenki 				all_status_ok = 0;
17843941Svenki 				return (PICL_WALK_TERMINATE);
17853941Svenki 			}
17863941Svenki 		} else
17873941Svenki 			return (PICL_WALK_CONTINUE);
178812046SMichael.Bergknoff@Sun.COM 	} else {
178912046SMichael.Bergknoff@Sun.COM 		if (all_status_ok && (strcmp(status, "disabled") == 0)) {
179012046SMichael.Bergknoff@Sun.COM 			all_status_ok = 0;
179112046SMichael.Bergknoff@Sun.COM 		}
17923941Svenki 	}
179310070SBirva.Shah@Sun.COM 
179410070SBirva.Shah@Sun.COM 	if (is_fru_absent(nodeh))
179510070SBirva.Shah@Sun.COM 		strcpy(status, "Not present");
179610070SBirva.Shah@Sun.COM 
17973941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
17984669Sfw157321 	    sizeof (parenth));
17993941Svenki 	if (err != PICL_SUCCESS) {
18003941Svenki 		log_printf("\n");
18013941Svenki 		return (PICL_WALK_CONTINUE);
18023941Svenki 	}
18033941Svenki 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
18043941Svenki 		return (PICL_WALK_TERMINATE);
18053941Svenki 	for (i = 0; i < PARENT_NAMES; i++)
18063941Svenki 		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
18073941Svenki 			while (--i > -1)
18083941Svenki 				free(names[i]);
18093941Svenki 			free(loc);
18103941Svenki 			return (PICL_WALK_TERMINATE);
18113941Svenki 		}
18123941Svenki 	i = 0;
18133941Svenki 	while (err == PICL_SUCCESS) {
18144802Sfw157321 		if (parenth == phyplatformh)
18153941Svenki 			break;
18163941Svenki 		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
18174669Sfw157321 		    names[i++], PICL_PROPNAMELEN_MAX);
18183941Svenki 		if (err != PICL_SUCCESS) {
18193941Svenki 			i--;
18203941Svenki 			break;
18213941Svenki 		}
18223941Svenki 		if (i == PARENT_NAMES)
18233941Svenki 			break;
18243941Svenki 		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
18254669Sfw157321 		    &parenth, sizeof (parenth));
18263941Svenki 	}
18273941Svenki 	loc[0] = '\0';
18284003Svivek 	if (--i > -1) {
18294003Svivek 		(void) strlcat(loc, names[i],
18304669Sfw157321 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
18314003Svivek 	}
18323941Svenki 	while (--i > -1) {
18334003Svivek 		(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * PARENT_NAMES);
18344003Svivek 		(void) strlcat(loc, names[i],
18354669Sfw157321 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
18363941Svenki 	}
18375028Sfw157321 	log_printf("%-35s", loc);
18383941Svenki 	for (i = 0; i < PARENT_NAMES; i++)
18393941Svenki 		free(names[i]);
18403941Svenki 	free(loc);
18413941Svenki 	log_printf("%-10s", label);
18423941Svenki 	log_printf("%-9s", status);
18433941Svenki 	log_printf("\n");
18443941Svenki 	return (PICL_WALK_CONTINUE);
18453941Svenki }
18463941Svenki 
18473941Svenki static void
sun4v_print_fru_status()18483941Svenki sun4v_print_fru_status()
18493941Svenki {
18505028Sfw157321 	char *fmt = "%-34s %-9s %-8s\n";
18515436Sfw157321 
18523941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
18534669Sfw157321 	    sun4v_print_fru_status_callback);
18543941Svenki 	if (!class_node_found)
18553941Svenki 		return;
18565436Sfw157321 
18573941Svenki 	log_printf("\n");
18583941Svenki 	log_printf("============================");
18593941Svenki 	log_printf(" FRU Status ");
18603941Svenki 	log_printf("============================");
18613941Svenki 	log_printf("\n");
18623941Svenki 
18633941Svenki 	if (syserrlog == 0) {
18643941Svenki 		(void) picl_walk_tree_by_class(phyplatformh,
18654802Sfw157321 		    NULL, NULL,
18664669Sfw157321 		    sun4v_print_fru_status_callback);
18673941Svenki 		if (all_status_ok) {
18683941Svenki 			log_printf("All FRUs are enabled.\n");
18693941Svenki 			return;
18703941Svenki 		}
18713941Svenki 	}
18723941Svenki 	log_printf(fmt, "Location", "Name", "Status", 0);
18735028Sfw157321 	log_printf("------------------------------------------------------\n");
18744802Sfw157321 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
18754669Sfw157321 	    sun4v_print_fru_status_callback);
18763941Svenki }
18773941Svenki 
187810070SBirva.Shah@Sun.COM /*  Check the children of the FRU node for a presence indicator */
187910070SBirva.Shah@Sun.COM static int
is_fru_absent(picl_nodehdl_t fruh)188010070SBirva.Shah@Sun.COM is_fru_absent(picl_nodehdl_t fruh)
188110070SBirva.Shah@Sun.COM {
188210070SBirva.Shah@Sun.COM 	char class [PICL_CLASSNAMELEN_MAX];
188310070SBirva.Shah@Sun.COM 	char condition [PICL_PROPNAMELEN_MAX];
188410070SBirva.Shah@Sun.COM 	picl_errno_t err;
188510070SBirva.Shah@Sun.COM 	picl_nodehdl_t nodeh;
188610070SBirva.Shah@Sun.COM 
188710070SBirva.Shah@Sun.COM 	err = picl_get_propval_by_name(fruh, PICL_PROP_CHILD, &nodeh,
188810070SBirva.Shah@Sun.COM 	    sizeof (picl_nodehdl_t));
188910070SBirva.Shah@Sun.COM 	while (err == PICL_SUCCESS) {
189010070SBirva.Shah@Sun.COM 		err = picl_get_propval_by_name(nodeh,
189110070SBirva.Shah@Sun.COM 		    PICL_PROP_CLASSNAME, class, sizeof (class));
189210070SBirva.Shah@Sun.COM 		if (err == PICL_SUCCESS &&
189310070SBirva.Shah@Sun.COM 		    strcmp(class, "presence-indicator") == 0) {
189410070SBirva.Shah@Sun.COM 			err = picl_get_propval_by_name(nodeh,
189510070SBirva.Shah@Sun.COM 			    PICL_PROP_CONDITION, condition,
189610070SBirva.Shah@Sun.COM 			    sizeof (condition));
189710070SBirva.Shah@Sun.COM 			if (err == PICL_SUCCESS) {
189810070SBirva.Shah@Sun.COM 				if (strcmp(condition, "Absent") == 0) {
189910070SBirva.Shah@Sun.COM 					return (1);
190010070SBirva.Shah@Sun.COM 				} else	{
190110070SBirva.Shah@Sun.COM 					return (0);
190210070SBirva.Shah@Sun.COM 				}
190310070SBirva.Shah@Sun.COM 			}
190410070SBirva.Shah@Sun.COM 		}
190510070SBirva.Shah@Sun.COM 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
190610070SBirva.Shah@Sun.COM 		    &nodeh, sizeof (picl_nodehdl_t));
190710070SBirva.Shah@Sun.COM 	}
190810070SBirva.Shah@Sun.COM 	return (0);
190910070SBirva.Shah@Sun.COM }
191010070SBirva.Shah@Sun.COM 
19113941Svenki /*ARGSUSED*/
19123941Svenki static int
sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh,void * args)19133941Svenki sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args)
19143941Svenki {
19153941Svenki 	char rev[PICL_PROPNAMELEN_MAX];
19163941Svenki 	picl_errno_t err;
19173941Svenki 
19183941Svenki 	if (!class_node_found) {
19193941Svenki 		class_node_found = 1;
19203941Svenki 		return (PICL_WALK_TERMINATE);
19213941Svenki 	}
19225436Sfw157321 
19233941Svenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev,
19244669Sfw157321 	    sizeof (rev));
19253941Svenki 	if (err != PICL_SUCCESS)
19263941Svenki 		return (PICL_WALK_CONTINUE);
19273941Svenki 	if (strlen(rev) == 0)
19283941Svenki 		return (PICL_WALK_CONTINUE);
19295436Sfw157321 	log_printf("%s", rev);
19303941Svenki 	log_printf("\n");
19313941Svenki 	return (PICL_WALK_CONTINUE);
19323941Svenki }
19333941Svenki 
19343941Svenki static void
sun4v_print_fw_rev()19353941Svenki sun4v_print_fw_rev()
19363941Svenki {
19373941Svenki 	if (syserrlog == 0)
19383941Svenki 		return;
19395436Sfw157321 
19403941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
19414669Sfw157321 	    sun4v_print_fw_rev_callback);
19423941Svenki 	if (!class_node_found)
19433941Svenki 		return;
19445436Sfw157321 
19453941Svenki 	log_printf("\n");
19463941Svenki 	log_printf("============================");
19473941Svenki 	log_printf(" FW Version ");
19483941Svenki 	log_printf("============================");
19493941Svenki 	log_printf("\n");
19505436Sfw157321 	log_printf("Version\n");
19515028Sfw157321 	log_printf("-------------------------------------------------"
19525028Sfw157321 	    "-----------\n");
19533941Svenki 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
19544669Sfw157321 	    sun4v_print_fw_rev_callback);
19553941Svenki }
19563941Svenki 
19573941Svenki static void
sun4v_print_openprom_rev()19585436Sfw157321 sun4v_print_openprom_rev()
19595436Sfw157321 {
19605436Sfw157321 	if (syserrlog == 0)
19615436Sfw157321 		return;
19625436Sfw157321 
19635436Sfw157321 	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
19645436Sfw157321 	    openprom_callback);
19655436Sfw157321 	if (!class_node_found)
19665436Sfw157321 		return;
19675436Sfw157321 
19685436Sfw157321 	log_printf("\n");
19695436Sfw157321 	log_printf("======================");
19705436Sfw157321 	log_printf(" System PROM revisions ");
19715436Sfw157321 	log_printf("=======================");
19725436Sfw157321 	log_printf("\n");
19735436Sfw157321 	log_printf("Version\n");
19745436Sfw157321 	log_printf("-------------------------------------------------"
19755436Sfw157321 	    "-----------\n");
19765436Sfw157321 	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
19775436Sfw157321 	    openprom_callback);
19785436Sfw157321 }
19795436Sfw157321 
19805436Sfw157321 /*
19815436Sfw157321  * display the OBP and POST prom revisions (if present)
19825436Sfw157321  */
19835436Sfw157321 /* ARGSUSED */
19845436Sfw157321 static int
openprom_callback(picl_nodehdl_t openpromh,void * arg)19855436Sfw157321 openprom_callback(picl_nodehdl_t openpromh, void *arg)
19865436Sfw157321 {
19875436Sfw157321 	picl_prophdl_t	proph;
19885436Sfw157321 	picl_prophdl_t	tblh;
19895436Sfw157321 	picl_prophdl_t	rowproph;
19905436Sfw157321 	picl_propinfo_t	pinfo;
19915436Sfw157321 	char		*prom_version = NULL;
19925436Sfw157321 	char		*obp_version = NULL;
19935436Sfw157321 	int		err;
19945436Sfw157321 
19955436Sfw157321 	if (!class_node_found) {
19965436Sfw157321 		class_node_found = 1;
19975436Sfw157321 		return (PICL_WALK_TERMINATE);
19985436Sfw157321 	}
19995436Sfw157321 
20005436Sfw157321 	err = picl_get_propinfo_by_name(openpromh, OBP_PROP_VERSION,
20015436Sfw157321 	    &pinfo, &proph);
20025436Sfw157321 	if (err == PICL_PROPNOTFOUND)
20035436Sfw157321 		return (PICL_WALK_TERMINATE);
20045436Sfw157321 	else if (err != PICL_SUCCESS)
20055436Sfw157321 		return (err);
20065436Sfw157321 
20075436Sfw157321 	/*
20085436Sfw157321 	 * If it's a table prop, the first element is OBP revision
20095436Sfw157321 	 * The second one is POST revision.
20105436Sfw157321 	 * If it's a charstring prop, the value will be only OBP revision
20115436Sfw157321 	 */
20125436Sfw157321 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
20135436Sfw157321 		prom_version = (char *)alloca(pinfo.size);
20145436Sfw157321 		if (prom_version == NULL)
20155436Sfw157321 			return (PICL_FAILURE);
20165436Sfw157321 		err = picl_get_propval(proph, prom_version, pinfo.size);
20175436Sfw157321 		if (err != PICL_SUCCESS)
20185436Sfw157321 			return (err);
20195436Sfw157321 		log_printf("%s\n", prom_version);
20205436Sfw157321 	}
20215436Sfw157321 
20225436Sfw157321 	if (pinfo.type != PICL_PTYPE_TABLE)	/* not supported type */
20235436Sfw157321 		return (PICL_WALK_TERMINATE);
20245436Sfw157321 
20255436Sfw157321 	err = picl_get_propval(proph, &tblh, pinfo.size);
20265436Sfw157321 	if (err != PICL_SUCCESS)
20275436Sfw157321 		return (err);
20285436Sfw157321 
20295436Sfw157321 	err = picl_get_next_by_row(tblh, &rowproph);
20305436Sfw157321 	if (err == PICL_SUCCESS) {
20315436Sfw157321 		/* get first row */
20325436Sfw157321 		err = picl_get_propinfo(rowproph, &pinfo);
20335436Sfw157321 		if (err != PICL_SUCCESS)
20345436Sfw157321 			return (err);
20355436Sfw157321 
20365436Sfw157321 		prom_version = (char *)alloca(pinfo.size);
20375436Sfw157321 		if (prom_version == NULL)
20385436Sfw157321 			return (PICL_FAILURE);
20395436Sfw157321 
20405436Sfw157321 		err = picl_get_propval(rowproph, prom_version, pinfo.size);
20415436Sfw157321 		if (err != PICL_SUCCESS)
20425436Sfw157321 			return (err);
20435436Sfw157321 		log_printf("%s\n", prom_version);
20445436Sfw157321 
20455436Sfw157321 		/* get second row */
20465436Sfw157321 		err = picl_get_next_by_col(rowproph, &rowproph);
20475436Sfw157321 		if (err == PICL_SUCCESS) {
20485436Sfw157321 			err = picl_get_propinfo(rowproph, &pinfo);
20495436Sfw157321 			if (err != PICL_SUCCESS)
20505436Sfw157321 				return (err);
20515436Sfw157321 
20525436Sfw157321 			obp_version = (char *)alloca(pinfo.size);
20535436Sfw157321 			if (obp_version == NULL)
20545436Sfw157321 				return (PICL_FAILURE);
20555436Sfw157321 			err = picl_get_propval(rowproph, obp_version,
20565436Sfw157321 			    pinfo.size);
20575436Sfw157321 			if (err != PICL_SUCCESS)
20585436Sfw157321 				return (err);
20595436Sfw157321 			log_printf("%s\n", obp_version);
20605436Sfw157321 		}
20615436Sfw157321 	}
20625436Sfw157321 
20635436Sfw157321 	return (PICL_WALK_TERMINATE);
20645436Sfw157321 }
20655436Sfw157321 
20665436Sfw157321 static void
sun4v_print_chassis_serial_no()20673941Svenki sun4v_print_chassis_serial_no()
20683941Svenki {
20693941Svenki 	char val[PICL_PROPNAMELEN_MAX];
20703941Svenki 	picl_errno_t err;
20713941Svenki 	if (syserrlog == 0 || chassish == 0)
20723941Svenki 		return;
20733941Svenki 
20743941Svenki 	log_printf("\n");
20756014Ssuha 	log_printf("Chassis Serial Number");
20763941Svenki 	log_printf("\n");
20773941Svenki 	log_printf("---------------------\n");
20783941Svenki 	err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER,
20794669Sfw157321 	    val, sizeof (val));
20803941Svenki 	if (err == PICL_SUCCESS)
20813941Svenki 		log_printf("%s", val);
20823941Svenki 	log_printf("\n");
20833941Svenki }
2084