103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
50d63ce2bSvenki  * Common Development and Distribution License (the "License").
60d63ce2bSvenki  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel /*
227ae8c7a8SMichael Bergknoff  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
232bcbf80cSPeter Tribble  * Copyright (c) 2020 Peter Tribble.
2403831d35Sstevel  */
2503831d35Sstevel 
2603831d35Sstevel #include <stdio.h>
2703831d35Sstevel #include <stdlib.h>
28dc6ca969Sfw #include <alloca.h>
2903831d35Sstevel #include <unistd.h>
3003831d35Sstevel #include <ctype.h>
3103831d35Sstevel #include <string.h>
3203831d35Sstevel #include <kvm.h>
3303831d35Sstevel #include <varargs.h>
3403831d35Sstevel #include <time.h>
3503831d35Sstevel #include <dirent.h>
3603831d35Sstevel #include <fcntl.h>
3703831d35Sstevel #include <sys/param.h>
3803831d35Sstevel #include <sys/stat.h>
3903831d35Sstevel #include <sys/types.h>
4003831d35Sstevel #include <sys/utsname.h>
4103831d35Sstevel #include <sys/openpromio.h>
4203831d35Sstevel #include <libintl.h>
4303831d35Sstevel #include <syslog.h>
4403831d35Sstevel #include <sys/dkio.h>
450d63ce2bSvenki #include <sys/systeminfo.h>
460d63ce2bSvenki #include <picldefs.h>
47aaba19e2Sfw #include <math.h>
48aaba19e2Sfw #include <errno.h>
4903831d35Sstevel #include "pdevinfo.h"
5003831d35Sstevel #include "display.h"
5103831d35Sstevel #include "display_sun4v.h"
5203831d35Sstevel #include "libprtdiag.h"
5303831d35Sstevel 
5403831d35Sstevel #if !defined(TEXT_DOMAIN)
5503831d35Sstevel #define	TEXT_DOMAIN	"SYS_TEST"
5603831d35Sstevel #endif
5703831d35Sstevel 
58a90d965dSfw #define	MOTHERBOARD			"MB"
590d63ce2bSvenki #define	NETWORK				"network"
600d63ce2bSvenki #define	SUN4V_MACHINE			"sun4v"
610d63ce2bSvenki #define	PARENT_NAMES			10
620d63ce2bSvenki 
630d63ce2bSvenki /*
640d63ce2bSvenki  * Additional OBP properties
650d63ce2bSvenki  */
660d63ce2bSvenki #define	OBP_PROP_COMPATIBLE		"compatible"
670d63ce2bSvenki #define	OBP_PROP_MODEL			"model"
680d63ce2bSvenki #define	OBP_PROP_SLOT_NAMES		"slot-names"
69dc6ca969Sfw #define	OBP_PROP_VERSION		"version"
700d63ce2bSvenki 
710d63ce2bSvenki #define	PICL_NODE_PHYSICAL_PLATFORM	"physical-platform"
720d63ce2bSvenki #define	PICL_NODE_CHASSIS		"chassis"
730d63ce2bSvenki #define	MEMORY_SIZE_FIELD		11
740d63ce2bSvenki #define	INVALID_THRESHOLD		1000000
750d63ce2bSvenki 
760d63ce2bSvenki /*
770d63ce2bSvenki  * Additional picl classes
780d63ce2bSvenki  */
790d63ce2bSvenki #ifndef	PICL_CLASS_SUN4V
800d63ce2bSvenki #define	PICL_CLASS_SUN4V		"sun4v"
810d63ce2bSvenki #endif
820d63ce2bSvenki 
830d63ce2bSvenki #ifndef	PICL_PROP_NAC
840d63ce2bSvenki #define	PICL_PROP_NAC			"nac"
850d63ce2bSvenki #endif
860d63ce2bSvenki 
870d63ce2bSvenki extern int sys_clk;
880d63ce2bSvenki extern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *,
890d63ce2bSvenki 	picl_nodehdl_t *);
900d63ce2bSvenki 
910d63ce2bSvenki static picl_nodehdl_t rooth = 0, phyplatformh = 0;
920d63ce2bSvenki static picl_nodehdl_t chassish = 0;
930d63ce2bSvenki static int class_node_found;
940d63ce2bSvenki static int syserrlog;
950d63ce2bSvenki static int all_status_ok;
960d63ce2bSvenki 
970d63ce2bSvenki /* local functions */
980d63ce2bSvenki static int sun4v_get_first_compatible_value(picl_nodehdl_t, char **);
990d63ce2bSvenki static void sun4v_display_memory_conf(picl_nodehdl_t);
100d776656fSmb static int sun4v_disp_env_status();
1010d63ce2bSvenki static void sun4v_env_print_fan_sensors();
1020d63ce2bSvenki static void sun4v_env_print_fan_indicators();
1030d63ce2bSvenki static void sun4v_env_print_temp_sensors();
1040d63ce2bSvenki static void sun4v_env_print_temp_indicators();
1050d63ce2bSvenki static void sun4v_env_print_current_sensors();
1060d63ce2bSvenki static void sun4v_env_print_current_indicators();
1070d63ce2bSvenki static void sun4v_env_print_voltage_sensors();
1080d63ce2bSvenki static void sun4v_env_print_voltage_indicators();
1090d63ce2bSvenki static void sun4v_env_print_LEDs();
1100d63ce2bSvenki static void sun4v_print_fru_status();
1118a31bd2bSBirva Shah static int is_fru_absent(picl_nodehdl_t);
1120d63ce2bSvenki static void sun4v_print_fw_rev();
1130d63ce2bSvenki static void sun4v_print_chassis_serial_no();
114dc6ca969Sfw static int openprom_callback(picl_nodehdl_t openpromh, void *arg);
115dc6ca969Sfw static void sun4v_print_openprom_rev();
11603831d35Sstevel 
11703831d35Sstevel int
sun4v_display(Sys_tree * tree,Prom_node * root,int log,picl_nodehdl_t plafh)1180d63ce2bSvenki sun4v_display(Sys_tree *tree, Prom_node *root, int log,
119*6fb59094SToomas Soome     picl_nodehdl_t plafh)
12003831d35Sstevel {
12103831d35Sstevel 	void *value;		/* used for opaque PROM data */
12203831d35Sstevel 	struct mem_total memory_total;	/* Total memory in system */
1230d63ce2bSvenki 	char machine[MAXSTRLEN];
124d776656fSmb 	int	exit_code = 0;
1250d63ce2bSvenki 
1260d63ce2bSvenki 	if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1)
1270d63ce2bSvenki 		return (1);
1280d63ce2bSvenki 	if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0)
1290d63ce2bSvenki 		return (1);
13003831d35Sstevel 
13103831d35Sstevel 	sys_clk = -1;  /* System clock freq. (in MHz) */
13203831d35Sstevel 
13303831d35Sstevel 	/*
13403831d35Sstevel 	 * Now display the machine's configuration. We do this if we
13503831d35Sstevel 	 * are not logging.
13603831d35Sstevel 	 */
13703831d35Sstevel 	if (!logging) {
13803831d35Sstevel 		struct utsname uts_buf;
13903831d35Sstevel 
14003831d35Sstevel 		/*
14103831d35Sstevel 		 * Display system banner
14203831d35Sstevel 		 */
14303831d35Sstevel 		(void) uname(&uts_buf);
14403831d35Sstevel 
1450d63ce2bSvenki 		log_printf(dgettext(TEXT_DOMAIN, "System Configuration:  "
1462983dda7SMichael Bergknoff 		    "Oracle Corporation  %s %s\n"), uts_buf.machine,
147a90d965dSfw 		    get_prop_val(find_prop(root, "banner-name")), 0);
14803831d35Sstevel 
14903831d35Sstevel 		/* display system clock frequency */
15003831d35Sstevel 		value = get_prop_val(find_prop(root, "clock-frequency"));
15103831d35Sstevel 		if (value != NULL) {
15203831d35Sstevel 			sys_clk = ((*((int *)value)) + 500000) / 1000000;
15303831d35Sstevel 			log_printf(dgettext(TEXT_DOMAIN, "System clock "
154a90d965dSfw 			    "frequency: %d MHz\n"), sys_clk, 0);
15503831d35Sstevel 		}
15603831d35Sstevel 
15703831d35Sstevel 		/* Display the Memory Size */
1582bcbf80cSPeter Tribble 		display_memorysize(tree, NULL, &memory_total);
15903831d35Sstevel 
16003831d35Sstevel 		/* Display the CPU devices */
16103831d35Sstevel 		sun4v_display_cpu_devices(plafh);
16203831d35Sstevel 
16303831d35Sstevel 		/* Display the Memory configuration */
1640d63ce2bSvenki 		class_node_found = 0;
1650d63ce2bSvenki 		sun4v_display_memory_conf(plafh);
16603831d35Sstevel 
16703831d35Sstevel 		/* Display all the IO cards. */
16803831d35Sstevel 		(void) sun4v_display_pci(plafh);
1690d63ce2bSvenki 		sun4v_display_diaginfo((log || (logging)), root, plafh);
17003831d35Sstevel 
1710d63ce2bSvenki 		if (picl_get_root(&rooth) != PICL_SUCCESS)
1720d63ce2bSvenki 			return (1);
173d776656fSmb 
174d776656fSmb 		/*
175d776656fSmb 		 * The physical-platform node may be missing on systems with
176d776656fSmb 		 * older firmware so don't consider that an error.
177d776656fSmb 		 */
1780d63ce2bSvenki 		if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM,
179a90d965dSfw 		    &phyplatformh) != PICL_SUCCESS)
180d776656fSmb 			return (0);
1810d63ce2bSvenki 
1820d63ce2bSvenki 		if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME,
183a90d965dSfw 		    PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS,
184a90d965dSfw 		    strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS)
1850d63ce2bSvenki 			return (1);
1860d63ce2bSvenki 
1870d63ce2bSvenki 		syserrlog = log;
188d776656fSmb 		exit_code = sun4v_disp_env_status();
1890d63ce2bSvenki 	}
190d776656fSmb 	return (exit_code);
1910d63ce2bSvenki }
1920d63ce2bSvenki 
193db8f0877Sfw /*
194db8f0877Sfw  * The binding-name property encodes the bus type.
195db8f0877Sfw  */
1960d63ce2bSvenki static void
get_bus_type(picl_nodehdl_t nodeh,struct io_card * card)1970d63ce2bSvenki get_bus_type(picl_nodehdl_t nodeh, struct io_card *card)
1980d63ce2bSvenki {
199db8f0877Sfw 	char val[PICL_PROPNAMELEN_MAX], *p, *q;
2000d63ce2bSvenki 
201db8f0877Sfw 	card->bus_type[0] = '\0';
202db8f0877Sfw 
203db8f0877Sfw 	if (picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, val,
204db8f0877Sfw 	    sizeof (val)) == PICL_SUCCESS) {
205db8f0877Sfw 		if (strstr(val, PICL_CLASS_PCIEX))
2064c5e0fdeSvivek 			(void) strlcpy(card->bus_type, "PCIE",
207a90d965dSfw 			    sizeof (card->bus_type));
208db8f0877Sfw 		else if (strstr(val, PICL_CLASS_PCI))
209db8f0877Sfw 			(void) strlcpy(card->bus_type, "PCIX",
210db8f0877Sfw 			    sizeof (card->bus_type));
211db8f0877Sfw 		else {
212db8f0877Sfw 			/*
213db8f0877Sfw 			 * Not perfect: process the binding-name until
214db8f0877Sfw 			 * we encounter something that we don't think would
215db8f0877Sfw 			 * be part of a bus type.  This may get confused a bit
216db8f0877Sfw 			 * if a device or vendor id is encoded right after
217db8f0877Sfw 			 * the bus class since there's no delimiter.  If the
218db8f0877Sfw 			 * id number begins with a hex digit [abcdef] then
219db8f0877Sfw 			 * this will become part of the bus type string
220db8f0877Sfw 			 * reported by prtdiag.  This is all an effort to
221db8f0877Sfw 			 * print something potentially useful for bus types
222db8f0877Sfw 			 * other than PCI/PCIe.
223db8f0877Sfw 			 *
224db8f0877Sfw 			 * We do this because this code will get called for
225db8f0877Sfw 			 * non-PCI class devices like the xaui (class sun4v.)
226db8f0877Sfw 			 */
227db8f0877Sfw 			if (strstr(val, "SUNW,") != NULL)
228db8f0877Sfw 				p = strchr(val, ',') + 1;
229db8f0877Sfw 			else
230db8f0877Sfw 				p = val;
231db8f0877Sfw 			q = p;
232db8f0877Sfw 			while (*p != '\0') {
233db8f0877Sfw 				if (isdigit((char)*p) || ispunct((char)*p)) {
234db8f0877Sfw 					*p = '\0';
235db8f0877Sfw 					break;
236db8f0877Sfw 				}
237db8f0877Sfw 				*p = (char)_toupper((int)*p);
238db8f0877Sfw 				++p;
239db8f0877Sfw 			}
240db8f0877Sfw 			(void) strlcpy(card->bus_type, q,
241db8f0877Sfw 			    sizeof (card->bus_type));
242db8f0877Sfw 		}
2430d63ce2bSvenki 	}
2440d63ce2bSvenki }
2450d63ce2bSvenki 
246db8f0877Sfw /*
247db8f0877Sfw  * Fetch the Label property for this device.  If none is found then
248db8f0877Sfw  * search all the siblings with the same device ID for a
249db8f0877Sfw  * Label and return that Label.  The plug-in can only match the canonical
250db8f0877Sfw  * path from the PRI with a specific devfs path.  So we take care of
251db8f0877Sfw  * devices with multiple functions here.  A leaf device downstream of
252db8f0877Sfw  * a bridge should fall out of here with PICL_PROPNOTFOUND, and the
253db8f0877Sfw  * caller can walk back up the tree in search of the slot's Label.
254db8f0877Sfw  */
2550d63ce2bSvenki static picl_errno_t
get_slot_label(picl_nodehdl_t nodeh,struct io_card * card)2560d63ce2bSvenki get_slot_label(picl_nodehdl_t nodeh, struct io_card *card)
2570d63ce2bSvenki {
2580d63ce2bSvenki 	char val[PICL_PROPNAMELEN_MAX];
2590d63ce2bSvenki 	picl_errno_t err;
260dc6ca969Sfw 	picl_nodehdl_t pnodeh;
261db8f0877Sfw 	uint32_t devid, sib_devid;
262db8f0877Sfw 	int32_t instance;
2630d63ce2bSvenki 
264dc6ca969Sfw 	/*
265db8f0877Sfw 	 * If there's a Label at this node then return it - we're
266db8f0877Sfw 	 * done.
267dc6ca969Sfw 	 */
2680d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
269a90d965dSfw 	    sizeof (val));
270db8f0877Sfw 	if (err == PICL_SUCCESS) {
271dc6ca969Sfw 		(void) strlcpy(card->slot_str, val, sizeof (card->slot_str));
272db8f0877Sfw 		return (err);
273db8f0877Sfw 	} else if (err != PICL_PROPNOTFOUND)
274db8f0877Sfw 		return (err);
275db8f0877Sfw 
276db8f0877Sfw 	/*
277db8f0877Sfw 	 * At this point we're starting to extrapolate what the Label
278db8f0877Sfw 	 * should be since there is none at this specific node.
279db8f0877Sfw 	 * Note that until the value of "err" is overwritten in the
280db8f0877Sfw 	 * loop below, its value should be PICL_PROPNOTFOUND.
281db8f0877Sfw 	 */
282db8f0877Sfw 
283db8f0877Sfw 	/*
284db8f0877Sfw 	 * The device must be attached, and we can figure that out if
285db8f0877Sfw 	 * the instance number is present and is not equal to -1.
286db8f0877Sfw 	 * This will prevent is from returning a Label for a sibling
287db8f0877Sfw 	 * node when the node passed in would have a unique Label if the
288db8f0877Sfw 	 * device were attached.  But if the device is downstream of a
289db8f0877Sfw 	 * node with a Label then pci_callback() will still find that
290db8f0877Sfw 	 * and use it.
291db8f0877Sfw 	 */
292db8f0877Sfw 	if (picl_get_propval_by_name(nodeh, PICL_PROP_INSTANCE, &instance,
293db8f0877Sfw 	    sizeof (instance)) != PICL_SUCCESS)
294db8f0877Sfw 		return (err);
295db8f0877Sfw 	if (instance == -1)
296db8f0877Sfw 		return (err);
297db8f0877Sfw 
298db8f0877Sfw 	/*
299db8f0877Sfw 	 * Narrow the search to just the one device ID.
300db8f0877Sfw 	 */
301db8f0877Sfw 	if (picl_get_propval_by_name(nodeh, PICL_PROP_DEVICE_ID, &devid,
302db8f0877Sfw 	    sizeof (devid)) != PICL_SUCCESS)
303db8f0877Sfw 		return (err);
304db8f0877Sfw 
305db8f0877Sfw 	/*
306db8f0877Sfw 	 * Go find the first child of the parent so we can search
307db8f0877Sfw 	 * all of the siblings.
308db8f0877Sfw 	 */
309db8f0877Sfw 	if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
310db8f0877Sfw 	    sizeof (pnodeh)) != PICL_SUCCESS)
311db8f0877Sfw 		return (err);
312db8f0877Sfw 	if (picl_get_propval_by_name(pnodeh, PICL_PROP_CHILD, &pnodeh,
313db8f0877Sfw 	    sizeof (pnodeh)) != PICL_SUCCESS)
314db8f0877Sfw 		return (err);
315db8f0877Sfw 
316db8f0877Sfw 	/*
317db8f0877Sfw 	 * If the child's device ID matches, then fetch the Label and
318db8f0877Sfw 	 * return it.  The first child/device ID should have a Label
319db8f0877Sfw 	 * associated with it.
320db8f0877Sfw 	 */
321db8f0877Sfw 	do {
322db8f0877Sfw 		if (picl_get_propval_by_name(pnodeh, PICL_PROP_DEVICE_ID,
323db8f0877Sfw 		    &sib_devid, sizeof (sib_devid)) == PICL_SUCCESS) {
324db8f0877Sfw 			if (sib_devid == devid) {
325db8f0877Sfw 				if ((err = picl_get_propval_by_name(pnodeh,
326db8f0877Sfw 				    PICL_PROP_LABEL, val, sizeof (val))) ==
327db8f0877Sfw 				    PICL_SUCCESS) {
328db8f0877Sfw 					(void) strlcpy(card->slot_str, val,
329db8f0877Sfw 					    sizeof (card->slot_str));
330db8f0877Sfw 					break;
331db8f0877Sfw 				}
332db8f0877Sfw 			}
333db8f0877Sfw 		}
334db8f0877Sfw 	} while (picl_get_propval_by_name(pnodeh, PICL_PROP_PEER, &pnodeh,
335db8f0877Sfw 	    sizeof (pnodeh)) == PICL_SUCCESS);
3360d63ce2bSvenki 
337dc6ca969Sfw 	return (err);
3380d63ce2bSvenki }
3390d63ce2bSvenki 
3400d63ce2bSvenki static void
get_slot_number(picl_nodehdl_t nodeh,struct io_card * card)3410d63ce2bSvenki get_slot_number(picl_nodehdl_t nodeh, struct io_card *card)
3420d63ce2bSvenki {
3430d63ce2bSvenki 	picl_errno_t err;
3440d63ce2bSvenki 	picl_prophdl_t proph;
3450d63ce2bSvenki 	picl_propinfo_t pinfo;
3460d63ce2bSvenki 	picl_nodehdl_t pnodeh;
3470d63ce2bSvenki 	uint8_t *pval;
3480d63ce2bSvenki 	uint32_t dev_mask;
3490d63ce2bSvenki 	char uaddr[MAXSTRLEN];
3500d63ce2bSvenki 	int i;
3510d63ce2bSvenki 
3520d63ce2bSvenki 	err = PICL_SUCCESS;
3530d63ce2bSvenki 	while (err == PICL_SUCCESS) {
3540d63ce2bSvenki 		if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
355a90d965dSfw 		    sizeof (pnodeh)) != PICL_SUCCESS) {
356a90d965dSfw 			(void) strlcpy(card->slot_str, MOTHERBOARD,
357a90d965dSfw 			    sizeof (card->slot_str));
3580d63ce2bSvenki 			card->slot = -1;
3590d63ce2bSvenki 			return;
3600d63ce2bSvenki 		}
3610d63ce2bSvenki 		if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES,
362a90d965dSfw 		    &pinfo, &proph) == PICL_SUCCESS) {
3630d63ce2bSvenki 			break;
3640d63ce2bSvenki 		}
3650d63ce2bSvenki 		nodeh = pnodeh;
3660d63ce2bSvenki 	}
3670d63ce2bSvenki 	if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr,
368a90d965dSfw 	    sizeof (uaddr)) != PICL_SUCCESS) {
369a90d965dSfw 		(void) strlcpy(card->slot_str, MOTHERBOARD,
370a90d965dSfw 		    sizeof (card->slot_str));
3710d63ce2bSvenki 		card->slot = -1;
3720d63ce2bSvenki 		return;
3730d63ce2bSvenki 	}
3740d63ce2bSvenki 	pval = (uint8_t *)malloc(pinfo.size);
3750d63ce2bSvenki 	if (!pval) {
376a90d965dSfw 		(void) strlcpy(card->slot_str, MOTHERBOARD,
377a90d965dSfw 		    sizeof (card->slot_str));
3780d63ce2bSvenki 		card->slot = -1;
3790d63ce2bSvenki 		return;
3800d63ce2bSvenki 	}
3810d63ce2bSvenki 	if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) {
382a90d965dSfw 		(void) strlcpy(card->slot_str, MOTHERBOARD,
383a90d965dSfw 		    sizeof (card->slot_str));
3840d63ce2bSvenki 		card->slot = -1;
3850d63ce2bSvenki 		free(pval);
3860d63ce2bSvenki 		return;
38703831d35Sstevel 	}
38803831d35Sstevel 
3890d63ce2bSvenki 	dev_mask = 0;
3900d63ce2bSvenki 	for (i = 0; i < sizeof (dev_mask); i++)
3910d63ce2bSvenki 		dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i));
3920d63ce2bSvenki 	for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) {
3930d63ce2bSvenki 		if (uaddr[i] == ',') {
3940d63ce2bSvenki 			uaddr[i] = '\0';
3950d63ce2bSvenki 			break;
3960d63ce2bSvenki 		}
3970d63ce2bSvenki 	}
3980d63ce2bSvenki 	card->slot = atol(uaddr);
3990d63ce2bSvenki 	if (((1 << card->slot) & dev_mask) == 0) {
400a90d965dSfw 		(void) strlcpy(card->slot_str, MOTHERBOARD,
401a90d965dSfw 		    sizeof (card->slot_str));
4020d63ce2bSvenki 		card->slot = -1;
4030d63ce2bSvenki 	} else {
4040d63ce2bSvenki 		char *p = (char *)(pval+sizeof (dev_mask));
4050d63ce2bSvenki 		int shift = sizeof (uint32_t)*8-1-card->slot;
4060d63ce2bSvenki 		uint32_t x = (dev_mask << shift) >> shift;
4070d63ce2bSvenki 		int count = 0;	/* count # of 1's in x */
4080d63ce2bSvenki 		int i = 0;
4090d63ce2bSvenki 		while (x != 0) {
4100d63ce2bSvenki 			count++;
4110d63ce2bSvenki 			x &= x-1;
4120d63ce2bSvenki 		}
4130d63ce2bSvenki 		while (count > 1) {
414a90d965dSfw 			while (p[i++] != '\0')
415a90d965dSfw 				;
4160d63ce2bSvenki 			count--;
4170d63ce2bSvenki 		}
4184c5e0fdeSvivek 		(void) strlcpy(card->slot_str, (char *)(p+i),
419a90d965dSfw 		    sizeof (card->slot_str));
4200d63ce2bSvenki 	}
4210d63ce2bSvenki 	free(pval);
4220d63ce2bSvenki }
4230d63ce2bSvenki 
4240d63ce2bSvenki /*
4250d63ce2bSvenki  * add all io devices under pci in io list
4260d63ce2bSvenki  */
4270d63ce2bSvenki /* ARGSUSED */
4280d63ce2bSvenki static int
sun4v_pci_callback(picl_nodehdl_t pcih,void * args)4290d63ce2bSvenki sun4v_pci_callback(picl_nodehdl_t pcih, void *args)
4300d63ce2bSvenki {
4310d63ce2bSvenki 	char path[PICL_PROPNAMELEN_MAX];
4320d63ce2bSvenki 	char class[PICL_CLASSNAMELEN_MAX];
4330d63ce2bSvenki 	char name[PICL_PROPNAMELEN_MAX];
4340d63ce2bSvenki 	char model[PICL_PROPNAMELEN_MAX];
4350d63ce2bSvenki 	char binding_name[PICL_PROPNAMELEN_MAX];
4360d63ce2bSvenki 	char val[PICL_PROPNAMELEN_MAX];
4370d63ce2bSvenki 	char *compatible;
4380d63ce2bSvenki 	picl_errno_t err;
439db8f0877Sfw 	picl_nodehdl_t nodeh, pnodeh;
4400d63ce2bSvenki 	struct io_card pci_card;
4410d63ce2bSvenki 
4420d63ce2bSvenki 	/* Walk through the children */
4430d63ce2bSvenki 
4440d63ce2bSvenki 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
445a90d965dSfw 	    sizeof (picl_nodehdl_t));
4460d63ce2bSvenki 
4470d63ce2bSvenki 	while (err == PICL_SUCCESS) {
4480d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
449a90d965dSfw 		    class, sizeof (class));
4500d63ce2bSvenki 		if (err !=  PICL_SUCCESS)
4510d63ce2bSvenki 			return (err);
4520d63ce2bSvenki 
4530d63ce2bSvenki 		if (args) {
4540d63ce2bSvenki 			char *val = args;
4550d63ce2bSvenki 			if (strcmp(class, val) == 0) {
4560d63ce2bSvenki 				err = picl_get_propval_by_name(nodeh,
457a90d965dSfw 				    PICL_PROP_PEER, &nodeh,
458a90d965dSfw 				    sizeof (picl_nodehdl_t));
4590d63ce2bSvenki 				continue;
4600d63ce2bSvenki 			} else if (strcmp(val, PICL_CLASS_PCIEX) == 0 &&
461a90d965dSfw 			    strcmp(class, PICL_CLASS_PCI) == 0) {
4620d63ce2bSvenki 				err = picl_get_propval_by_name(nodeh,
463a90d965dSfw 				    PICL_PROP_PEER, &nodeh,
464a90d965dSfw 				    sizeof (picl_nodehdl_t));
4650d63ce2bSvenki 				continue;
4660d63ce2bSvenki 			} else if (strcmp(val, PICL_CLASS_PCI) == 0 &&
467a90d965dSfw 			    strcmp(class, PICL_CLASS_PCIEX) == 0) {
4680d63ce2bSvenki 				err = picl_get_propval_by_name(nodeh,
469a90d965dSfw 				    PICL_PROP_PEER, &nodeh,
470a90d965dSfw 				    sizeof (picl_nodehdl_t));
4710d63ce2bSvenki 				continue;
4720d63ce2bSvenki 			}
4730d63ce2bSvenki 		}
4740d63ce2bSvenki 
4750d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
476a90d965dSfw 		    path, sizeof (path));
4770d63ce2bSvenki 		if (err != PICL_SUCCESS)
4780d63ce2bSvenki 			return (err);
4790d63ce2bSvenki 
4800d63ce2bSvenki 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
4810d63ce2bSvenki 
482db8f0877Sfw 		pnodeh = nodeh;
483db8f0877Sfw 		err = get_slot_label(nodeh, &pci_card);
484db8f0877Sfw 
485db8f0877Sfw 		/*
486db8f0877Sfw 		 * No Label at this node, maybe we're looking at a device
487db8f0877Sfw 		 * downstream of a bridge.  Walk back up and find a Label and
488db8f0877Sfw 		 * record that node in "pnodeh".
489db8f0877Sfw 		 */
490db8f0877Sfw 		while (err != PICL_SUCCESS) {
491db8f0877Sfw 			if (err != PICL_PROPNOTFOUND)
492db8f0877Sfw 				break;
493db8f0877Sfw 			else if (picl_get_propval_by_name(pnodeh,
494db8f0877Sfw 			    PICL_PROP_PARENT, &pnodeh, sizeof (pnodeh)) ==
495db8f0877Sfw 			    PICL_SUCCESS)
496db8f0877Sfw 				err = get_slot_label(pnodeh, &pci_card);
497db8f0877Sfw 			else
498db8f0877Sfw 				break;
499db8f0877Sfw 		}
500db8f0877Sfw 
501db8f0877Sfw 		/*
502db8f0877Sfw 		 * Can't find a Label for this device in the PCI heirarchy.
503db8f0877Sfw 		 * Try to synthesize a slot name from atoms.  This depends
504db8f0877Sfw 		 * on the OBP slot_names property being implemented, and this
505db8f0877Sfw 		 * so far doesn't seem to be on sun4v.  But just in case that
506db8f0877Sfw 		 * is resurrected, the code is here.
507db8f0877Sfw 		 */
508db8f0877Sfw 		if (err != PICL_SUCCESS) {
509db8f0877Sfw 			pnodeh = nodeh;
510db8f0877Sfw 			get_slot_number(nodeh, &pci_card);
511db8f0877Sfw 		}
512db8f0877Sfw 
513db8f0877Sfw 		/*
514db8f0877Sfw 		 * Passing in pnodeh instead of nodeh will cause prtdiag
515db8f0877Sfw 		 * to display the type of IO slot for the leaf node.  For
516db8f0877Sfw 		 * built-in devices and a lot of IO cards these will be
517db8f0877Sfw 		 * the same thing.  But for IO cards with bridge chips or
518db8f0877Sfw 		 * for things like expansion chassis, prtdiag will report
519db8f0877Sfw 		 * the bus type of the IO slot and not the leaf, which
520db8f0877Sfw 		 * could be different things.
521db8f0877Sfw 		 */
522db8f0877Sfw 		get_bus_type(pnodeh, &pci_card);
5230d63ce2bSvenki 
5240d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
525a90d965dSfw 		    sizeof (name));
5260d63ce2bSvenki 		if (err == PICL_PROPNOTFOUND)
5274c5e0fdeSvivek 			(void) strlcpy(name, "", sizeof (name));
5280d63ce2bSvenki 		else if (err != PICL_SUCCESS)
5290d63ce2bSvenki 			return (err);
5300d63ce2bSvenki 
5310d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val,
532a90d965dSfw 		    sizeof (val));
5330d63ce2bSvenki 		if (err == PICL_PROPNOTFOUND)
5344c5e0fdeSvivek 			(void) strlcpy(val, "", sizeof (val));
5350d63ce2bSvenki 		else if (err != PICL_SUCCESS)
5360d63ce2bSvenki 			return (err);
5370d63ce2bSvenki 
538dc6ca969Sfw 		(void) snprintf(pci_card.status, sizeof (pci_card.status),
539dc6ca969Sfw 		    "%s", pci_card.slot_str);
5400d63ce2bSvenki 
5410d63ce2bSvenki 		/*
5420d63ce2bSvenki 		 * Get the name of this card. If binding_name is found,
5430d63ce2bSvenki 		 * name will be <nodename>-<binding_name>.
5440d63ce2bSvenki 		 */
5450d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
546a90d965dSfw 		    binding_name, sizeof (binding_name));
5470d63ce2bSvenki 		if (err == PICL_SUCCESS) {
5480d63ce2bSvenki 			if (strcmp(name, binding_name) != 0) {
5490d63ce2bSvenki 				(void) strlcat(name, "-", sizeof (name));
5500d63ce2bSvenki 				(void) strlcat(name, binding_name,
551a90d965dSfw 				    sizeof (name));
5520d63ce2bSvenki 			}
5530d63ce2bSvenki 		} else if (err == PICL_PROPNOTFOUND) {
5540d63ce2bSvenki 			/*
5550d63ce2bSvenki 			 * if compatible prop is not found, name will be
5560d63ce2bSvenki 			 * <nodename>-<compatible>
5570d63ce2bSvenki 			 */
5580d63ce2bSvenki 			err = sun4v_get_first_compatible_value(nodeh,
559a90d965dSfw 			    &compatible);
5600d63ce2bSvenki 			if (err == PICL_SUCCESS) {
5610d63ce2bSvenki 				(void) strlcat(name, "-", sizeof (name));
5624c5e0fdeSvivek 				(void) strlcat(name, compatible,
563a90d965dSfw 				    sizeof (name));
5640d63ce2bSvenki 				free(compatible);
5650d63ce2bSvenki 			}
5660d63ce2bSvenki 		} else
5670d63ce2bSvenki 			return (err);
5680d63ce2bSvenki 
5690d63ce2bSvenki 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
5700d63ce2bSvenki 
5710d63ce2bSvenki 		/* Get the model of this card */
5720d63ce2bSvenki 
5730d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
574a90d965dSfw 		    model, sizeof (model));
5750d63ce2bSvenki 		if (err == PICL_PROPNOTFOUND)
5764c5e0fdeSvivek 			(void) strlcpy(model, "", sizeof (model));
5770d63ce2bSvenki 		else if (err != PICL_SUCCESS)
5780d63ce2bSvenki 			return (err);
5790d63ce2bSvenki 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
5800d63ce2bSvenki 
5810d63ce2bSvenki 		/* Print NAC name */
582aaba19e2Sfw 		log_printf("%-18s", pci_card.status);
5830d63ce2bSvenki 		/* Print IO Type */
5840d63ce2bSvenki 		log_printf("%-6s", pci_card.bus_type);
5850d63ce2bSvenki 		/* Printf Card Name */
5867ae4bfcbSfw 		log_printf("%-34s", pci_card.name);
5870d63ce2bSvenki 		/* Print Card Model */
5880d63ce2bSvenki 		log_printf("%-8s", pci_card.model);
5890d63ce2bSvenki 		log_printf("\n");
5900d63ce2bSvenki 		/* Print Status */
591aaba19e2Sfw 		log_printf("%-18s", val);
5920d63ce2bSvenki 		/* Print IO Type */
5930d63ce2bSvenki 		log_printf("%-6s", "");
5940d63ce2bSvenki 		/* Print Parent Path */
595aaba19e2Sfw 		log_printf("%-44s", pci_card.notes);
5960d63ce2bSvenki 		log_printf("\n");
5970d63ce2bSvenki 
5980d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
599a90d965dSfw 		    sizeof (picl_nodehdl_t));
6000d63ce2bSvenki 	}
6010d63ce2bSvenki 	return (PICL_WALK_CONTINUE);
60203831d35Sstevel }
60303831d35Sstevel 
60403831d35Sstevel /*
60503831d35Sstevel  * display_pci
60603831d35Sstevel  * Display all the PCI IO cards on this board.
60703831d35Sstevel  */
60803831d35Sstevel void
sun4v_display_pci(picl_nodehdl_t plafh)60903831d35Sstevel sun4v_display_pci(picl_nodehdl_t plafh)
61003831d35Sstevel {
6117ae4bfcbSfw 	char *fmt = "%-17s %-5s %-33s %-8s";
6120d63ce2bSvenki 	/* Have we printed the column headings? */
6130d63ce2bSvenki 	static int banner = FALSE;
6140d63ce2bSvenki 
6150d63ce2bSvenki 	if (banner == FALSE) {
6160d63ce2bSvenki 		log_printf("\n");
617aaba19e2Sfw 		log_printf("================================");
6180d63ce2bSvenki 		log_printf(" IO Devices ");
619aaba19e2Sfw 		log_printf("================================");
6200d63ce2bSvenki 		log_printf("\n");
6210d63ce2bSvenki 		log_printf(fmt, "Slot +", "Bus", "Name +", "Model", 0);
6220d63ce2bSvenki 		log_printf("\n");
6230d63ce2bSvenki 		log_printf(fmt, "Status", "Type", "Path", "", 0);
6240d63ce2bSvenki 		log_printf("\n");
6250d63ce2bSvenki 		log_printf("---------------------------------"
626aaba19e2Sfw 		    "-------------------------------------------\n");
6270d63ce2bSvenki 		banner = TRUE;
6280d63ce2bSvenki 	}
6290d63ce2bSvenki 
6300d63ce2bSvenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
631a90d965dSfw 	    PICL_CLASS_PCIEX, sun4v_pci_callback);
6320d63ce2bSvenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
633a90d965dSfw 	    PICL_CLASS_PCI, sun4v_pci_callback);
6340d63ce2bSvenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V,
635a90d965dSfw 	    PICL_CLASS_SUN4V, sun4v_pci_callback);
63603831d35Sstevel }
63703831d35Sstevel 
6380d63ce2bSvenki /*
6390d63ce2bSvenki  * return the first compatible value
6400d63ce2bSvenki  */
6410d63ce2bSvenki static int
sun4v_get_first_compatible_value(picl_nodehdl_t nodeh,char ** outbuf)6420d63ce2bSvenki sun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
6430d63ce2bSvenki {
6440d63ce2bSvenki 	picl_errno_t err;
6450d63ce2bSvenki 	picl_prophdl_t proph;
6460d63ce2bSvenki 	picl_propinfo_t pinfo;
6470d63ce2bSvenki 	picl_prophdl_t tblh;
6480d63ce2bSvenki 	picl_prophdl_t rowproph;
6490d63ce2bSvenki 	char *pval;
6500d63ce2bSvenki 
6510d63ce2bSvenki 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
652a90d965dSfw 	    &pinfo, &proph);
6530d63ce2bSvenki 	if (err != PICL_SUCCESS)
6540d63ce2bSvenki 		return (err);
6550d63ce2bSvenki 
6560d63ce2bSvenki 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
6570d63ce2bSvenki 		pval = malloc(pinfo.size);
6580d63ce2bSvenki 		if (pval == NULL)
6590d63ce2bSvenki 			return (PICL_FAILURE);
6600d63ce2bSvenki 		err = picl_get_propval(proph, pval, pinfo.size);
6610d63ce2bSvenki 		if (err != PICL_SUCCESS) {
6620d63ce2bSvenki 			free(pval);
6630d63ce2bSvenki 			return (err);
6640d63ce2bSvenki 		}
6650d63ce2bSvenki 		*outbuf = pval;
6660d63ce2bSvenki 		return (PICL_SUCCESS);
6670d63ce2bSvenki 	}
6680d63ce2bSvenki 
6690d63ce2bSvenki 	if (pinfo.type != PICL_PTYPE_TABLE)
6700d63ce2bSvenki 		return (PICL_FAILURE);
6710d63ce2bSvenki 
6720d63ce2bSvenki 	/* get first string from table */
6730d63ce2bSvenki 	err = picl_get_propval(proph, &tblh, pinfo.size);
6740d63ce2bSvenki 	if (err != PICL_SUCCESS)
6750d63ce2bSvenki 		return (err);
6760d63ce2bSvenki 
6770d63ce2bSvenki 	err = picl_get_next_by_row(tblh, &rowproph);
6780d63ce2bSvenki 	if (err != PICL_SUCCESS)
6790d63ce2bSvenki 		return (err);
6800d63ce2bSvenki 
6810d63ce2bSvenki 	err = picl_get_propinfo(rowproph, &pinfo);
6820d63ce2bSvenki 	if (err != PICL_SUCCESS)
6830d63ce2bSvenki 		return (err);
6840d63ce2bSvenki 
6850d63ce2bSvenki 	pval = malloc(pinfo.size);
6860d63ce2bSvenki 	if (pval == NULL)
6870d63ce2bSvenki 		return (PICL_FAILURE);
6880d63ce2bSvenki 
6890d63ce2bSvenki 	err = picl_get_propval(rowproph, pval, pinfo.size);
6900d63ce2bSvenki 	if (err != PICL_SUCCESS) {
6910d63ce2bSvenki 		free(pval);
6920d63ce2bSvenki 		return (err);
6930d63ce2bSvenki 	}
6940d63ce2bSvenki 
6950d63ce2bSvenki 	*outbuf = pval;
6960d63ce2bSvenki 	return (PICL_SUCCESS);
6970d63ce2bSvenki }
6980d63ce2bSvenki 
6990d63ce2bSvenki /*
7000d63ce2bSvenki  * print size of a memory segment
7010d63ce2bSvenki  */
7020d63ce2bSvenki static void
print_memory_segment_size(uint64_t size)7030d63ce2bSvenki print_memory_segment_size(uint64_t size)
7040d63ce2bSvenki {
7050d63ce2bSvenki 	uint64_t kbyte = 1024;
7060d63ce2bSvenki 	uint64_t mbyte = kbyte * kbyte;
7070d63ce2bSvenki 	uint64_t gbyte = kbyte * mbyte;
7087ae4bfcbSfw 	uint64_t tbyte = kbyte * gbyte;
7090d63ce2bSvenki 	char buf[MEMORY_SIZE_FIELD];
7100d63ce2bSvenki 
7117ae4bfcbSfw 	if (size >= tbyte) {
7127ae4bfcbSfw 		if (size % tbyte == 0)
7137ae4bfcbSfw 			(void) snprintf(buf, sizeof (buf), "%d TB",
7147ae4bfcbSfw 			    (int)(size / tbyte));
7157ae4bfcbSfw 		else
7167ae4bfcbSfw 			(void) snprintf(buf, sizeof (buf), "%.2f TB",
7177ae4bfcbSfw 			    (float)size / tbyte);
7187ae4bfcbSfw 	} else if (size >= gbyte) {
7190d63ce2bSvenki 		if (size % gbyte == 0)
7200d63ce2bSvenki 			(void) snprintf(buf, sizeof (buf), "%d GB",
721a90d965dSfw 			    (int)(size / gbyte));
7220d63ce2bSvenki 		else
7230d63ce2bSvenki 			(void) snprintf(buf, sizeof (buf), "%.2f GB",
724a90d965dSfw 			    (float)size / gbyte);
7250d63ce2bSvenki 	} else if (size >= mbyte) {
7260d63ce2bSvenki 		if (size % mbyte == 0)
7270d63ce2bSvenki 			(void) snprintf(buf, sizeof (buf), "%d MB",
728a90d965dSfw 			    (int)(size / mbyte));
7290d63ce2bSvenki 		else
7300d63ce2bSvenki 			(void) snprintf(buf, sizeof (buf), "%.2f MB",
731a90d965dSfw 			    (float)size / mbyte);
7320d63ce2bSvenki 	} else {
7330d63ce2bSvenki 		if (size % kbyte == 0)
7340d63ce2bSvenki 			(void) snprintf(buf, sizeof (buf), "%d KB",
735a90d965dSfw 			    (int)(size / kbyte));
7360d63ce2bSvenki 		else
7370d63ce2bSvenki 			(void) snprintf(buf, sizeof (buf), "%.2f KB",
738a90d965dSfw 			    (float)size / kbyte);
7390d63ce2bSvenki 	}
7407ae4bfcbSfw 	log_printf("%-9s", buf);
7410d63ce2bSvenki }
7420d63ce2bSvenki 
7430d63ce2bSvenki /*
744a90d965dSfw  * Enumerate banks and dimms within a memory segment.  We're handed
745a90d965dSfw  * the first bank within the segment - we assume there are dimms
746a90d965dSfw  * (memory-module) nodes underneath.
7470d63ce2bSvenki  */
7480d63ce2bSvenki static void
print_memory_segment_contain(picl_nodehdl_t bank_nodeh)749a90d965dSfw print_memory_segment_contain(picl_nodehdl_t bank_nodeh)
7500d63ce2bSvenki {
7510d63ce2bSvenki 	char val[PICL_PROPNAMELEN_MAX];
752a90d965dSfw 	picl_nodehdl_t module_nodeh;
753a90d965dSfw 	int flag = 0;
7547ae4bfcbSfw 	uint64_t size;
755a90d965dSfw 
756a90d965dSfw 	do {
757a90d965dSfw 		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_CHILD,
758a90d965dSfw 		    &module_nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
759a90d965dSfw 			continue;
7607ae4bfcbSfw 		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_SIZE,
7617ae4bfcbSfw 		    &size, sizeof (size)) == PICL_SUCCESS) {
7627ae4bfcbSfw 			if (!flag) {
7637ae4bfcbSfw 				print_memory_segment_size(size);
7647ae4bfcbSfw 			} else {
7657ae4bfcbSfw 				log_printf("                "
7667ae4bfcbSfw 				    "                    ");
7677ae4bfcbSfw 				print_memory_segment_size(size);
7687ae4bfcbSfw 				flag = 0;
7697ae4bfcbSfw 			}
7707ae4bfcbSfw 		}
771a90d965dSfw 		do {
772a90d965dSfw 			if (picl_get_propval_by_name(module_nodeh,
773a90d965dSfw 			    PICL_PROP_NAC, val, sizeof (val)) !=
774a90d965dSfw 			    PICL_SUCCESS)
775a90d965dSfw 				continue;
776a90d965dSfw 			else {
777a90d965dSfw 				if (!flag) {
7787ae4bfcbSfw 					log_printf("%s\n", val);
779a90d965dSfw 					flag = 1;
7807ae4bfcbSfw 				} else {
7817ae4bfcbSfw 					log_printf("%s%s\n",
7827ae4bfcbSfw 					    "                       "
7837ae4bfcbSfw 					    "                      ",
7847ae4bfcbSfw 					    val);
7857ae4bfcbSfw 				}
786a90d965dSfw 			}
787a90d965dSfw 		} while (picl_get_propval_by_name(module_nodeh, PICL_PROP_PEER,
788a90d965dSfw 		    &module_nodeh, sizeof (picl_nodehdl_t)) ==
789a90d965dSfw 		    PICL_SUCCESS);
790a90d965dSfw 	} while (picl_get_propval_by_name(bank_nodeh, PICL_PROP_PEER,
791a90d965dSfw 	    &bank_nodeh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS);
7920d63ce2bSvenki }
7930d63ce2bSvenki 
7940d63ce2bSvenki /*
7950d63ce2bSvenki  * Search node where _class=="memory-segment"
7960d63ce2bSvenki  * print "Base Address", "Size", etc
7970d63ce2bSvenki  */
7980d63ce2bSvenki /*ARGSUSED*/
7990d63ce2bSvenki static int
sun4v_memory_conf_callback(picl_nodehdl_t nodeh,void * args)8000d63ce2bSvenki sun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args)
8010d63ce2bSvenki {
8020d63ce2bSvenki 	uint64_t base;
8030d63ce2bSvenki 	uint64_t size;
8040d63ce2bSvenki 	uint64_t ifactor;
8050d63ce2bSvenki 	picl_errno_t err = PICL_SUCCESS;
8060d63ce2bSvenki 
8070d63ce2bSvenki 	if (class_node_found == 0) {
8080d63ce2bSvenki 		class_node_found = 1;
8090d63ce2bSvenki 		return (PICL_WALK_TERMINATE);
8100d63ce2bSvenki 	}
8110d63ce2bSvenki 	while (err == PICL_SUCCESS) {
8120d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS,
813a90d965dSfw 		    &base, sizeof (base));
8140d63ce2bSvenki 		if (err !=  PICL_SUCCESS)
8150d63ce2bSvenki 			break;
8160d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE,
817a90d965dSfw 		    &size, sizeof (size));
8180d63ce2bSvenki 		if (err !=  PICL_SUCCESS)
8190d63ce2bSvenki 			break;
8200d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh,
821a90d965dSfw 		    PICL_PROP_INTERLEAVE_FACTOR, &ifactor,
822a90d965dSfw 		    sizeof (ifactor));
8230d63ce2bSvenki 		if (err !=  PICL_SUCCESS)
8240d63ce2bSvenki 			break;
8257ae4bfcbSfw 		log_printf("0x%-13llx", base);
8260d63ce2bSvenki 		print_memory_segment_size(size);
8277ae4bfcbSfw 		log_printf("%-12lld", ifactor);
828a90d965dSfw 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
829a90d965dSfw 		    &nodeh, sizeof (nodeh));
830a90d965dSfw 		if (err ==  PICL_SUCCESS)
831a90d965dSfw 			print_memory_segment_contain(nodeh);
8320d63ce2bSvenki 		log_printf("\n");
8330d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
834a90d965dSfw 		    sizeof (picl_nodehdl_t));
8350d63ce2bSvenki 	}
8360d63ce2bSvenki 
8370d63ce2bSvenki 	return (PICL_WALK_CONTINUE);
8380d63ce2bSvenki }
8390d63ce2bSvenki 
8400d63ce2bSvenki /*ARGSUSED*/
84103831d35Sstevel void
sun4v_display_memory_conf(picl_nodehdl_t plafh)8420d63ce2bSvenki sun4v_display_memory_conf(picl_nodehdl_t plafh)
84303831d35Sstevel {
8447ae4bfcbSfw 	char *fmt = "%-14s %-8s %-11s %-8s %-s";
8450d63ce2bSvenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
846a90d965dSfw 	    NULL, sun4v_memory_conf_callback);
8470d63ce2bSvenki 	if (class_node_found == 0)
8480d63ce2bSvenki 		return;
8490d63ce2bSvenki 	log_printf("\n");
8507ae4bfcbSfw 	log_printf("=======================");
8517ae4bfcbSfw 	log_printf(" Physical Memory Configuration ");
8527ae4bfcbSfw 	log_printf("========================");
8530d63ce2bSvenki 	log_printf("\n");
8540d63ce2bSvenki 	log_printf("Segment Table:\n");
855a90d965dSfw 	log_printf(
8567ae4bfcbSfw 	    "--------------------------------------------------------------\n");
8577ae4bfcbSfw 	log_printf(fmt, "Base", "Segment", "Interleave", "Bank", "Contains", 0);
8587ae4bfcbSfw 	log_printf("\n");
8597ae4bfcbSfw 	log_printf(fmt, "Address", "Size", "Factor", "Size", "Modules", 0);
8600d63ce2bSvenki 	log_printf("\n");
861a90d965dSfw 	log_printf(
8627ae4bfcbSfw 	    "--------------------------------------------------------------\n");
8630d63ce2bSvenki 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
864a90d965dSfw 	    NULL, sun4v_memory_conf_callback);
86503831d35Sstevel }
86603831d35Sstevel 
86703831d35Sstevel void
sun4v_display_cpu_devices(picl_nodehdl_t plafh)86803831d35Sstevel sun4v_display_cpu_devices(picl_nodehdl_t plafh)
86903831d35Sstevel {
8707ae4bfcbSfw 	char *fmt = "%-6s %-9s %-22s %-6s";
87103831d35Sstevel 
87203831d35Sstevel 	/*
87303831d35Sstevel 	 * Display the table header for CPUs . Then display the CPU
87403831d35Sstevel 	 * frequency, cache size, and processor revision of all cpus.
87503831d35Sstevel 	 */
87603831d35Sstevel 	log_printf(dgettext(TEXT_DOMAIN,
877a90d965dSfw 	    "\n"
8787ae4bfcbSfw 	    "================================"
8797ae4bfcbSfw 	    " Virtual CPUs "
8807ae4bfcbSfw 	    "================================"
881a90d965dSfw 	    "\n"
882a90d965dSfw 	    "\n"));
88303831d35Sstevel 	log_printf("\n");
8847ae4bfcbSfw 	log_printf(fmt, "CPU ID", "Frequency", "Implementation",
8857ae4bfcbSfw 	    "Status", 0);
88603831d35Sstevel 	log_printf("\n");
8877ae4bfcbSfw 	log_printf(fmt, "------", "---------",
8887ae4bfcbSfw 	    "----------------------", "-------", 0);
88903831d35Sstevel 	log_printf("\n");
89003831d35Sstevel 
8917ae4bfcbSfw 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
8927ae4bfcbSfw 	    sun4v_display_cpus);
89303831d35Sstevel }
89403831d35Sstevel 
89503831d35Sstevel /*
89603831d35Sstevel  * Display the CPUs present on this board.
89703831d35Sstevel  */
89803831d35Sstevel /*ARGSUSED*/
89903831d35Sstevel int
sun4v_display_cpus(picl_nodehdl_t cpuh,void * args)90003831d35Sstevel sun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
90103831d35Sstevel {
90203831d35Sstevel 	int status;
9030d63ce2bSvenki 	picl_prophdl_t proph;
9040d63ce2bSvenki 	picl_prophdl_t tblh;
9050d63ce2bSvenki 	picl_prophdl_t rowproph;
90603831d35Sstevel 	picl_propinfo_t propinfo;
9070d63ce2bSvenki 	int *int_value;
9085e3e415aSfw 	int cpuid;
9090d63ce2bSvenki 	char *comp_value;
9100d63ce2bSvenki 	char *no_prop_value = "   ";
9110d63ce2bSvenki 	char freq_str[MAXSTRLEN];
9125e3e415aSfw 	char state[MAXSTRLEN];
91303831d35Sstevel 
91403831d35Sstevel 	/*
91503831d35Sstevel 	 * Get cpuid property and print it and the NAC name
91603831d35Sstevel 	 */
9177ae4bfcbSfw 	status = picl_get_propinfo_by_name(cpuh, OBP_PROP_CPUID, &propinfo,
9187ae4bfcbSfw 	    &proph);
91903831d35Sstevel 	if (status == PICL_SUCCESS) {
92003831d35Sstevel 		status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
92103831d35Sstevel 		if (status != PICL_SUCCESS) {
9227ae4bfcbSfw 			log_printf("%-7s", no_prop_value);
92303831d35Sstevel 		} else {
9247ae4bfcbSfw 			log_printf("%-7d", cpuid);
92503831d35Sstevel 		}
92603831d35Sstevel 	} else {
9277ae4bfcbSfw 		log_printf("%-7s", no_prop_value);
92803831d35Sstevel 	}
92903831d35Sstevel 
93003831d35Sstevel clock_freq:
93103831d35Sstevel 	status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
932a90d965dSfw 	    &proph);
93303831d35Sstevel 	if (status == PICL_SUCCESS) {
93403831d35Sstevel 		int_value = malloc(propinfo.size);
93503831d35Sstevel 		if (int_value == NULL) {
9367ae4bfcbSfw 			log_printf("%-10s", no_prop_value);
93703831d35Sstevel 			goto compatible;
93803831d35Sstevel 		}
93903831d35Sstevel 		status = picl_get_propval(proph, int_value, propinfo.size);
94003831d35Sstevel 		if (status != PICL_SUCCESS) {
9417ae4bfcbSfw 			log_printf("%-10s", no_prop_value);
94203831d35Sstevel 		} else {
94303831d35Sstevel 			/* Running frequency */
94403831d35Sstevel 			(void) snprintf(freq_str, sizeof (freq_str), "%d MHz",
94503831d35Sstevel 			    CLK_FREQ_TO_MHZ(*int_value));
9467ae4bfcbSfw 			log_printf("%-10s", freq_str);
94703831d35Sstevel 		}
94803831d35Sstevel 		free(int_value);
94903831d35Sstevel 	} else
9507ae4bfcbSfw 		log_printf("%-10s", no_prop_value);
95103831d35Sstevel 
95203831d35Sstevel compatible:
95303831d35Sstevel 	status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
954a90d965dSfw 	    &proph);
95503831d35Sstevel 	if (status == PICL_SUCCESS) {
95603831d35Sstevel 		if (propinfo.type == PICL_PTYPE_CHARSTRING) {
95703831d35Sstevel 			/*
95803831d35Sstevel 			 * Compatible Property only has 1 value
95903831d35Sstevel 			 */
96003831d35Sstevel 			comp_value = malloc(propinfo.size);
96103831d35Sstevel 			if (comp_value == NULL) {
9627ae4bfcbSfw 				log_printf("%-23s", no_prop_value, 0);
9635e3e415aSfw 				goto state;
96403831d35Sstevel 			}
96503831d35Sstevel 			status = picl_get_propval(proph, comp_value,
966a90d965dSfw 			    propinfo.size);
9670d63ce2bSvenki 			if (status != PICL_SUCCESS)
9687ae4bfcbSfw 				log_printf("%-23s", no_prop_value, 0);
9690d63ce2bSvenki 			else
9707ae4bfcbSfw 				log_printf("%-23s", comp_value, 0);
9710d63ce2bSvenki 			free(comp_value);
97203831d35Sstevel 		} else if (propinfo.type == PICL_PTYPE_TABLE) {
97303831d35Sstevel 			/*
97403831d35Sstevel 			 * Compatible Property has multiple values
97503831d35Sstevel 			 */
97603831d35Sstevel 			status = picl_get_propval(proph, &tblh, propinfo.size);
97703831d35Sstevel 			if (status != PICL_SUCCESS) {
9787ae4bfcbSfw 				log_printf("%-23s", no_prop_value, 0);
9795e3e415aSfw 				goto state;
98003831d35Sstevel 			}
98103831d35Sstevel 			status = picl_get_next_by_row(tblh, &rowproph);
98203831d35Sstevel 			if (status != PICL_SUCCESS) {
9837ae4bfcbSfw 				log_printf("%-23s", no_prop_value, 0);
9845e3e415aSfw 				goto state;
98503831d35Sstevel 			}
98603831d35Sstevel 
98703831d35Sstevel 			status = picl_get_propinfo(rowproph, &propinfo);
98803831d35Sstevel 			if (status != PICL_SUCCESS) {
9897ae4bfcbSfw 				log_printf("%-23s", no_prop_value, 0);
9905e3e415aSfw 				goto state;
99103831d35Sstevel 			}
99203831d35Sstevel 
99303831d35Sstevel 			comp_value = malloc(propinfo.size);
99403831d35Sstevel 			if (comp_value == NULL) {
9957ae4bfcbSfw 				log_printf("%-23s", no_prop_value, 0);
9965e3e415aSfw 				goto state;
99703831d35Sstevel 			}
99803831d35Sstevel 			status = picl_get_propval(rowproph, comp_value,
999a90d965dSfw 			    propinfo.size);
10000d63ce2bSvenki 			if (status != PICL_SUCCESS)
10017ae4bfcbSfw 				log_printf("%-23s", no_prop_value, 0);
10020d63ce2bSvenki 			else
10037ae4bfcbSfw 				log_printf("%-23s", comp_value, 0);
100403831d35Sstevel 			free(comp_value);
100503831d35Sstevel 		}
100603831d35Sstevel 	} else
10077ae4bfcbSfw 		log_printf("%-23s", no_prop_value, 0);
100803831d35Sstevel 
10095e3e415aSfw state:
10105e3e415aSfw 	status = picl_get_propinfo_by_name(cpuh, PICL_PROP_STATE,
10115e3e415aSfw 	    &propinfo, &proph);
101203831d35Sstevel 	if (status == PICL_SUCCESS) {
10135e3e415aSfw 		status = picl_get_propval(proph, state, sizeof (state));
101403831d35Sstevel 		if (status != PICL_SUCCESS) {
10150d63ce2bSvenki 			log_printf("%-9s", no_prop_value);
101603831d35Sstevel 		} else {
10175e3e415aSfw 			log_printf("%-9s", state);
101803831d35Sstevel 		}
101903831d35Sstevel 	} else
10200d63ce2bSvenki 		log_printf("%-9s", no_prop_value);
102103831d35Sstevel 
102203831d35Sstevel done:
102303831d35Sstevel 	log_printf("\n");
102403831d35Sstevel 	return (PICL_WALK_CONTINUE);
102503831d35Sstevel }
102603831d35Sstevel 
102703831d35Sstevel void
sun4v_display_diaginfo(int flag,Prom_node * root,picl_nodehdl_t plafh)102803831d35Sstevel sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
102903831d35Sstevel {
103003831d35Sstevel #ifdef	lint
103103831d35Sstevel 	flag = flag;
103203831d35Sstevel 	root = root;
103303831d35Sstevel 	plafh = plafh;
103403831d35Sstevel #endif
103503831d35Sstevel 	/*
103603831d35Sstevel 	 * This function is intentionally empty
103703831d35Sstevel 	 */
103803831d35Sstevel }
103903831d35Sstevel 
104003831d35Sstevel void
display_boardnum(int num)104103831d35Sstevel display_boardnum(int num)
104203831d35Sstevel {
104303831d35Sstevel 	log_printf("%2d   ", num, 0);
104403831d35Sstevel }
10450d63ce2bSvenki 
1046d776656fSmb static int
sun4v_disp_env_status()10470d63ce2bSvenki sun4v_disp_env_status()
10480d63ce2bSvenki {
1049d776656fSmb 	int	exit_code = 0;
1050d776656fSmb 
10510d63ce2bSvenki 	if (phyplatformh == 0)
1052d776656fSmb 		return (0);
10530d63ce2bSvenki 	log_printf("\n");
10540d63ce2bSvenki 	log_printf("============================");
10550d63ce2bSvenki 	log_printf(" Environmental Status ");
10560d63ce2bSvenki 	log_printf("============================");
10570d63ce2bSvenki 	log_printf("\n");
10580d63ce2bSvenki 
10590d63ce2bSvenki 	class_node_found = 0;
10600d63ce2bSvenki 	all_status_ok = 1;
10610d63ce2bSvenki 	sun4v_env_print_fan_sensors();
1062d776656fSmb 	exit_code |= (!all_status_ok);
10630d63ce2bSvenki 
10640d63ce2bSvenki 	class_node_found = 0;
10650d63ce2bSvenki 	all_status_ok = 1;
10660d63ce2bSvenki 	sun4v_env_print_fan_indicators();
1067d776656fSmb 	exit_code |= (!all_status_ok);
10680d63ce2bSvenki 
10690d63ce2bSvenki 	class_node_found = 0;
10700d63ce2bSvenki 	all_status_ok = 1;
10710d63ce2bSvenki 	sun4v_env_print_temp_sensors();
1072d776656fSmb 	exit_code |= (!all_status_ok);
10730d63ce2bSvenki 
10740d63ce2bSvenki 	class_node_found = 0;
10750d63ce2bSvenki 	all_status_ok = 1;
10760d63ce2bSvenki 	sun4v_env_print_temp_indicators();
1077d776656fSmb 	exit_code |= (!all_status_ok);
10780d63ce2bSvenki 
10790d63ce2bSvenki 	class_node_found = 0;
10800d63ce2bSvenki 	all_status_ok = 1;
10810d63ce2bSvenki 	sun4v_env_print_current_sensors();
1082d776656fSmb 	exit_code |= (!all_status_ok);
10830d63ce2bSvenki 
10840d63ce2bSvenki 	class_node_found = 0;
10850d63ce2bSvenki 	all_status_ok = 1;
10860d63ce2bSvenki 	sun4v_env_print_current_indicators();
1087d776656fSmb 	exit_code |= (!all_status_ok);
10880d63ce2bSvenki 
10890d63ce2bSvenki 	class_node_found = 0;
10900d63ce2bSvenki 	all_status_ok = 1;
10910d63ce2bSvenki 	sun4v_env_print_voltage_sensors();
1092d776656fSmb 	exit_code |= (!all_status_ok);
10930d63ce2bSvenki 
10940d63ce2bSvenki 	class_node_found = 0;
10950d63ce2bSvenki 	all_status_ok = 1;
10960d63ce2bSvenki 	sun4v_env_print_voltage_indicators();
1097d776656fSmb 	exit_code |= (!all_status_ok);
10980d63ce2bSvenki 
10990d63ce2bSvenki 	class_node_found = 0;
1100d776656fSmb 	all_status_ok = 1;
11010d63ce2bSvenki 	sun4v_env_print_LEDs();
1102d776656fSmb 	exit_code |= (!all_status_ok);
11030d63ce2bSvenki 
11040d63ce2bSvenki 	class_node_found = 0;
11050d63ce2bSvenki 	all_status_ok = 1;
11060d63ce2bSvenki 	sun4v_print_fru_status();
1107d776656fSmb 	exit_code |= (!all_status_ok);
11080d63ce2bSvenki 
11090d63ce2bSvenki 	class_node_found = 0;
11100d63ce2bSvenki 	sun4v_print_fw_rev();
11110d63ce2bSvenki 
1112dc6ca969Sfw 	class_node_found = 0;
1113dc6ca969Sfw 	sun4v_print_openprom_rev();
1114dc6ca969Sfw 
11150d63ce2bSvenki 	sun4v_print_chassis_serial_no();
1116d776656fSmb 
1117d776656fSmb 	return (exit_code);
11180d63ce2bSvenki }
11190d63ce2bSvenki 
11200d63ce2bSvenki /*ARGSUSED*/
11210d63ce2bSvenki static int
sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh,void * args)11220d63ce2bSvenki sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args)
11230d63ce2bSvenki {
11240d63ce2bSvenki 	char val[PICL_PROPNAMELEN_MAX];
11250d63ce2bSvenki 	picl_nodehdl_t parenth;
11260d63ce2bSvenki 	char *names[PARENT_NAMES];
1127aaba19e2Sfw 	char *base_units[PICL_PROPNAMELEN_MAX];
11280d63ce2bSvenki 	char *loc;
11290d63ce2bSvenki 	int i;
11300d63ce2bSvenki 	char *prop;
11310d63ce2bSvenki 	picl_errno_t err;
1132dc6ca969Sfw 	int32_t lo_warning, lo_shutdown, lo_poweroff;
1133dc6ca969Sfw 	int32_t hi_warning, hi_shutdown, hi_poweroff;
11340d63ce2bSvenki 	int32_t current_val;
1135aaba19e2Sfw 	int32_t exponent;
1136aaba19e2Sfw 	double display_val;
1137a42ff480Sfw 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
1138a42ff480Sfw 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
1139a42ff480Sfw 	sensor_status_t sensor_status = SENSOR_OK;
11400d63ce2bSvenki 
11410d63ce2bSvenki 	if (class_node_found == 0) {
11420d63ce2bSvenki 		class_node_found = 1;
11430d63ce2bSvenki 		return (PICL_WALK_TERMINATE);
11440d63ce2bSvenki 	}
11450d63ce2bSvenki 
1146a42ff480Sfw 	prop = (char *)args;
1147a42ff480Sfw 	if (!prop) {
1148a42ff480Sfw 		sensor_status = SENSOR_UNKNOWN;
1149a42ff480Sfw 		all_status_ok = 0;
1150a42ff480Sfw 	} else {
11510d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh,
1152a90d965dSfw 		    PICL_PROP_OPERATIONAL_STATUS, val,
1153a90d965dSfw 		    sizeof (val));
11540d63ce2bSvenki 		if (err == PICL_SUCCESS) {
11550d63ce2bSvenki 			if (strcmp(val, "disabled") == 0) {
1156a42ff480Sfw 				sensor_status = SENSOR_DISABLED;
1157a42ff480Sfw 			}
1158a42ff480Sfw 		}
1159a42ff480Sfw 	}
1160a42ff480Sfw 
1161a42ff480Sfw 	if (sensor_status != SENSOR_DISABLED &&
1162a42ff480Sfw 	    sensor_status != SENSOR_UNKNOWN) {
1163a42ff480Sfw 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
1164a42ff480Sfw 		    sizeof (current_val)) != PICL_SUCCESS) {
1165a42ff480Sfw 			sensor_status = SENSOR_UNKNOWN;
11660d63ce2bSvenki 		} else {
1167dc6ca969Sfw 			if (picl_get_propval_by_name(nodeh,
1168dc6ca969Sfw 			    PICL_PROP_LOW_WARNING,
1169dc6ca969Sfw 			    &lo_warning, sizeof (lo_warning)) != PICL_SUCCESS)
1170dc6ca969Sfw 				lo_warning = INVALID_THRESHOLD;
1171dc6ca969Sfw 			if (picl_get_propval_by_name(nodeh,
1172dc6ca969Sfw 			    PICL_PROP_LOW_SHUTDOWN,
1173dc6ca969Sfw 			    &lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS)
1174dc6ca969Sfw 				lo_shutdown = INVALID_THRESHOLD;
1175dc6ca969Sfw 			if (picl_get_propval_by_name(nodeh,
1176dc6ca969Sfw 			    PICL_PROP_LOW_POWER_OFF,
1177dc6ca969Sfw 			    &lo_poweroff, sizeof (lo_poweroff)) != PICL_SUCCESS)
1178dc6ca969Sfw 				lo_poweroff = INVALID_THRESHOLD;
1179dc6ca969Sfw 			if (picl_get_propval_by_name(nodeh,
1180dc6ca969Sfw 			    PICL_PROP_HIGH_WARNING,
1181dc6ca969Sfw 			    &hi_warning, sizeof (hi_warning)) != PICL_SUCCESS)
1182dc6ca969Sfw 				hi_warning = INVALID_THRESHOLD;
1183dc6ca969Sfw 			if (picl_get_propval_by_name(nodeh,
1184dc6ca969Sfw 			    PICL_PROP_HIGH_SHUTDOWN,
1185dc6ca969Sfw 			    &hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS)
1186dc6ca969Sfw 				hi_shutdown = INVALID_THRESHOLD;
1187dc6ca969Sfw 			if (picl_get_propval_by_name(nodeh,
1188dc6ca969Sfw 			    PICL_PROP_HIGH_POWER_OFF,
1189dc6ca969Sfw 			    &hi_poweroff, sizeof (hi_poweroff)) != PICL_SUCCESS)
1190dc6ca969Sfw 				hi_poweroff = INVALID_THRESHOLD;
1191dc6ca969Sfw 
1192dc6ca969Sfw 			if ((lo_poweroff != INVALID_THRESHOLD &&
1193dc6ca969Sfw 			    current_val <= lo_poweroff) ||
1194dc6ca969Sfw 			    (hi_poweroff != INVALID_THRESHOLD &&
1195dc6ca969Sfw 			    current_val >= hi_poweroff)) {
1196dc6ca969Sfw 				sensor_status = SENSOR_FAILED;
1197dc6ca969Sfw 			} else if ((lo_shutdown != INVALID_THRESHOLD &&
1198dc6ca969Sfw 			    current_val <= lo_shutdown) ||
1199dc6ca969Sfw 			    (hi_shutdown != INVALID_THRESHOLD &&
1200dc6ca969Sfw 			    current_val >= hi_shutdown)) {
1201dc6ca969Sfw 				sensor_status = SENSOR_FAILED;
1202dc6ca969Sfw 			} else if ((lo_warning != INVALID_THRESHOLD &&
1203dc6ca969Sfw 			    current_val <= lo_warning) ||
1204dc6ca969Sfw 			    (hi_warning != INVALID_THRESHOLD &&
1205dc6ca969Sfw 			    current_val >= hi_warning)) {
1206dc6ca969Sfw 				sensor_status = SENSOR_WARN;
1207dc6ca969Sfw 			} else {
1208dc6ca969Sfw 				sensor_status = SENSOR_OK;
1209dc6ca969Sfw 			}
1210a42ff480Sfw 		}
1211a42ff480Sfw 	}
1212a42ff480Sfw 
1213a42ff480Sfw 	if (syserrlog == 0) {
1214a42ff480Sfw 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
12150d63ce2bSvenki 			all_status_ok = 0;
12160d63ce2bSvenki 			return (PICL_WALK_TERMINATE);
12170d63ce2bSvenki 		}
1218a42ff480Sfw 		if (sensor_status == SENSOR_OK) {
1219a42ff480Sfw 			return (PICL_WALK_CONTINUE);
1220a42ff480Sfw 		}
12217ae8c7a8SMichael Bergknoff 	} else {
12227ae8c7a8SMichael Bergknoff 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
12237ae8c7a8SMichael Bergknoff 			all_status_ok = 0;
12247ae8c7a8SMichael Bergknoff 		}
12250d63ce2bSvenki 	}
1226a42ff480Sfw 
1227a42ff480Sfw 	/*
1228a42ff480Sfw 	 * If we're here then prtdiag was invoked with "-v" or we have
1229a42ff480Sfw 	 * a sensor that is beyond a threshold, so give them a book to
1230a42ff480Sfw 	 * read instead of the Cliff Notes.
1231a42ff480Sfw 	 */
12320d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1233a90d965dSfw 	    sizeof (parenth));
12340d63ce2bSvenki 	if (err != PICL_SUCCESS) {
12350d63ce2bSvenki 		log_printf("\n");
12360d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
12370d63ce2bSvenki 	}
12384c5e0fdeSvivek 
1239a42ff480Sfw 	/* gather up the path name for the sensor */
1240a42ff480Sfw 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
1241a42ff480Sfw 		for (i = 0; i < PARENT_NAMES; i++) {
1242a42ff480Sfw 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
1243a42ff480Sfw 			    NULL) {
1244a42ff480Sfw 				while (--i > -1)
1245a42ff480Sfw 					free(names[i]);
1246a42ff480Sfw 				free(loc);
1247a42ff480Sfw 				loc = NULL;
1248a42ff480Sfw 			}
12490d63ce2bSvenki 		}
1250a42ff480Sfw 	}
12510d63ce2bSvenki 	i = 0;
1252a42ff480Sfw 	if (loc != 0) {
1253a42ff480Sfw 		while (err == PICL_SUCCESS) {
1254a42ff480Sfw 			if (parenth == phyplatformh)
1255a42ff480Sfw 				break;
1256a42ff480Sfw 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1257a42ff480Sfw 			    names[i++], PICL_PROPNAMELEN_MAX);
1258a42ff480Sfw 			if (err != PICL_SUCCESS) {
1259a42ff480Sfw 				i--;
1260a42ff480Sfw 				break;
1261a42ff480Sfw 			}
1262a42ff480Sfw 			if (i == PARENT_NAMES)
1263a42ff480Sfw 				break;
1264a42ff480Sfw 			err = picl_get_propval_by_name(parenth,
1265a42ff480Sfw 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
12660d63ce2bSvenki 		}
1267a42ff480Sfw 		loc[0] = '\0';
1268a42ff480Sfw 		if (--i > -1) {
1269a42ff480Sfw 			(void) strlcat(loc, names[i],
1270a42ff480Sfw 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1271a42ff480Sfw 		}
1272a42ff480Sfw 		while (--i > -1) {
1273a42ff480Sfw 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
1274a42ff480Sfw 			    PARENT_NAMES);
1275a42ff480Sfw 			(void) strlcat(loc, names[i],
1276a42ff480Sfw 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1277a42ff480Sfw 		}
12785e3e415aSfw 		log_printf("%-35s", loc);
1279a42ff480Sfw 		for (i = 0; i < PARENT_NAMES; i++)
1280a42ff480Sfw 			free(names[i]);
1281a42ff480Sfw 		free(loc);
1282a42ff480Sfw 	} else {
12835e3e415aSfw 		log_printf("%-35s", " ");
12840d63ce2bSvenki 	}
12850d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
1286a90d965dSfw 	    sizeof (val));
12870d63ce2bSvenki 	if (err == PICL_SUCCESS)
1288bbda49b5SSree Vemuri 		log_printf("%-19s", val);
12890d63ce2bSvenki 
1290a42ff480Sfw 	/*
1291a42ff480Sfw 	 * Get the exponent if present, and do a little math so that
1292a42ff480Sfw 	 * if we need to we can print a normalized value for the
1293a42ff480Sfw 	 * sensor reading.
1294a42ff480Sfw 	 */
1295aaba19e2Sfw 	if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPONENT,
1296aaba19e2Sfw 	    &exponent, sizeof (exponent)) != PICL_SUCCESS)
1297aaba19e2Sfw 		exponent = 0;
1298aaba19e2Sfw 	if (exponent == 0)
1299aaba19e2Sfw 		display_val = (double)current_val;
1300dc6ca969Sfw 	else {
1301aaba19e2Sfw 		display_val = (double)current_val *
1302aaba19e2Sfw 		    pow((double)10, (double)exponent);
1303dc6ca969Sfw 
1304dc6ca969Sfw 		/*
1305dc6ca969Sfw 		 * Sometimes ILOM will scale a sensor reading but
1306dc6ca969Sfw 		 * there will be nothing to the right of the decimal
1307dc6ca969Sfw 		 * once that value is normalized.  Setting the
1308dc6ca969Sfw 		 * exponent to zero will prevent the printf below
1309dc6ca969Sfw 		 * from printing extraneous zeros.  Otherwise a
1310dc6ca969Sfw 		 * negative exponent is used to set the precision
1311dc6ca969Sfw 		 * for the printf.
1312dc6ca969Sfw 		 */
1313dc6ca969Sfw 		if ((int)display_val == display_val || exponent > 0)
1314dc6ca969Sfw 			exponent = 0;
1315dc6ca969Sfw 	}
1316dc6ca969Sfw 
1317a42ff480Sfw 	err = picl_get_propval_by_name(nodeh, PICL_PROP_BASE_UNITS,
1318a42ff480Sfw 	    base_units, sizeof (base_units));
1319aaba19e2Sfw 	if (err != PICL_SUCCESS)
1320aaba19e2Sfw 		base_units[0] = '\0';
13210d63ce2bSvenki 
1322a42ff480Sfw 	switch (sensor_status) {
1323a42ff480Sfw 	case SENSOR_FAILED:
13240d63ce2bSvenki 		log_printf("%-s", "failed (");
1325aaba19e2Sfw 		log_printf("%-.*f", abs(exponent), display_val);
1326aaba19e2Sfw 		log_printf("%-s %s", base_units, ")");
1327a42ff480Sfw 		break;
1328a42ff480Sfw 	case SENSOR_WARN:
13290d63ce2bSvenki 		log_printf("%-s", "warning (");
1330aaba19e2Sfw 		log_printf("%-.*f", abs(exponent), display_val);
1331aaba19e2Sfw 		log_printf("%-s %s", base_units, ")");
1332a42ff480Sfw 		break;
1333a42ff480Sfw 	case SENSOR_DISABLED:
1334a42ff480Sfw 		log_printf("%-s", "disabled");
1335a42ff480Sfw 		break;
1336a42ff480Sfw 	case SENSOR_OK:
13370d63ce2bSvenki 		log_printf("%-s", "ok");
1338a42ff480Sfw 		break;
1339a42ff480Sfw 	default:
1340a42ff480Sfw 		log_printf("%-s", "unknown");
1341a42ff480Sfw 		break;
1342a42ff480Sfw 	}
13430d63ce2bSvenki 
13440d63ce2bSvenki 	log_printf("\n");
13450d63ce2bSvenki 	return (PICL_WALK_CONTINUE);
13460d63ce2bSvenki }
13470d63ce2bSvenki 
13480d63ce2bSvenki /*ARGSUSED*/
13490d63ce2bSvenki static int
sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh,void * args)13500d63ce2bSvenki sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args)
13510d63ce2bSvenki {
1352a42ff480Sfw 	char current_val[PICL_PROPNAMELEN_MAX];
1353a42ff480Sfw 	char expected_val[PICL_PROPNAMELEN_MAX];
1354a42ff480Sfw 	char label[PICL_PROPNAMELEN_MAX];
13550d63ce2bSvenki 	picl_nodehdl_t parenth;
13560d63ce2bSvenki 	char *names[PARENT_NAMES];
13570d63ce2bSvenki 	char *loc;
13580d63ce2bSvenki 	int i = 0;
13590d63ce2bSvenki 	char *prop = (char *)args;
13600d63ce2bSvenki 	picl_errno_t err = PICL_SUCCESS;
1361a42ff480Sfw 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
1362a42ff480Sfw 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
1363a42ff480Sfw 	sensor_status_t sensor_status = SENSOR_OK;
13640d63ce2bSvenki 
13650d63ce2bSvenki 	if (class_node_found == 0) {
13660d63ce2bSvenki 		class_node_found = 1;
13670d63ce2bSvenki 		return (PICL_WALK_TERMINATE);
13680d63ce2bSvenki 	}
1369a42ff480Sfw 
1370a42ff480Sfw 	prop = (char *)args;
1371a42ff480Sfw 	if (!prop) {
1372a42ff480Sfw 		sensor_status = SENSOR_UNKNOWN;
1373a42ff480Sfw 		all_status_ok = 0;
1374a42ff480Sfw 	} else {
13750d63ce2bSvenki 		err = picl_get_propval_by_name(nodeh,
1376a42ff480Sfw 		    PICL_PROP_OPERATIONAL_STATUS, current_val,
1377a42ff480Sfw 		    sizeof (current_val));
13780d63ce2bSvenki 		if (err == PICL_SUCCESS) {
1379a42ff480Sfw 			if (strcmp(current_val, "disabled") == 0) {
1380a42ff480Sfw 				sensor_status = SENSOR_DISABLED;
1381a42ff480Sfw 			}
1382a42ff480Sfw 		}
1383a42ff480Sfw 	}
1384a42ff480Sfw 
1385a42ff480Sfw 	if (sensor_status != SENSOR_DISABLED &&
1386a42ff480Sfw 	    sensor_status != SENSOR_UNKNOWN) {
1387a42ff480Sfw 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
1388a42ff480Sfw 		    sizeof (current_val)) != PICL_SUCCESS) {
1389a42ff480Sfw 			(void) strlcpy(current_val, "unknown",
1390a42ff480Sfw 			    sizeof (current_val));
1391a42ff480Sfw 			sensor_status = SENSOR_UNKNOWN;
13920d63ce2bSvenki 		} else {
1393a42ff480Sfw 			if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPECTED,
13947ae8c7a8SMichael Bergknoff 			    &expected_val, sizeof (expected_val)) ==
1395a42ff480Sfw 			    PICL_SUCCESS) {
1396a42ff480Sfw 				if (strncmp(current_val, expected_val,
1397a42ff480Sfw 				    sizeof (current_val)) == 0) {
1398a42ff480Sfw 					sensor_status = SENSOR_OK;
1399a42ff480Sfw 				} else {
1400a42ff480Sfw 					sensor_status = SENSOR_FAILED;
1401a42ff480Sfw 				}
1402a42ff480Sfw 			}
1403a42ff480Sfw 		}
1404a42ff480Sfw 	}
1405a42ff480Sfw 
1406a42ff480Sfw 	if (syserrlog == 0) {
1407a42ff480Sfw 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
14080d63ce2bSvenki 			all_status_ok = 0;
14090d63ce2bSvenki 			return (PICL_WALK_TERMINATE);
14100d63ce2bSvenki 		}
1411a42ff480Sfw 		if (sensor_status == SENSOR_OK) {
1412a42ff480Sfw 			return (PICL_WALK_CONTINUE);
1413a42ff480Sfw 		}
14147ae8c7a8SMichael Bergknoff 	} else {
14157ae8c7a8SMichael Bergknoff 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
14167ae8c7a8SMichael Bergknoff 			all_status_ok = 0;
14177ae8c7a8SMichael Bergknoff 		}
14180d63ce2bSvenki 	}
1419a42ff480Sfw 
1420a42ff480Sfw 	/*
1421a42ff480Sfw 	 * If we're here then prtdiag was invoked with "-v" or we have
1422a42ff480Sfw 	 * a sensor that is beyond a threshold, so give them a book to
1423a42ff480Sfw 	 * read instead of the Cliff Notes.
1424a42ff480Sfw 	 */
14250d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1426a90d965dSfw 	    sizeof (parenth));
14270d63ce2bSvenki 	if (err != PICL_SUCCESS) {
14280d63ce2bSvenki 		log_printf("\n");
14290d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
14300d63ce2bSvenki 	}
1431a42ff480Sfw 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
1432a42ff480Sfw 		for (i = 0; i < PARENT_NAMES; i++) {
1433a42ff480Sfw 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
1434a42ff480Sfw 			    NULL) {
1435a42ff480Sfw 				while (--i > -1)
1436a42ff480Sfw 					free(names[i]);
1437a42ff480Sfw 				free(loc);
1438a42ff480Sfw 				loc = NULL;
1439a42ff480Sfw 			}
14400d63ce2bSvenki 		}
1441a42ff480Sfw 	}
14420d63ce2bSvenki 	i = 0;
1443a42ff480Sfw 	if (loc) {
1444a42ff480Sfw 		while (err == PICL_SUCCESS) {
1445a42ff480Sfw 			if (parenth == phyplatformh)
1446a42ff480Sfw 				break;
1447a42ff480Sfw 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1448a42ff480Sfw 			    names[i++], PICL_PROPNAMELEN_MAX);
1449a42ff480Sfw 			if (err != PICL_SUCCESS) {
1450a42ff480Sfw 				i--;
1451a42ff480Sfw 				break;
1452a42ff480Sfw 			}
1453a42ff480Sfw 			if (i == PARENT_NAMES)
1454a42ff480Sfw 				break;
1455a42ff480Sfw 			err = picl_get_propval_by_name(parenth,
1456a42ff480Sfw 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
14570d63ce2bSvenki 		}
1458a42ff480Sfw 		loc[0] = '\0';
1459a42ff480Sfw 		if (--i > -1) {
1460a42ff480Sfw 			(void) strlcat(loc, names[i],
1461a42ff480Sfw 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1462a42ff480Sfw 		}
1463a42ff480Sfw 		while (--i > -1) {
1464a42ff480Sfw 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
1465a42ff480Sfw 			    PARENT_NAMES);
1466a42ff480Sfw 			(void) strlcat(loc, names[i],
1467a42ff480Sfw 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1468a42ff480Sfw 		}
14695e3e415aSfw 		log_printf("%-35s", loc);
1470a42ff480Sfw 		for (i = 0; i < PARENT_NAMES; i++)
1471a42ff480Sfw 			free(names[i]);
1472a42ff480Sfw 		free(loc);
1473a42ff480Sfw 	} else {
14745e3e415aSfw 		log_printf("%-35s", "");
14750d63ce2bSvenki 	}
1476a42ff480Sfw 
1477a42ff480Sfw 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
1478a42ff480Sfw 	    sizeof (label));
1479a42ff480Sfw 	if (err != PICL_SUCCESS)
1480a42ff480Sfw 		(void) strlcpy(label, "", sizeof (label));
1481bbda49b5SSree Vemuri 	log_printf("%-19s", label);
1482a42ff480Sfw 
1483a42ff480Sfw 	log_printf("%-8s", current_val);
1484a42ff480Sfw 
14850d63ce2bSvenki 	log_printf("\n");
14860d63ce2bSvenki 	return (PICL_WALK_CONTINUE);
14870d63ce2bSvenki }
14880d63ce2bSvenki 
14890d63ce2bSvenki static void
sun4v_env_print_fan_sensors()14900d63ce2bSvenki sun4v_env_print_fan_sensors()
14910d63ce2bSvenki {
1492bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-10s\n";
14930d63ce2bSvenki 	/*
14940d63ce2bSvenki 	 * If there isn't any fan sensor node, return now.
14950d63ce2bSvenki 	 */
14960d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1497a42ff480Sfw 	    PICL_CLASS_RPM_SENSOR, (void *)PICL_PROP_SPEED,
1498a90d965dSfw 	    sun4v_env_print_sensor_callback);
14990d63ce2bSvenki 	if (!class_node_found)
15000d63ce2bSvenki 		return;
15010d63ce2bSvenki 	log_printf("Fan sensors:\n");
15020d63ce2bSvenki 	if (syserrlog == 0) {
15030d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1504a90d965dSfw 		    PICL_CLASS_RPM_SENSOR,
1505a42ff480Sfw 		    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
15060d63ce2bSvenki 		if (all_status_ok) {
15070d63ce2bSvenki 			log_printf("All fan sensors are OK.\n");
15080d63ce2bSvenki 			return;
15090d63ce2bSvenki 		}
15100d63ce2bSvenki 	}
15115e3e415aSfw 	log_printf("-------------------------------------------------"
1512bbda49b5SSree Vemuri 	    "---------------\n");
15130d63ce2bSvenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
15145e3e415aSfw 	log_printf("-------------------------------------------------"
1515bbda49b5SSree Vemuri 	    "---------------\n");
15160d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR,
1517a90d965dSfw 	    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
15180d63ce2bSvenki }
15190d63ce2bSvenki 
15200d63ce2bSvenki static void
sun4v_env_print_fan_indicators()15210d63ce2bSvenki sun4v_env_print_fan_indicators()
15220d63ce2bSvenki {
1523bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-10s\n";
15240d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1525a42ff480Sfw 	    PICL_CLASS_RPM_INDICATOR, (void *)PICL_PROP_CONDITION,
1526a90d965dSfw 	    sun4v_env_print_indicator_callback);
15270d63ce2bSvenki 	if (!class_node_found)
15280d63ce2bSvenki 		return;
15290d63ce2bSvenki 	log_printf("\nFan indicators:\n");
15300d63ce2bSvenki 	if (syserrlog == 0) {
15310d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1532a90d965dSfw 		    PICL_CLASS_RPM_INDICATOR,
1533a42ff480Sfw 		    (void *)PICL_PROP_CONDITION,
1534a42ff480Sfw 		    sun4v_env_print_indicator_callback);
15350d63ce2bSvenki 		if (all_status_ok) {
15360d63ce2bSvenki 			log_printf("All fan indicators are OK.\n");
15370d63ce2bSvenki 			return;
15380d63ce2bSvenki 		}
15390d63ce2bSvenki 	}
15405e3e415aSfw 	log_printf("-------------------------------------------------"
1541bbda49b5SSree Vemuri 	    "---------------\n");
15420d63ce2bSvenki 	log_printf(fmt, "Location", "Sensor", "Condition", 0);
15435e3e415aSfw 	log_printf("-------------------------------------------------"
1544bbda49b5SSree Vemuri 	    "---------------\n");
15450d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR,
1546aaba19e2Sfw 	    (void *)PICL_PROP_CONDITION, sun4v_env_print_indicator_callback);
15470d63ce2bSvenki }
15480d63ce2bSvenki 
15490d63ce2bSvenki static void
sun4v_env_print_temp_sensors()15500d63ce2bSvenki sun4v_env_print_temp_sensors()
15510d63ce2bSvenki {
1552bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-10s\n";
15530d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1554a90d965dSfw 	    PICL_CLASS_TEMPERATURE_SENSOR,
1555a90d965dSfw 	    (void *)PICL_PROP_TEMPERATURE,
1556a90d965dSfw 	    sun4v_env_print_sensor_callback);
15570d63ce2bSvenki 	if (!class_node_found)
15580d63ce2bSvenki 		return;
15590d63ce2bSvenki 
15600d63ce2bSvenki 	log_printf("\nTemperature sensors:\n");
15610d63ce2bSvenki 	if (syserrlog == 0) {
15620d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1563a90d965dSfw 		    PICL_CLASS_TEMPERATURE_SENSOR,
1564a42ff480Sfw 		    PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
15650d63ce2bSvenki 		if (all_status_ok) {
15660d63ce2bSvenki 			log_printf("All temperature sensors are OK.\n");
15670d63ce2bSvenki 			return;
15680d63ce2bSvenki 		}
15690d63ce2bSvenki 	}
15705e3e415aSfw 	log_printf("-------------------------------------------------"
1571bbda49b5SSree Vemuri 	    "---------------\n");
15720d63ce2bSvenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
15735e3e415aSfw 	log_printf("-------------------------------------------------"
1574bbda49b5SSree Vemuri 	    "---------------\n");
15750d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1576a90d965dSfw 	    PICL_CLASS_TEMPERATURE_SENSOR,
1577a90d965dSfw 	    (void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
15780d63ce2bSvenki }
15790d63ce2bSvenki 
15800d63ce2bSvenki static void
sun4v_env_print_temp_indicators()15810d63ce2bSvenki sun4v_env_print_temp_indicators()
15820d63ce2bSvenki {
1583bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-8s\n";
15840d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1585a90d965dSfw 	    PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION,
1586a90d965dSfw 	    sun4v_env_print_indicator_callback);
15870d63ce2bSvenki 	if (!class_node_found)
15880d63ce2bSvenki 		return;
15890d63ce2bSvenki 	log_printf("\nTemperature indicators:\n");
15900d63ce2bSvenki 	if (syserrlog == 0) {
15910d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1592a42ff480Sfw 		    PICL_CLASS_TEMPERATURE_INDICATOR,
1593a42ff480Sfw 		    (void *)PICL_PROP_CONDITION,
1594a90d965dSfw 		    sun4v_env_print_indicator_callback);
15950d63ce2bSvenki 		if (all_status_ok) {
15960d63ce2bSvenki 			log_printf("All temperature indicators are OK.\n");
15970d63ce2bSvenki 			return;
15980d63ce2bSvenki 		}
15990d63ce2bSvenki 	}
16005e3e415aSfw 	log_printf("-------------------------------------------------"
1601bbda49b5SSree Vemuri 	    "---------------\n");
16020d63ce2bSvenki 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
16035e3e415aSfw 	log_printf("-------------------------------------------------"
1604bbda49b5SSree Vemuri 	    "---------------\n");
16050d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1606a90d965dSfw 	    PICL_CLASS_TEMPERATURE_INDICATOR,
1607a90d965dSfw 	    (void *)PICL_PROP_CONDITION,
1608a90d965dSfw 	    sun4v_env_print_indicator_callback);
16090d63ce2bSvenki }
16100d63ce2bSvenki 
16110d63ce2bSvenki static void
sun4v_env_print_current_sensors()16120d63ce2bSvenki sun4v_env_print_current_sensors()
16130d63ce2bSvenki {
1614bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-10s\n";
16150d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR,
1616a90d965dSfw 	    (void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
16170d63ce2bSvenki 	if (!class_node_found)
16180d63ce2bSvenki 		return;
16190d63ce2bSvenki 	log_printf("\nCurrent sensors:\n");
16200d63ce2bSvenki 	if (syserrlog == 0) {
16210d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1622a90d965dSfw 		    PICL_CLASS_CURRENT_SENSOR,
1623a42ff480Sfw 		    PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
16240d63ce2bSvenki 		if (all_status_ok) {
16250d63ce2bSvenki 			log_printf("All current sensors are OK.\n");
16260d63ce2bSvenki 			return;
16270d63ce2bSvenki 		}
16280d63ce2bSvenki 	}
16295e3e415aSfw 	log_printf("-------------------------------------------------"
1630bbda49b5SSree Vemuri 	    "---------------\n");
16310d63ce2bSvenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
16325e3e415aSfw 	log_printf("-------------------------------------------------"
1633bbda49b5SSree Vemuri 	    "---------------\n");
16340d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1635a90d965dSfw 	    PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT,
1636a90d965dSfw 	    sun4v_env_print_sensor_callback);
16370d63ce2bSvenki }
16380d63ce2bSvenki 
16390d63ce2bSvenki static void
sun4v_env_print_current_indicators()16400d63ce2bSvenki sun4v_env_print_current_indicators()
16410d63ce2bSvenki {
1642bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-8s\n";
16430d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1644a90d965dSfw 	    PICL_CLASS_CURRENT_INDICATOR,
1645a90d965dSfw 	    (void *)PICL_PROP_CONDITION,
1646a90d965dSfw 	    sun4v_env_print_indicator_callback);
16470d63ce2bSvenki 	if (!class_node_found)
16480d63ce2bSvenki 		return;
16490d63ce2bSvenki 	log_printf("\nCurrent indicators:\n");
16500d63ce2bSvenki 	if (syserrlog == 0) {
16510d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1652a42ff480Sfw 		    PICL_CLASS_CURRENT_INDICATOR, (void *)PICL_PROP_CONDITION,
1653a90d965dSfw 		    sun4v_env_print_indicator_callback);
16540d63ce2bSvenki 		if (all_status_ok) {
16550d63ce2bSvenki 			log_printf("All current indicators are OK.\n");
16560d63ce2bSvenki 			return;
16570d63ce2bSvenki 		}
16580d63ce2bSvenki 	}
16595e3e415aSfw 	log_printf("-------------------------------------------------"
1660bbda49b5SSree Vemuri 	    "---------------\n");
16610d63ce2bSvenki 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
16625e3e415aSfw 	log_printf("-------------------------------------------------"
1663bbda49b5SSree Vemuri 	    "---------------\n");
16640d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1665a90d965dSfw 	    PICL_CLASS_CURRENT_INDICATOR,
1666a90d965dSfw 	    (void *)PICL_PROP_CONDITION,
1667a90d965dSfw 	    sun4v_env_print_indicator_callback);
16680d63ce2bSvenki }
16690d63ce2bSvenki 
16700d63ce2bSvenki static void
sun4v_env_print_voltage_sensors()16710d63ce2bSvenki sun4v_env_print_voltage_sensors()
16720d63ce2bSvenki {
1673bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-10s\n";
16740d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1675a90d965dSfw 	    PICL_CLASS_VOLTAGE_SENSOR,
1676a90d965dSfw 	    PICL_PROP_VOLTAGE,
1677a90d965dSfw 	    sun4v_env_print_sensor_callback);
16780d63ce2bSvenki 	if (!class_node_found)
16790d63ce2bSvenki 		return;
16800d63ce2bSvenki 	log_printf("\nVoltage sensors:\n");
16810d63ce2bSvenki 	if (syserrlog == 0) {
16820d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1683a90d965dSfw 		    PICL_CLASS_VOLTAGE_SENSOR,
1684a42ff480Sfw 		    PICL_PROP_VOLTAGE, sun4v_env_print_sensor_callback);
16850d63ce2bSvenki 		if (all_status_ok) {
16860d63ce2bSvenki 			log_printf("All voltage sensors are OK.\n");
16870d63ce2bSvenki 			return;
16880d63ce2bSvenki 		}
16890d63ce2bSvenki 	}
16905e3e415aSfw 	log_printf("-------------------------------------------------"
1691bbda49b5SSree Vemuri 	    "---------------\n");
16920d63ce2bSvenki 	log_printf(fmt, "Location", "Sensor", "Status", 0);
16935e3e415aSfw 	log_printf("-------------------------------------------------"
1694bbda49b5SSree Vemuri 	    "---------------\n");
16950d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1696a90d965dSfw 	    PICL_CLASS_VOLTAGE_SENSOR,
1697a90d965dSfw 	    (void *)PICL_PROP_VOLTAGE,
1698a90d965dSfw 	    sun4v_env_print_sensor_callback);
16990d63ce2bSvenki }
17000d63ce2bSvenki 
17010d63ce2bSvenki static void
sun4v_env_print_voltage_indicators()17020d63ce2bSvenki sun4v_env_print_voltage_indicators()
17030d63ce2bSvenki {
1704bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-8s\n";
17050d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1706a90d965dSfw 	    PICL_CLASS_VOLTAGE_INDICATOR,
1707a90d965dSfw 	    (void *)PICL_PROP_CONDITION,
1708a90d965dSfw 	    sun4v_env_print_indicator_callback);
17090d63ce2bSvenki 	if (!class_node_found)
17100d63ce2bSvenki 		return;
17110d63ce2bSvenki 	log_printf("\nVoltage indicators:\n");
17120d63ce2bSvenki 	if (syserrlog == 0) {
17130d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1714a42ff480Sfw 		    PICL_CLASS_VOLTAGE_INDICATOR, (void *)PICL_PROP_CONDITION,
1715a90d965dSfw 		    sun4v_env_print_indicator_callback);
17160d63ce2bSvenki 		if (all_status_ok) {
17170d63ce2bSvenki 			log_printf("All voltage indicators are OK.\n");
17180d63ce2bSvenki 			return;
17190d63ce2bSvenki 		}
17200d63ce2bSvenki 	}
17215e3e415aSfw 	log_printf("-------------------------------------------------"
1722bbda49b5SSree Vemuri 	    "---------------\n");
17230d63ce2bSvenki 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
17245e3e415aSfw 	log_printf("-------------------------------------------------"
1725bbda49b5SSree Vemuri 	    "---------------\n");
17260d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh,
1727a90d965dSfw 	    PICL_CLASS_VOLTAGE_INDICATOR,
1728a90d965dSfw 	    (void *)PICL_PROP_CONDITION,
1729a90d965dSfw 	    sun4v_env_print_indicator_callback);
17300d63ce2bSvenki }
17310d63ce2bSvenki 
17320d63ce2bSvenki static void
sun4v_env_print_LEDs()17330d63ce2bSvenki sun4v_env_print_LEDs()
17340d63ce2bSvenki {
1735bbda49b5SSree Vemuri 	char *fmt = "%-34s %-18s %-8s\n";
17360d63ce2bSvenki 	if (syserrlog == 0)
17370d63ce2bSvenki 		return;
17380d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
1739a90d965dSfw 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
17400d63ce2bSvenki 	if (!class_node_found)
17410d63ce2bSvenki 		return;
17420d63ce2bSvenki 	log_printf("\nLEDs:\n");
17435e3e415aSfw 	log_printf("-------------------------------------------------"
1744bbda49b5SSree Vemuri 	    "---------------\n");
17450d63ce2bSvenki 	log_printf(fmt, "Location", "LED", "State", 0);
17465e3e415aSfw 	log_printf("-------------------------------------------------"
1747bbda49b5SSree Vemuri 	    "---------------\n");
17480d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
1749a90d965dSfw 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
17500d63ce2bSvenki }
17510d63ce2bSvenki 
17520d63ce2bSvenki /*ARGSUSED*/
17530d63ce2bSvenki static int
sun4v_print_fru_status_callback(picl_nodehdl_t nodeh,void * args)17540d63ce2bSvenki sun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args)
17550d63ce2bSvenki {
17560d63ce2bSvenki 	char label[PICL_PROPNAMELEN_MAX];
17570d63ce2bSvenki 	char status[PICL_PROPNAMELEN_MAX];
17580d63ce2bSvenki 	picl_errno_t err;
17590d63ce2bSvenki 	picl_prophdl_t proph;
17600d63ce2bSvenki 	picl_nodehdl_t parenth;
17610d63ce2bSvenki 	char *names[PARENT_NAMES];
17620d63ce2bSvenki 	char *loc;
17630d63ce2bSvenki 	int i;
17640d63ce2bSvenki 
17650d63ce2bSvenki 	if (!class_node_found) {
17660d63ce2bSvenki 		class_node_found = 1;
17670d63ce2bSvenki 		return (PICL_WALK_TERMINATE);
17680d63ce2bSvenki 	}
17690d63ce2bSvenki 	err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph);
17700d63ce2bSvenki 	if (err != PICL_SUCCESS)
17710d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
17720d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
1773a90d965dSfw 	    sizeof (label));
17740d63ce2bSvenki 	if (err != PICL_SUCCESS)
17750d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
17760d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
1777a90d965dSfw 	    status, sizeof (status));
17780d63ce2bSvenki 	if (err != PICL_SUCCESS)
17790d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
17800d63ce2bSvenki 	if (syserrlog == 0) {
17810d63ce2bSvenki 		if (strcmp(status, "disabled") == 0) {
17820d63ce2bSvenki 			if (all_status_ok) {
17830d63ce2bSvenki 				all_status_ok = 0;
17840d63ce2bSvenki 				return (PICL_WALK_TERMINATE);
17850d63ce2bSvenki 			}
17860d63ce2bSvenki 		} else
17870d63ce2bSvenki 			return (PICL_WALK_CONTINUE);
17887ae8c7a8SMichael Bergknoff 	} else {
17897ae8c7a8SMichael Bergknoff 		if (all_status_ok && (strcmp(status, "disabled") == 0)) {
17907ae8c7a8SMichael Bergknoff 			all_status_ok = 0;
17917ae8c7a8SMichael Bergknoff 		}
17920d63ce2bSvenki 	}
17938a31bd2bSBirva Shah 
17948a31bd2bSBirva Shah 	if (is_fru_absent(nodeh))
1795*6fb59094SToomas Soome 		(void) strcpy(status, "Not present");
17968a31bd2bSBirva Shah 
17970d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1798a90d965dSfw 	    sizeof (parenth));
17990d63ce2bSvenki 	if (err != PICL_SUCCESS) {
18000d63ce2bSvenki 		log_printf("\n");
18010d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
18020d63ce2bSvenki 	}
18030d63ce2bSvenki 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
18040d63ce2bSvenki 		return (PICL_WALK_TERMINATE);
18050d63ce2bSvenki 	for (i = 0; i < PARENT_NAMES; i++)
18060d63ce2bSvenki 		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
18070d63ce2bSvenki 			while (--i > -1)
18080d63ce2bSvenki 				free(names[i]);
18090d63ce2bSvenki 			free(loc);
18100d63ce2bSvenki 			return (PICL_WALK_TERMINATE);
18110d63ce2bSvenki 		}
18120d63ce2bSvenki 	i = 0;
18130d63ce2bSvenki 	while (err == PICL_SUCCESS) {
1814aaba19e2Sfw 		if (parenth == phyplatformh)
18150d63ce2bSvenki 			break;
18160d63ce2bSvenki 		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1817a90d965dSfw 		    names[i++], PICL_PROPNAMELEN_MAX);
18180d63ce2bSvenki 		if (err != PICL_SUCCESS) {
18190d63ce2bSvenki 			i--;
18200d63ce2bSvenki 			break;
18210d63ce2bSvenki 		}
18220d63ce2bSvenki 		if (i == PARENT_NAMES)
18230d63ce2bSvenki 			break;
18240d63ce2bSvenki 		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
1825a90d965dSfw 		    &parenth, sizeof (parenth));
18260d63ce2bSvenki 	}
18270d63ce2bSvenki 	loc[0] = '\0';
18284c5e0fdeSvivek 	if (--i > -1) {
18294c5e0fdeSvivek 		(void) strlcat(loc, names[i],
1830a90d965dSfw 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
18314c5e0fdeSvivek 	}
18320d63ce2bSvenki 	while (--i > -1) {
18334c5e0fdeSvivek 		(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * PARENT_NAMES);
18344c5e0fdeSvivek 		(void) strlcat(loc, names[i],
1835a90d965dSfw 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
18360d63ce2bSvenki 	}
18375e3e415aSfw 	log_printf("%-35s", loc);
18380d63ce2bSvenki 	for (i = 0; i < PARENT_NAMES; i++)
18390d63ce2bSvenki 		free(names[i]);
18400d63ce2bSvenki 	free(loc);
18410d63ce2bSvenki 	log_printf("%-10s", label);
18420d63ce2bSvenki 	log_printf("%-9s", status);
18430d63ce2bSvenki 	log_printf("\n");
18440d63ce2bSvenki 	return (PICL_WALK_CONTINUE);
18450d63ce2bSvenki }
18460d63ce2bSvenki 
18470d63ce2bSvenki static void
sun4v_print_fru_status()18480d63ce2bSvenki sun4v_print_fru_status()
18490d63ce2bSvenki {
18505e3e415aSfw 	char *fmt = "%-34s %-9s %-8s\n";
1851dc6ca969Sfw 
18520d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1853a90d965dSfw 	    sun4v_print_fru_status_callback);
18540d63ce2bSvenki 	if (!class_node_found)
18550d63ce2bSvenki 		return;
1856dc6ca969Sfw 
18570d63ce2bSvenki 	log_printf("\n");
18580d63ce2bSvenki 	log_printf("============================");
18590d63ce2bSvenki 	log_printf(" FRU Status ");
18600d63ce2bSvenki 	log_printf("============================");
18610d63ce2bSvenki 	log_printf("\n");
18620d63ce2bSvenki 
18630d63ce2bSvenki 	if (syserrlog == 0) {
18640d63ce2bSvenki 		(void) picl_walk_tree_by_class(phyplatformh,
1865aaba19e2Sfw 		    NULL, NULL,
1866a90d965dSfw 		    sun4v_print_fru_status_callback);
18670d63ce2bSvenki 		if (all_status_ok) {
18680d63ce2bSvenki 			log_printf("All FRUs are enabled.\n");
18690d63ce2bSvenki 			return;
18700d63ce2bSvenki 		}
18710d63ce2bSvenki 	}
18720d63ce2bSvenki 	log_printf(fmt, "Location", "Name", "Status", 0);
18735e3e415aSfw 	log_printf("------------------------------------------------------\n");
1874aaba19e2Sfw 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1875a90d965dSfw 	    sun4v_print_fru_status_callback);
18760d63ce2bSvenki }
18770d63ce2bSvenki 
18788a31bd2bSBirva Shah /*  Check the children of the FRU node for a presence indicator */
18798a31bd2bSBirva Shah static int
is_fru_absent(picl_nodehdl_t fruh)18808a31bd2bSBirva Shah is_fru_absent(picl_nodehdl_t fruh)
18818a31bd2bSBirva Shah {
18828a31bd2bSBirva Shah 	char class [PICL_CLASSNAMELEN_MAX];
18838a31bd2bSBirva Shah 	char condition [PICL_PROPNAMELEN_MAX];
18848a31bd2bSBirva Shah 	picl_errno_t err;
18858a31bd2bSBirva Shah 	picl_nodehdl_t nodeh;
18868a31bd2bSBirva Shah 
18878a31bd2bSBirva Shah 	err = picl_get_propval_by_name(fruh, PICL_PROP_CHILD, &nodeh,
18888a31bd2bSBirva Shah 	    sizeof (picl_nodehdl_t));
18898a31bd2bSBirva Shah 	while (err == PICL_SUCCESS) {
18908a31bd2bSBirva Shah 		err = picl_get_propval_by_name(nodeh,
18918a31bd2bSBirva Shah 		    PICL_PROP_CLASSNAME, class, sizeof (class));
18928a31bd2bSBirva Shah 		if (err == PICL_SUCCESS &&
18938a31bd2bSBirva Shah 		    strcmp(class, "presence-indicator") == 0) {
18948a31bd2bSBirva Shah 			err = picl_get_propval_by_name(nodeh,
18958a31bd2bSBirva Shah 			    PICL_PROP_CONDITION, condition,
18968a31bd2bSBirva Shah 			    sizeof (condition));
18978a31bd2bSBirva Shah 			if (err == PICL_SUCCESS) {
18988a31bd2bSBirva Shah 				if (strcmp(condition, "Absent") == 0) {
18998a31bd2bSBirva Shah 					return (1);
19008a31bd2bSBirva Shah 				} else	{
19018a31bd2bSBirva Shah 					return (0);
19028a31bd2bSBirva Shah 				}
19038a31bd2bSBirva Shah 			}
19048a31bd2bSBirva Shah 		}
19058a31bd2bSBirva Shah 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
19068a31bd2bSBirva Shah 		    &nodeh, sizeof (picl_nodehdl_t));
19078a31bd2bSBirva Shah 	}
19088a31bd2bSBirva Shah 	return (0);
19098a31bd2bSBirva Shah }
19108a31bd2bSBirva Shah 
19110d63ce2bSvenki /*ARGSUSED*/
19120d63ce2bSvenki static int
sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh,void * args)19130d63ce2bSvenki sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args)
19140d63ce2bSvenki {
19150d63ce2bSvenki 	char rev[PICL_PROPNAMELEN_MAX];
19160d63ce2bSvenki 	picl_errno_t err;
19170d63ce2bSvenki 
19180d63ce2bSvenki 	if (!class_node_found) {
19190d63ce2bSvenki 		class_node_found = 1;
19200d63ce2bSvenki 		return (PICL_WALK_TERMINATE);
19210d63ce2bSvenki 	}
1922dc6ca969Sfw 
19230d63ce2bSvenki 	err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev,
1924a90d965dSfw 	    sizeof (rev));
19250d63ce2bSvenki 	if (err != PICL_SUCCESS)
19260d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
19270d63ce2bSvenki 	if (strlen(rev) == 0)
19280d63ce2bSvenki 		return (PICL_WALK_CONTINUE);
1929dc6ca969Sfw 	log_printf("%s", rev);
19300d63ce2bSvenki 	log_printf("\n");
19310d63ce2bSvenki 	return (PICL_WALK_CONTINUE);
19320d63ce2bSvenki }
19330d63ce2bSvenki 
19340d63ce2bSvenki static void
sun4v_print_fw_rev()19350d63ce2bSvenki sun4v_print_fw_rev()
19360d63ce2bSvenki {
19370d63ce2bSvenki 	if (syserrlog == 0)
19380d63ce2bSvenki 		return;
1939dc6ca969Sfw 
19400d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1941a90d965dSfw 	    sun4v_print_fw_rev_callback);
19420d63ce2bSvenki 	if (!class_node_found)
19430d63ce2bSvenki 		return;
1944dc6ca969Sfw 
19450d63ce2bSvenki 	log_printf("\n");
19460d63ce2bSvenki 	log_printf("============================");
19470d63ce2bSvenki 	log_printf(" FW Version ");
19480d63ce2bSvenki 	log_printf("============================");
19490d63ce2bSvenki 	log_printf("\n");
1950dc6ca969Sfw 	log_printf("Version\n");
19515e3e415aSfw 	log_printf("-------------------------------------------------"
19525e3e415aSfw 	    "-----------\n");
19530d63ce2bSvenki 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1954a90d965dSfw 	    sun4v_print_fw_rev_callback);
19550d63ce2bSvenki }
19560d63ce2bSvenki 
1957dc6ca969Sfw static void
sun4v_print_openprom_rev()1958dc6ca969Sfw sun4v_print_openprom_rev()
1959dc6ca969Sfw {
1960dc6ca969Sfw 	if (syserrlog == 0)
1961dc6ca969Sfw 		return;
1962dc6ca969Sfw 
1963dc6ca969Sfw 	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
1964dc6ca969Sfw 	    openprom_callback);
1965dc6ca969Sfw 	if (!class_node_found)
1966dc6ca969Sfw 		return;
1967dc6ca969Sfw 
1968dc6ca969Sfw 	log_printf("\n");
1969dc6ca969Sfw 	log_printf("======================");
1970dc6ca969Sfw 	log_printf(" System PROM revisions ");
1971dc6ca969Sfw 	log_printf("=======================");
1972dc6ca969Sfw 	log_printf("\n");
1973dc6ca969Sfw 	log_printf("Version\n");
1974dc6ca969Sfw 	log_printf("-------------------------------------------------"
1975dc6ca969Sfw 	    "-----------\n");
1976dc6ca969Sfw 	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
1977dc6ca969Sfw 	    openprom_callback);
1978dc6ca969Sfw }
1979dc6ca969Sfw 
1980dc6ca969Sfw /*
1981dc6ca969Sfw  * display the OBP and POST prom revisions (if present)
1982dc6ca969Sfw  */
1983dc6ca969Sfw /* ARGSUSED */
1984dc6ca969Sfw static int
openprom_callback(picl_nodehdl_t openpromh,void * arg)1985dc6ca969Sfw openprom_callback(picl_nodehdl_t openpromh, void *arg)
1986dc6ca969Sfw {
1987dc6ca969Sfw 	picl_prophdl_t	proph;
1988dc6ca969Sfw 	picl_prophdl_t	tblh;
1989dc6ca969Sfw 	picl_prophdl_t	rowproph;
1990dc6ca969Sfw 	picl_propinfo_t	pinfo;
1991dc6ca969Sfw 	char		*prom_version = NULL;
1992dc6ca969Sfw 	char		*obp_version = NULL;
1993dc6ca969Sfw 	int		err;
1994dc6ca969Sfw 
1995dc6ca969Sfw 	if (!class_node_found) {
1996dc6ca969Sfw 		class_node_found = 1;
1997dc6ca969Sfw 		return (PICL_WALK_TERMINATE);
1998dc6ca969Sfw 	}
1999dc6ca969Sfw 
2000dc6ca969Sfw 	err = picl_get_propinfo_by_name(openpromh, OBP_PROP_VERSION,
2001dc6ca969Sfw 	    &pinfo, &proph);
2002dc6ca969Sfw 	if (err == PICL_PROPNOTFOUND)
2003dc6ca969Sfw 		return (PICL_WALK_TERMINATE);
2004dc6ca969Sfw 	else if (err != PICL_SUCCESS)
2005dc6ca969Sfw 		return (err);
2006dc6ca969Sfw 
2007dc6ca969Sfw 	/*
2008dc6ca969Sfw 	 * If it's a table prop, the first element is OBP revision
2009dc6ca969Sfw 	 * The second one is POST revision.
2010dc6ca969Sfw 	 * If it's a charstring prop, the value will be only OBP revision
2011dc6ca969Sfw 	 */
2012dc6ca969Sfw 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
2013dc6ca969Sfw 		prom_version = (char *)alloca(pinfo.size);
2014dc6ca969Sfw 		if (prom_version == NULL)
2015dc6ca969Sfw 			return (PICL_FAILURE);
2016dc6ca969Sfw 		err = picl_get_propval(proph, prom_version, pinfo.size);
2017dc6ca969Sfw 		if (err != PICL_SUCCESS)
2018dc6ca969Sfw 			return (err);
2019dc6ca969Sfw 		log_printf("%s\n", prom_version);
2020dc6ca969Sfw 	}
2021dc6ca969Sfw 
2022dc6ca969Sfw 	if (pinfo.type != PICL_PTYPE_TABLE)	/* not supported type */
2023dc6ca969Sfw 		return (PICL_WALK_TERMINATE);
2024dc6ca969Sfw 
2025dc6ca969Sfw 	err = picl_get_propval(proph, &tblh, pinfo.size);
2026dc6ca969Sfw 	if (err != PICL_SUCCESS)
2027dc6ca969Sfw 		return (err);
2028dc6ca969Sfw 
2029dc6ca969Sfw 	err = picl_get_next_by_row(tblh, &rowproph);
2030dc6ca969Sfw 	if (err == PICL_SUCCESS) {
2031dc6ca969Sfw 		/* get first row */
2032dc6ca969Sfw 		err = picl_get_propinfo(rowproph, &pinfo);
2033dc6ca969Sfw 		if (err != PICL_SUCCESS)
2034dc6ca969Sfw 			return (err);
2035dc6ca969Sfw 
2036dc6ca969Sfw 		prom_version = (char *)alloca(pinfo.size);
2037dc6ca969Sfw 		if (prom_version == NULL)
2038dc6ca969Sfw 			return (PICL_FAILURE);
2039dc6ca969Sfw 
2040dc6ca969Sfw 		err = picl_get_propval(rowproph, prom_version, pinfo.size);
2041dc6ca969Sfw 		if (err != PICL_SUCCESS)
2042dc6ca969Sfw 			return (err);
2043dc6ca969Sfw 		log_printf("%s\n", prom_version);
2044dc6ca969Sfw 
2045dc6ca969Sfw 		/* get second row */
2046dc6ca969Sfw 		err = picl_get_next_by_col(rowproph, &rowproph);
2047dc6ca969Sfw 		if (err == PICL_SUCCESS) {
2048dc6ca969Sfw 			err = picl_get_propinfo(rowproph, &pinfo);
2049dc6ca969Sfw 			if (err != PICL_SUCCESS)
2050dc6ca969Sfw 				return (err);
2051dc6ca969Sfw 
2052dc6ca969Sfw 			obp_version = (char *)alloca(pinfo.size);
2053dc6ca969Sfw 			if (obp_version == NULL)
2054dc6ca969Sfw 				return (PICL_FAILURE);
2055dc6ca969Sfw 			err = picl_get_propval(rowproph, obp_version,
2056dc6ca969Sfw 			    pinfo.size);
2057dc6ca969Sfw 			if (err != PICL_SUCCESS)
2058dc6ca969Sfw 				return (err);
2059dc6ca969Sfw 			log_printf("%s\n", obp_version);
2060dc6ca969Sfw 		}
2061dc6ca969Sfw 	}
2062dc6ca969Sfw 
2063dc6ca969Sfw 	return (PICL_WALK_TERMINATE);
2064dc6ca969Sfw }
2065dc6ca969Sfw 
20660d63ce2bSvenki static void
sun4v_print_chassis_serial_no()20670d63ce2bSvenki sun4v_print_chassis_serial_no()
20680d63ce2bSvenki {
20690d63ce2bSvenki 	char val[PICL_PROPNAMELEN_MAX];
20700d63ce2bSvenki 	picl_errno_t err;
20710d63ce2bSvenki 	if (syserrlog == 0 || chassish == 0)
20720d63ce2bSvenki 		return;
20730d63ce2bSvenki 
20740d63ce2bSvenki 	log_printf("\n");
20751cf6ec7eSsuha 	log_printf("Chassis Serial Number");
20760d63ce2bSvenki 	log_printf("\n");
20770d63ce2bSvenki 	log_printf("---------------------\n");
20780d63ce2bSvenki 	err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER,
2079a90d965dSfw 	    val, sizeof (val));
20800d63ce2bSvenki 	if (err == PICL_SUCCESS)
20810d63ce2bSvenki 		log_printf("%s", val);
20820d63ce2bSvenki 	log_printf("\n");
20830d63ce2bSvenki }
2084