Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <alloca.h>
     29 #include <unistd.h>
     30 #include <ctype.h>
     31 #include <string.h>
     32 #include <kvm.h>
     33 #include <varargs.h>
     34 #include <time.h>
     35 #include <dirent.h>
     36 #include <fcntl.h>
     37 #include <sys/param.h>
     38 #include <sys/stat.h>
     39 #include <sys/types.h>
     40 #include <sys/utsname.h>
     41 #include <sys/openpromio.h>
     42 #include <libintl.h>
     43 #include <syslog.h>
     44 #include <sys/dkio.h>
     45 #include <sys/systeminfo.h>
     46 #include <picldefs.h>
     47 #include <math.h>
     48 #include <errno.h>
     49 #include "pdevinfo.h"
     50 #include "display.h"
     51 #include "display_sun4v.h"
     52 #include "libprtdiag.h"
     53 
     54 #if !defined(TEXT_DOMAIN)
     55 #define	TEXT_DOMAIN	"SYS_TEST"
     56 #endif
     57 
     58 #define	MOTHERBOARD			"MB"
     59 #define	NETWORK				"network"
     60 #define	SUN4V_MACHINE			"sun4v"
     61 #define	PARENT_NAMES			10
     62 
     63 /*
     64  * Additional OBP properties
     65  */
     66 #define	OBP_PROP_COMPATIBLE		"compatible"
     67 #define	OBP_PROP_MODEL			"model"
     68 #define	OBP_PROP_SLOT_NAMES		"slot-names"
     69 #define	OBP_PROP_VERSION		"version"
     70 
     71 #define	PICL_NODE_PHYSICAL_PLATFORM	"physical-platform"
     72 #define	PICL_NODE_CHASSIS		"chassis"
     73 #define	MEMORY_SIZE_FIELD		11
     74 #define	INVALID_THRESHOLD		1000000
     75 
     76 /*
     77  * Additional picl classes
     78  */
     79 #ifndef	PICL_CLASS_SUN4V
     80 #define	PICL_CLASS_SUN4V		"sun4v"
     81 #endif
     82 
     83 #ifndef	PICL_PROP_NAC
     84 #define	PICL_PROP_NAC			"nac"
     85 #endif
     86 
     87 extern int sys_clk;
     88 extern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *,
     89 	picl_nodehdl_t *);
     90 
     91 static picl_nodehdl_t rooth = 0, phyplatformh = 0;
     92 static picl_nodehdl_t chassish = 0;
     93 static int class_node_found;
     94 static int syserrlog;
     95 static int all_status_ok;
     96 
     97 /* local functions */
     98 static int sun4v_get_first_compatible_value(picl_nodehdl_t, char **);
     99 static void sun4v_display_memory_conf(picl_nodehdl_t);
    100 static int sun4v_disp_env_status();
    101 static void sun4v_env_print_fan_sensors();
    102 static void sun4v_env_print_fan_indicators();
    103 static void sun4v_env_print_temp_sensors();
    104 static void sun4v_env_print_temp_indicators();
    105 static void sun4v_env_print_current_sensors();
    106 static void sun4v_env_print_current_indicators();
    107 static void sun4v_env_print_voltage_sensors();
    108 static void sun4v_env_print_voltage_indicators();
    109 static void sun4v_env_print_LEDs();
    110 static void sun4v_print_fru_status();
    111 static int is_fru_absent(picl_nodehdl_t);
    112 static void sun4v_print_fw_rev();
    113 static void sun4v_print_chassis_serial_no();
    114 static int openprom_callback(picl_nodehdl_t openpromh, void *arg);
    115 static void sun4v_print_openprom_rev();
    116 
    117 int
    118 sun4v_display(Sys_tree *tree, Prom_node *root, int log,
    119 	picl_nodehdl_t plafh)
    120 {
    121 	void *value;		/* used for opaque PROM data */
    122 	struct mem_total memory_total;	/* Total memory in system */
    123 	struct grp_info grps;	/* Info on all groups in system */
    124 	char machine[MAXSTRLEN];
    125 	int	exit_code = 0;
    126 
    127 	if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1)
    128 		return (1);
    129 	if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0)
    130 		return (1);
    131 
    132 	sys_clk = -1;  /* System clock freq. (in MHz) */
    133 
    134 	/*
    135 	 * Now display the machine's configuration. We do this if we
    136 	 * are not logging.
    137 	 */
    138 	if (!logging) {
    139 		struct utsname uts_buf;
    140 
    141 		/*
    142 		 * Display system banner
    143 		 */
    144 		(void) uname(&uts_buf);
    145 
    146 		log_printf(dgettext(TEXT_DOMAIN, "System Configuration:  "
    147 		    "Sun Microsystems  %s %s\n"), uts_buf.machine,
    148 		    get_prop_val(find_prop(root, "banner-name")), 0);
    149 
    150 		/* display system clock frequency */
    151 		value = get_prop_val(find_prop(root, "clock-frequency"));
    152 		if (value != NULL) {
    153 			sys_clk = ((*((int *)value)) + 500000) / 1000000;
    154 			log_printf(dgettext(TEXT_DOMAIN, "System clock "
    155 			    "frequency: %d MHz\n"), sys_clk, 0);
    156 		}
    157 
    158 		/* Display the Memory Size */
    159 		display_memorysize(tree, NULL, &grps, &memory_total);
    160 
    161 		/* Display the CPU devices */
    162 		sun4v_display_cpu_devices(plafh);
    163 
    164 		/* Display the Memory configuration */
    165 		class_node_found = 0;
    166 		sun4v_display_memory_conf(plafh);
    167 
    168 		/* Display all the IO cards. */
    169 		(void) sun4v_display_pci(plafh);
    170 		sun4v_display_diaginfo((log || (logging)), root, plafh);
    171 
    172 		if (picl_get_root(&rooth) != PICL_SUCCESS)
    173 			return (1);
    174 
    175 		/*
    176 		 * The physical-platform node may be missing on systems with
    177 		 * older firmware so don't consider that an error.
    178 		 */
    179 		if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM,
    180 		    &phyplatformh) != PICL_SUCCESS)
    181 			return (0);
    182 
    183 		if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME,
    184 		    PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS,
    185 		    strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS)
    186 			return (1);
    187 
    188 		syserrlog = log;
    189 		exit_code = sun4v_disp_env_status();
    190 	}
    191 	return (exit_code);
    192 }
    193 
    194 /*
    195  * The binding-name property encodes the bus type.
    196  */
    197 static void
    198 get_bus_type(picl_nodehdl_t nodeh, struct io_card *card)
    199 {
    200 	char val[PICL_PROPNAMELEN_MAX], *p, *q;
    201 
    202 	card->bus_type[0] = '\0';
    203 
    204 	if (picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, val,
    205 	    sizeof (val)) == PICL_SUCCESS) {
    206 		if (strstr(val, PICL_CLASS_PCIEX))
    207 			(void) strlcpy(card->bus_type, "PCIE",
    208 			    sizeof (card->bus_type));
    209 		else if (strstr(val, PICL_CLASS_PCI))
    210 			(void) strlcpy(card->bus_type, "PCIX",
    211 			    sizeof (card->bus_type));
    212 		else {
    213 			/*
    214 			 * Not perfect: process the binding-name until
    215 			 * we encounter something that we don't think would
    216 			 * be part of a bus type.  This may get confused a bit
    217 			 * if a device or vendor id is encoded right after
    218 			 * the bus class since there's no delimiter.  If the
    219 			 * id number begins with a hex digit [abcdef] then
    220 			 * this will become part of the bus type string
    221 			 * reported by prtdiag.  This is all an effort to
    222 			 * print something potentially useful for bus types
    223 			 * other than PCI/PCIe.
    224 			 *
    225 			 * We do this because this code will get called for
    226 			 * non-PCI class devices like the xaui (class sun4v.)
    227 			 */
    228 			if (strstr(val, "SUNW,") != NULL)
    229 				p = strchr(val, ',') + 1;
    230 			else
    231 				p = val;
    232 			q = p;
    233 			while (*p != '\0') {
    234 				if (isdigit((char)*p) || ispunct((char)*p)) {
    235 					*p = '\0';
    236 					break;
    237 				}
    238 				*p = (char)_toupper((int)*p);
    239 				++p;
    240 			}
    241 			(void) strlcpy(card->bus_type, q,
    242 			    sizeof (card->bus_type));
    243 		}
    244 	}
    245 }
    246 
    247 /*
    248  * Fetch the Label property for this device.  If none is found then
    249  * search all the siblings with the same device ID for a
    250  * Label and return that Label.  The plug-in can only match the canonical
    251  * path from the PRI with a specific devfs path.  So we take care of
    252  * devices with multiple functions here.  A leaf device downstream of
    253  * a bridge should fall out of here with PICL_PROPNOTFOUND, and the
    254  * caller can walk back up the tree in search of the slot's Label.
    255  */
    256 static picl_errno_t
    257 get_slot_label(picl_nodehdl_t nodeh, struct io_card *card)
    258 {
    259 	char val[PICL_PROPNAMELEN_MAX];
    260 	picl_errno_t err;
    261 	picl_nodehdl_t pnodeh;
    262 	uint32_t devid, sib_devid;
    263 	int32_t instance;
    264 
    265 	/*
    266 	 * If there's a Label at this node then return it - we're
    267 	 * done.
    268 	 */
    269 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
    270 	    sizeof (val));
    271 	if (err == PICL_SUCCESS) {
    272 		(void) strlcpy(card->slot_str, val, sizeof (card->slot_str));
    273 		return (err);
    274 	} else if (err != PICL_PROPNOTFOUND)
    275 		return (err);
    276 
    277 	/*
    278 	 * At this point we're starting to extrapolate what the Label
    279 	 * should be since there is none at this specific node.
    280 	 * Note that until the value of "err" is overwritten in the
    281 	 * loop below, its value should be PICL_PROPNOTFOUND.
    282 	 */
    283 
    284 	/*
    285 	 * The device must be attached, and we can figure that out if
    286 	 * the instance number is present and is not equal to -1.
    287 	 * This will prevent is from returning a Label for a sibling
    288 	 * node when the node passed in would have a unique Label if the
    289 	 * device were attached.  But if the device is downstream of a
    290 	 * node with a Label then pci_callback() will still find that
    291 	 * and use it.
    292 	 */
    293 	if (picl_get_propval_by_name(nodeh, PICL_PROP_INSTANCE, &instance,
    294 	    sizeof (instance)) != PICL_SUCCESS)
    295 		return (err);
    296 	if (instance == -1)
    297 		return (err);
    298 
    299 	/*
    300 	 * Narrow the search to just the one device ID.
    301 	 */
    302 	if (picl_get_propval_by_name(nodeh, PICL_PROP_DEVICE_ID, &devid,
    303 	    sizeof (devid)) != PICL_SUCCESS)
    304 		return (err);
    305 
    306 	/*
    307 	 * Go find the first child of the parent so we can search
    308 	 * all of the siblings.
    309 	 */
    310 	if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
    311 	    sizeof (pnodeh)) != PICL_SUCCESS)
    312 		return (err);
    313 	if (picl_get_propval_by_name(pnodeh, PICL_PROP_CHILD, &pnodeh,
    314 	    sizeof (pnodeh)) != PICL_SUCCESS)
    315 		return (err);
    316 
    317 	/*
    318 	 * If the child's device ID matches, then fetch the Label and
    319 	 * return it.  The first child/device ID should have a Label
    320 	 * associated with it.
    321 	 */
    322 	do {
    323 		if (picl_get_propval_by_name(pnodeh, PICL_PROP_DEVICE_ID,
    324 		    &sib_devid, sizeof (sib_devid)) == PICL_SUCCESS) {
    325 			if (sib_devid == devid) {
    326 				if ((err = picl_get_propval_by_name(pnodeh,
    327 				    PICL_PROP_LABEL, val, sizeof (val))) ==
    328 				    PICL_SUCCESS) {
    329 					(void) strlcpy(card->slot_str, val,
    330 					    sizeof (card->slot_str));
    331 					break;
    332 				}
    333 			}
    334 		}
    335 	} while (picl_get_propval_by_name(pnodeh, PICL_PROP_PEER, &pnodeh,
    336 	    sizeof (pnodeh)) == PICL_SUCCESS);
    337 
    338 	return (err);
    339 }
    340 
    341 static void
    342 get_slot_number(picl_nodehdl_t nodeh, struct io_card *card)
    343 {
    344 	picl_errno_t err;
    345 	picl_prophdl_t proph;
    346 	picl_propinfo_t pinfo;
    347 	picl_nodehdl_t pnodeh;
    348 	uint8_t *pval;
    349 	uint32_t dev_mask;
    350 	char uaddr[MAXSTRLEN];
    351 	int i;
    352 
    353 	err = PICL_SUCCESS;
    354 	while (err == PICL_SUCCESS) {
    355 		if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
    356 		    sizeof (pnodeh)) != PICL_SUCCESS) {
    357 			(void) strlcpy(card->slot_str, MOTHERBOARD,
    358 			    sizeof (card->slot_str));
    359 			card->slot = -1;
    360 			return;
    361 		}
    362 		if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES,
    363 		    &pinfo, &proph) == PICL_SUCCESS) {
    364 			break;
    365 		}
    366 		nodeh = pnodeh;
    367 	}
    368 	if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr,
    369 	    sizeof (uaddr)) != PICL_SUCCESS) {
    370 		(void) strlcpy(card->slot_str, MOTHERBOARD,
    371 		    sizeof (card->slot_str));
    372 		card->slot = -1;
    373 		return;
    374 	}
    375 	pval = (uint8_t *)malloc(pinfo.size);
    376 	if (!pval) {
    377 		(void) strlcpy(card->slot_str, MOTHERBOARD,
    378 		    sizeof (card->slot_str));
    379 		card->slot = -1;
    380 		return;
    381 	}
    382 	if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) {
    383 		(void) strlcpy(card->slot_str, MOTHERBOARD,
    384 		    sizeof (card->slot_str));
    385 		card->slot = -1;
    386 		free(pval);
    387 		return;
    388 	}
    389 
    390 	dev_mask = 0;
    391 	for (i = 0; i < sizeof (dev_mask); i++)
    392 		dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i));
    393 	for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) {
    394 		if (uaddr[i] == ',') {
    395 			uaddr[i] = '\0';
    396 			break;
    397 		}
    398 	}
    399 	card->slot = atol(uaddr);
    400 	if (((1 << card->slot) & dev_mask) == 0) {
    401 		(void) strlcpy(card->slot_str, MOTHERBOARD,
    402 		    sizeof (card->slot_str));
    403 		card->slot = -1;
    404 	} else {
    405 		char *p = (char *)(pval+sizeof (dev_mask));
    406 		int shift = sizeof (uint32_t)*8-1-card->slot;
    407 		uint32_t x = (dev_mask << shift) >> shift;
    408 		int count = 0;	/* count # of 1's in x */
    409 		int i = 0;
    410 		while (x != 0) {
    411 			count++;
    412 			x &= x-1;
    413 		}
    414 		while (count > 1) {
    415 			while (p[i++] != '\0')
    416 				;
    417 			count--;
    418 		}
    419 		(void) strlcpy(card->slot_str, (char *)(p+i),
    420 		    sizeof (card->slot_str));
    421 	}
    422 	free(pval);
    423 }
    424 
    425 /*
    426  * add all io devices under pci in io list
    427  */
    428 /* ARGSUSED */
    429 static int
    430 sun4v_pci_callback(picl_nodehdl_t pcih, void *args)
    431 {
    432 	char path[PICL_PROPNAMELEN_MAX];
    433 	char class[PICL_CLASSNAMELEN_MAX];
    434 	char name[PICL_PROPNAMELEN_MAX];
    435 	char model[PICL_PROPNAMELEN_MAX];
    436 	char binding_name[PICL_PROPNAMELEN_MAX];
    437 	char val[PICL_PROPNAMELEN_MAX];
    438 	char *compatible;
    439 	picl_errno_t err;
    440 	picl_nodehdl_t nodeh, pnodeh;
    441 	struct io_card pci_card;
    442 
    443 	/* Walk through the children */
    444 
    445 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
    446 	    sizeof (picl_nodehdl_t));
    447 
    448 	while (err == PICL_SUCCESS) {
    449 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
    450 		    class, sizeof (class));
    451 		if (err !=  PICL_SUCCESS)
    452 			return (err);
    453 
    454 		if (args) {
    455 			char *val = args;
    456 			if (strcmp(class, val) == 0) {
    457 				err = picl_get_propval_by_name(nodeh,
    458 				    PICL_PROP_PEER, &nodeh,
    459 				    sizeof (picl_nodehdl_t));
    460 				continue;
    461 			} else if (strcmp(val, PICL_CLASS_PCIEX) == 0 &&
    462 			    strcmp(class, PICL_CLASS_PCI) == 0) {
    463 				err = picl_get_propval_by_name(nodeh,
    464 				    PICL_PROP_PEER, &nodeh,
    465 				    sizeof (picl_nodehdl_t));
    466 				continue;
    467 			} else if (strcmp(val, PICL_CLASS_PCI) == 0 &&
    468 			    strcmp(class, PICL_CLASS_PCIEX) == 0) {
    469 				err = picl_get_propval_by_name(nodeh,
    470 				    PICL_PROP_PEER, &nodeh,
    471 				    sizeof (picl_nodehdl_t));
    472 				continue;
    473 			}
    474 		}
    475 
    476 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
    477 		    path, sizeof (path));
    478 		if (err != PICL_SUCCESS)
    479 			return (err);
    480 
    481 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
    482 
    483 		pnodeh = nodeh;
    484 		err = get_slot_label(nodeh, &pci_card);
    485 
    486 		/*
    487 		 * No Label at this node, maybe we're looking at a device
    488 		 * downstream of a bridge.  Walk back up and find a Label and
    489 		 * record that node in "pnodeh".
    490 		 */
    491 		while (err != PICL_SUCCESS) {
    492 			if (err != PICL_PROPNOTFOUND)
    493 				break;
    494 			else if (picl_get_propval_by_name(pnodeh,
    495 			    PICL_PROP_PARENT, &pnodeh, sizeof (pnodeh)) ==
    496 			    PICL_SUCCESS)
    497 				err = get_slot_label(pnodeh, &pci_card);
    498 			else
    499 				break;
    500 		}
    501 
    502 		/*
    503 		 * Can't find a Label for this device in the PCI heirarchy.
    504 		 * Try to synthesize a slot name from atoms.  This depends
    505 		 * on the OBP slot_names property being implemented, and this
    506 		 * so far doesn't seem to be on sun4v.  But just in case that
    507 		 * is resurrected, the code is here.
    508 		 */
    509 		if (err != PICL_SUCCESS) {
    510 			pnodeh = nodeh;
    511 			get_slot_number(nodeh, &pci_card);
    512 		}
    513 
    514 		/*
    515 		 * Passing in pnodeh instead of nodeh will cause prtdiag
    516 		 * to display the type of IO slot for the leaf node.  For
    517 		 * built-in devices and a lot of IO cards these will be
    518 		 * the same thing.  But for IO cards with bridge chips or
    519 		 * for things like expansion chassis, prtdiag will report
    520 		 * the bus type of the IO slot and not the leaf, which
    521 		 * could be different things.
    522 		 */
    523 		get_bus_type(pnodeh, &pci_card);
    524 
    525 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
    526 		    sizeof (name));
    527 		if (err == PICL_PROPNOTFOUND)
    528 			(void) strlcpy(name, "", sizeof (name));
    529 		else if (err != PICL_SUCCESS)
    530 			return (err);
    531 
    532 		err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val,
    533 		    sizeof (val));
    534 		if (err == PICL_PROPNOTFOUND)
    535 			(void) strlcpy(val, "", sizeof (val));
    536 		else if (err != PICL_SUCCESS)
    537 			return (err);
    538 
    539 		(void) snprintf(pci_card.status, sizeof (pci_card.status),
    540 		    "%s", pci_card.slot_str);
    541 
    542 		/*
    543 		 * Get the name of this card. If binding_name is found,
    544 		 * name will be <nodename>-<binding_name>.
    545 		 */
    546 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
    547 		    binding_name, sizeof (binding_name));
    548 		if (err == PICL_SUCCESS) {
    549 			if (strcmp(name, binding_name) != 0) {
    550 				(void) strlcat(name, "-", sizeof (name));
    551 				(void) strlcat(name, binding_name,
    552 				    sizeof (name));
    553 			}
    554 		} else if (err == PICL_PROPNOTFOUND) {
    555 			/*
    556 			 * if compatible prop is not found, name will be
    557 			 * <nodename>-<compatible>
    558 			 */
    559 			err = sun4v_get_first_compatible_value(nodeh,
    560 			    &compatible);
    561 			if (err == PICL_SUCCESS) {
    562 				(void) strlcat(name, "-", sizeof (name));
    563 				(void) strlcat(name, compatible,
    564 				    sizeof (name));
    565 				free(compatible);
    566 			}
    567 		} else
    568 			return (err);
    569 
    570 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
    571 
    572 		/* Get the model of this card */
    573 
    574 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
    575 		    model, sizeof (model));
    576 		if (err == PICL_PROPNOTFOUND)
    577 			(void) strlcpy(model, "", sizeof (model));
    578 		else if (err != PICL_SUCCESS)
    579 			return (err);
    580 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
    581 
    582 		/* Print NAC name */
    583 		log_printf("%-18s", pci_card.status);
    584 		/* Print IO Type */
    585 		log_printf("%-6s", pci_card.bus_type);
    586 		/* Printf Card Name */
    587 		log_printf("%-34s", pci_card.name);
    588 		/* Print Card Model */
    589 		log_printf("%-8s", pci_card.model);
    590 		log_printf("\n");
    591 		/* Print Status */
    592 		log_printf("%-18s", val);
    593 		/* Print IO Type */
    594 		log_printf("%-6s", "");
    595 		/* Print Parent Path */
    596 		log_printf("%-44s", pci_card.notes);
    597 		log_printf("\n");
    598 
    599 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
    600 		    sizeof (picl_nodehdl_t));
    601 	}
    602 	return (PICL_WALK_CONTINUE);
    603 }
    604 
    605 /*
    606  * display_pci
    607  * Display all the PCI IO cards on this board.
    608  */
    609 void
    610 sun4v_display_pci(picl_nodehdl_t plafh)
    611 {
    612 	char *fmt = "%-17s %-5s %-33s %-8s";
    613 	/* Have we printed the column headings? */
    614 	static int banner = FALSE;
    615 
    616 	if (banner == FALSE) {
    617 		log_printf("\n");
    618 		log_printf("================================");
    619 		log_printf(" IO Devices ");
    620 		log_printf("================================");
    621 		log_printf("\n");
    622 		log_printf(fmt, "Slot +", "Bus", "Name +", "Model", 0);
    623 		log_printf("\n");
    624 		log_printf(fmt, "Status", "Type", "Path", "", 0);
    625 		log_printf("\n");
    626 		log_printf("---------------------------------"
    627 		    "-------------------------------------------\n");
    628 		banner = TRUE;
    629 	}
    630 
    631 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
    632 	    PICL_CLASS_PCIEX, sun4v_pci_callback);
    633 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
    634 	    PICL_CLASS_PCI, sun4v_pci_callback);
    635 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V,
    636 	    PICL_CLASS_SUN4V, sun4v_pci_callback);
    637 }
    638 
    639 /*
    640  * return the first compatible value
    641  */
    642 static int
    643 sun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
    644 {
    645 	picl_errno_t err;
    646 	picl_prophdl_t proph;
    647 	picl_propinfo_t pinfo;
    648 	picl_prophdl_t tblh;
    649 	picl_prophdl_t rowproph;
    650 	char *pval;
    651 
    652 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
    653 	    &pinfo, &proph);
    654 	if (err != PICL_SUCCESS)
    655 		return (err);
    656 
    657 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
    658 		pval = malloc(pinfo.size);
    659 		if (pval == NULL)
    660 			return (PICL_FAILURE);
    661 		err = picl_get_propval(proph, pval, pinfo.size);
    662 		if (err != PICL_SUCCESS) {
    663 			free(pval);
    664 			return (err);
    665 		}
    666 		*outbuf = pval;
    667 		return (PICL_SUCCESS);
    668 	}
    669 
    670 	if (pinfo.type != PICL_PTYPE_TABLE)
    671 		return (PICL_FAILURE);
    672 
    673 	/* get first string from table */
    674 	err = picl_get_propval(proph, &tblh, pinfo.size);
    675 	if (err != PICL_SUCCESS)
    676 		return (err);
    677 
    678 	err = picl_get_next_by_row(tblh, &rowproph);
    679 	if (err != PICL_SUCCESS)
    680 		return (err);
    681 
    682 	err = picl_get_propinfo(rowproph, &pinfo);
    683 	if (err != PICL_SUCCESS)
    684 		return (err);
    685 
    686 	pval = malloc(pinfo.size);
    687 	if (pval == NULL)
    688 		return (PICL_FAILURE);
    689 
    690 	err = picl_get_propval(rowproph, pval, pinfo.size);
    691 	if (err != PICL_SUCCESS) {
    692 		free(pval);
    693 		return (err);
    694 	}
    695 
    696 	*outbuf = pval;
    697 	return (PICL_SUCCESS);
    698 }
    699 
    700 /*
    701  * print size of a memory segment
    702  */
    703 static void
    704 print_memory_segment_size(uint64_t size)
    705 {
    706 	uint64_t kbyte = 1024;
    707 	uint64_t mbyte = kbyte * kbyte;
    708 	uint64_t gbyte = kbyte * mbyte;
    709 	uint64_t tbyte = kbyte * gbyte;
    710 	char buf[MEMORY_SIZE_FIELD];
    711 
    712 	if (size >= tbyte) {
    713 		if (size % tbyte == 0)
    714 			(void) snprintf(buf, sizeof (buf), "%d TB",
    715 			    (int)(size / tbyte));
    716 		else
    717 			(void) snprintf(buf, sizeof (buf), "%.2f TB",
    718 			    (float)size / tbyte);
    719 	} else if (size >= gbyte) {
    720 		if (size % gbyte == 0)
    721 			(void) snprintf(buf, sizeof (buf), "%d GB",
    722 			    (int)(size / gbyte));
    723 		else
    724 			(void) snprintf(buf, sizeof (buf), "%.2f GB",
    725 			    (float)size / gbyte);
    726 	} else if (size >= mbyte) {
    727 		if (size % mbyte == 0)
    728 			(void) snprintf(buf, sizeof (buf), "%d MB",
    729 			    (int)(size / mbyte));
    730 		else
    731 			(void) snprintf(buf, sizeof (buf), "%.2f MB",
    732 			    (float)size / mbyte);
    733 	} else {
    734 		if (size % kbyte == 0)
    735 			(void) snprintf(buf, sizeof (buf), "%d KB",
    736 			    (int)(size / kbyte));
    737 		else
    738 			(void) snprintf(buf, sizeof (buf), "%.2f KB",
    739 			    (float)size / kbyte);
    740 	}
    741 	log_printf("%-9s", buf);
    742 }
    743 
    744 /*
    745  * Enumerate banks and dimms within a memory segment.  We're handed
    746  * the first bank within the segment - we assume there are dimms
    747  * (memory-module) nodes underneath.
    748  */
    749 static void
    750 print_memory_segment_contain(picl_nodehdl_t bank_nodeh)
    751 {
    752 	char val[PICL_PROPNAMELEN_MAX];
    753 	picl_nodehdl_t module_nodeh;
    754 	int flag = 0;
    755 	uint64_t size;
    756 
    757 	do {
    758 		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_CHILD,
    759 		    &module_nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
    760 			continue;
    761 		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_SIZE,
    762 		    &size, sizeof (size)) == PICL_SUCCESS) {
    763 			if (!flag) {
    764 				print_memory_segment_size(size);
    765 			} else {
    766 				log_printf("                "
    767 				    "                    ");
    768 				print_memory_segment_size(size);
    769 				flag = 0;
    770 			}
    771 		}
    772 		do {
    773 			if (picl_get_propval_by_name(module_nodeh,
    774 			    PICL_PROP_NAC, val, sizeof (val)) !=
    775 			    PICL_SUCCESS)
    776 				continue;
    777 			else {
    778 				if (!flag) {
    779 					log_printf("%s\n", val);
    780 					flag = 1;
    781 				} else {
    782 					log_printf("%s%s\n",
    783 					    "                       "
    784 					    "                      ",
    785 					    val);
    786 				}
    787 			}
    788 		} while (picl_get_propval_by_name(module_nodeh, PICL_PROP_PEER,
    789 		    &module_nodeh, sizeof (picl_nodehdl_t)) ==
    790 		    PICL_SUCCESS);
    791 	} while (picl_get_propval_by_name(bank_nodeh, PICL_PROP_PEER,
    792 	    &bank_nodeh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS);
    793 }
    794 
    795 /*
    796  * Search node where _class=="memory-segment"
    797  * print "Base Address", "Size", etc
    798  */
    799 /*ARGSUSED*/
    800 static int
    801 sun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args)
    802 {
    803 	uint64_t base;
    804 	uint64_t size;
    805 	uint64_t ifactor;
    806 	picl_errno_t err = PICL_SUCCESS;
    807 
    808 	if (class_node_found == 0) {
    809 		class_node_found = 1;
    810 		return (PICL_WALK_TERMINATE);
    811 	}
    812 	while (err == PICL_SUCCESS) {
    813 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS,
    814 		    &base, sizeof (base));
    815 		if (err !=  PICL_SUCCESS)
    816 			break;
    817 		err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE,
    818 		    &size, sizeof (size));
    819 		if (err !=  PICL_SUCCESS)
    820 			break;
    821 		err = picl_get_propval_by_name(nodeh,
    822 		    PICL_PROP_INTERLEAVE_FACTOR, &ifactor,
    823 		    sizeof (ifactor));
    824 		if (err !=  PICL_SUCCESS)
    825 			break;
    826 		log_printf("0x%-13llx", base);
    827 		print_memory_segment_size(size);
    828 		log_printf("%-12lld", ifactor);
    829 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
    830 		    &nodeh, sizeof (nodeh));
    831 		if (err ==  PICL_SUCCESS)
    832 			print_memory_segment_contain(nodeh);
    833 		log_printf("\n");
    834 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
    835 		    sizeof (picl_nodehdl_t));
    836 	}
    837 
    838 	return (PICL_WALK_CONTINUE);
    839 }
    840 
    841 /*ARGSUSED*/
    842 void
    843 sun4v_display_memory_conf(picl_nodehdl_t plafh)
    844 {
    845 	char *fmt = "%-14s %-8s %-11s %-8s %-s";
    846 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
    847 	    NULL, sun4v_memory_conf_callback);
    848 	if (class_node_found == 0)
    849 		return;
    850 	log_printf("\n");
    851 	log_printf("=======================");
    852 	log_printf(" Physical Memory Configuration ");
    853 	log_printf("========================");
    854 	log_printf("\n");
    855 	log_printf("Segment Table:\n");
    856 	log_printf(
    857 	    "--------------------------------------------------------------\n");
    858 	log_printf(fmt, "Base", "Segment", "Interleave", "Bank", "Contains", 0);
    859 	log_printf("\n");
    860 	log_printf(fmt, "Address", "Size", "Factor", "Size", "Modules", 0);
    861 	log_printf("\n");
    862 	log_printf(
    863 	    "--------------------------------------------------------------\n");
    864 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
    865 	    NULL, sun4v_memory_conf_callback);
    866 }
    867 
    868 void
    869 sun4v_display_cpu_devices(picl_nodehdl_t plafh)
    870 {
    871 	char *fmt = "%-6s %-9s %-22s %-6s";
    872 
    873 	/*
    874 	 * Display the table header for CPUs . Then display the CPU
    875 	 * frequency, cache size, and processor revision of all cpus.
    876 	 */
    877 	log_printf(dgettext(TEXT_DOMAIN,
    878 	    "\n"
    879 	    "================================"
    880 	    " Virtual CPUs "
    881 	    "================================"
    882 	    "\n"
    883 	    "\n"));
    884 	log_printf("\n");
    885 	log_printf(fmt, "CPU ID", "Frequency", "Implementation",
    886 	    "Status", 0);
    887 	log_printf("\n");
    888 	log_printf(fmt, "------", "---------",
    889 	    "----------------------", "-------", 0);
    890 	log_printf("\n");
    891 
    892 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
    893 	    sun4v_display_cpus);
    894 }
    895 
    896 /*
    897  * Display the CPUs present on this board.
    898  */
    899 /*ARGSUSED*/
    900 int
    901 sun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
    902 {
    903 	int status;
    904 	picl_prophdl_t proph;
    905 	picl_prophdl_t tblh;
    906 	picl_prophdl_t rowproph;
    907 	picl_propinfo_t propinfo;
    908 	int *int_value;
    909 	int cpuid;
    910 	char *comp_value;
    911 	char *no_prop_value = "   ";
    912 	char freq_str[MAXSTRLEN];
    913 	char state[MAXSTRLEN];
    914 
    915 	/*
    916 	 * Get cpuid property and print it and the NAC name
    917 	 */
    918 	status = picl_get_propinfo_by_name(cpuh, OBP_PROP_CPUID, &propinfo,
    919 	    &proph);
    920 	if (status == PICL_SUCCESS) {
    921 		status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
    922 		if (status != PICL_SUCCESS) {
    923 			log_printf("%-7s", no_prop_value);
    924 		} else {
    925 			log_printf("%-7d", cpuid);
    926 		}
    927 	} else {
    928 		log_printf("%-7s", no_prop_value);
    929 	}
    930 
    931 clock_freq:
    932 	status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
    933 	    &proph);
    934 	if (status == PICL_SUCCESS) {
    935 		int_value = malloc(propinfo.size);
    936 		if (int_value == NULL) {
    937 			log_printf("%-10s", no_prop_value);
    938 			goto compatible;
    939 		}
    940 		status = picl_get_propval(proph, int_value, propinfo.size);
    941 		if (status != PICL_SUCCESS) {
    942 			log_printf("%-10s", no_prop_value);
    943 		} else {
    944 			/* Running frequency */
    945 			(void) snprintf(freq_str, sizeof (freq_str), "%d MHz",
    946 			    CLK_FREQ_TO_MHZ(*int_value));
    947 			log_printf("%-10s", freq_str);
    948 		}
    949 		free(int_value);
    950 	} else
    951 		log_printf("%-10s", no_prop_value);
    952 
    953 compatible:
    954 	status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
    955 	    &proph);
    956 	if (status == PICL_SUCCESS) {
    957 		if (propinfo.type == PICL_PTYPE_CHARSTRING) {
    958 			/*
    959 			 * Compatible Property only has 1 value
    960 			 */
    961 			comp_value = malloc(propinfo.size);
    962 			if (comp_value == NULL) {
    963 				log_printf("%-23s", no_prop_value, 0);
    964 				goto state;
    965 			}
    966 			status = picl_get_propval(proph, comp_value,
    967 			    propinfo.size);
    968 			if (status != PICL_SUCCESS)
    969 				log_printf("%-23s", no_prop_value, 0);
    970 			else
    971 				log_printf("%-23s", comp_value, 0);
    972 			free(comp_value);
    973 		} else if (propinfo.type == PICL_PTYPE_TABLE) {
    974 			/*
    975 			 * Compatible Property has multiple values
    976 			 */
    977 			status = picl_get_propval(proph, &tblh, propinfo.size);
    978 			if (status != PICL_SUCCESS) {
    979 				log_printf("%-23s", no_prop_value, 0);
    980 				goto state;
    981 			}
    982 			status = picl_get_next_by_row(tblh, &rowproph);
    983 			if (status != PICL_SUCCESS) {
    984 				log_printf("%-23s", no_prop_value, 0);
    985 				goto state;
    986 			}
    987 
    988 			status = picl_get_propinfo(rowproph, &propinfo);
    989 			if (status != PICL_SUCCESS) {
    990 				log_printf("%-23s", no_prop_value, 0);
    991 				goto state;
    992 			}
    993 
    994 			comp_value = malloc(propinfo.size);
    995 			if (comp_value == NULL) {
    996 				log_printf("%-23s", no_prop_value, 0);
    997 				goto state;
    998 			}
    999 			status = picl_get_propval(rowproph, comp_value,
   1000 			    propinfo.size);
   1001 			if (status != PICL_SUCCESS)
   1002 				log_printf("%-23s", no_prop_value, 0);
   1003 			else
   1004 				log_printf("%-23s", comp_value, 0);
   1005 			free(comp_value);
   1006 		}
   1007 	} else
   1008 		log_printf("%-23s", no_prop_value, 0);
   1009 
   1010 state:
   1011 	status = picl_get_propinfo_by_name(cpuh, PICL_PROP_STATE,
   1012 	    &propinfo, &proph);
   1013 	if (status == PICL_SUCCESS) {
   1014 		status = picl_get_propval(proph, state, sizeof (state));
   1015 		if (status != PICL_SUCCESS) {
   1016 			log_printf("%-9s", no_prop_value);
   1017 		} else {
   1018 			log_printf("%-9s", state);
   1019 		}
   1020 	} else
   1021 		log_printf("%-9s", no_prop_value);
   1022 
   1023 done:
   1024 	log_printf("\n");
   1025 	return (PICL_WALK_CONTINUE);
   1026 }
   1027 
   1028 void
   1029 sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
   1030 {
   1031 #ifdef	lint
   1032 	flag = flag;
   1033 	root = root;
   1034 	plafh = plafh;
   1035 #endif
   1036 	/*
   1037 	 * This function is intentionally empty
   1038 	 */
   1039 }
   1040 
   1041 void
   1042 display_boardnum(int num)
   1043 {
   1044 	log_printf("%2d   ", num, 0);
   1045 }
   1046 
   1047 static int
   1048 sun4v_disp_env_status()
   1049 {
   1050 	int	exit_code = 0;
   1051 
   1052 	if (phyplatformh == 0)
   1053 		return (0);
   1054 	log_printf("\n");
   1055 	log_printf("============================");
   1056 	log_printf(" Environmental Status ");
   1057 	log_printf("============================");
   1058 	log_printf("\n");
   1059 
   1060 	class_node_found = 0;
   1061 	all_status_ok = 1;
   1062 	sun4v_env_print_fan_sensors();
   1063 	exit_code |= (!all_status_ok);
   1064 
   1065 	class_node_found = 0;
   1066 	all_status_ok = 1;
   1067 	sun4v_env_print_fan_indicators();
   1068 	exit_code |= (!all_status_ok);
   1069 
   1070 	class_node_found = 0;
   1071 	all_status_ok = 1;
   1072 	sun4v_env_print_temp_sensors();
   1073 	exit_code |= (!all_status_ok);
   1074 
   1075 	class_node_found = 0;
   1076 	all_status_ok = 1;
   1077 	sun4v_env_print_temp_indicators();
   1078 	exit_code |= (!all_status_ok);
   1079 
   1080 	class_node_found = 0;
   1081 	all_status_ok = 1;
   1082 	sun4v_env_print_current_sensors();
   1083 	exit_code |= (!all_status_ok);
   1084 
   1085 	class_node_found = 0;
   1086 	all_status_ok = 1;
   1087 	sun4v_env_print_current_indicators();
   1088 	exit_code |= (!all_status_ok);
   1089 
   1090 	class_node_found = 0;
   1091 	all_status_ok = 1;
   1092 	sun4v_env_print_voltage_sensors();
   1093 	exit_code |= (!all_status_ok);
   1094 
   1095 	class_node_found = 0;
   1096 	all_status_ok = 1;
   1097 	sun4v_env_print_voltage_indicators();
   1098 	exit_code |= (!all_status_ok);
   1099 
   1100 	class_node_found = 0;
   1101 	all_status_ok = 1;
   1102 	sun4v_env_print_LEDs();
   1103 	exit_code |= (!all_status_ok);
   1104 
   1105 	class_node_found = 0;
   1106 	all_status_ok = 1;
   1107 	sun4v_print_fru_status();
   1108 	exit_code |= (!all_status_ok);
   1109 
   1110 	class_node_found = 0;
   1111 	sun4v_print_fw_rev();
   1112 
   1113 	class_node_found = 0;
   1114 	sun4v_print_openprom_rev();
   1115 
   1116 	sun4v_print_chassis_serial_no();
   1117 
   1118 	return (exit_code);
   1119 }
   1120 
   1121 /*ARGSUSED*/
   1122 static int
   1123 sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args)
   1124 {
   1125 	char val[PICL_PROPNAMELEN_MAX];
   1126 	picl_nodehdl_t parenth;
   1127 	char *names[PARENT_NAMES];
   1128 	char *base_units[PICL_PROPNAMELEN_MAX];
   1129 	char *loc;
   1130 	int i;
   1131 	char *prop;
   1132 	picl_errno_t err;
   1133 	int32_t lo_warning, lo_shutdown, lo_poweroff;
   1134 	int32_t hi_warning, hi_shutdown, hi_poweroff;
   1135 	int32_t current_val;
   1136 	int32_t exponent;
   1137 	double display_val;
   1138 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
   1139 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
   1140 	sensor_status_t sensor_status = SENSOR_OK;
   1141 
   1142 	if (class_node_found == 0) {
   1143 		class_node_found = 1;
   1144 		return (PICL_WALK_TERMINATE);
   1145 	}
   1146 
   1147 	prop = (char *)args;
   1148 	if (!prop) {
   1149 		sensor_status = SENSOR_UNKNOWN;
   1150 		all_status_ok = 0;
   1151 	} else {
   1152 		err = picl_get_propval_by_name(nodeh,
   1153 		    PICL_PROP_OPERATIONAL_STATUS, val,
   1154 		    sizeof (val));
   1155 		if (err == PICL_SUCCESS) {
   1156 			if (strcmp(val, "disabled") == 0) {
   1157 				sensor_status = SENSOR_DISABLED;
   1158 			}
   1159 		}
   1160 	}
   1161 
   1162 	if (sensor_status != SENSOR_DISABLED &&
   1163 	    sensor_status != SENSOR_UNKNOWN) {
   1164 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
   1165 		    sizeof (current_val)) != PICL_SUCCESS) {
   1166 			sensor_status = SENSOR_UNKNOWN;
   1167 		} else {
   1168 			if (picl_get_propval_by_name(nodeh,
   1169 			    PICL_PROP_LOW_WARNING,
   1170 			    &lo_warning, sizeof (lo_warning)) != PICL_SUCCESS)
   1171 				lo_warning = INVALID_THRESHOLD;
   1172 			if (picl_get_propval_by_name(nodeh,
   1173 			    PICL_PROP_LOW_SHUTDOWN,
   1174 			    &lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS)
   1175 				lo_shutdown = INVALID_THRESHOLD;
   1176 			if (picl_get_propval_by_name(nodeh,
   1177 			    PICL_PROP_LOW_POWER_OFF,
   1178 			    &lo_poweroff, sizeof (lo_poweroff)) != PICL_SUCCESS)
   1179 				lo_poweroff = INVALID_THRESHOLD;
   1180 			if (picl_get_propval_by_name(nodeh,
   1181 			    PICL_PROP_HIGH_WARNING,
   1182 			    &hi_warning, sizeof (hi_warning)) != PICL_SUCCESS)
   1183 				hi_warning = INVALID_THRESHOLD;
   1184 			if (picl_get_propval_by_name(nodeh,
   1185 			    PICL_PROP_HIGH_SHUTDOWN,
   1186 			    &hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS)
   1187 				hi_shutdown = INVALID_THRESHOLD;
   1188 			if (picl_get_propval_by_name(nodeh,
   1189 			    PICL_PROP_HIGH_POWER_OFF,
   1190 			    &hi_poweroff, sizeof (hi_poweroff)) != PICL_SUCCESS)
   1191 				hi_poweroff = INVALID_THRESHOLD;
   1192 
   1193 			if ((lo_poweroff != INVALID_THRESHOLD &&
   1194 			    current_val <= lo_poweroff) ||
   1195 			    (hi_poweroff != INVALID_THRESHOLD &&
   1196 			    current_val >= hi_poweroff)) {
   1197 				sensor_status = SENSOR_FAILED;
   1198 			} else if ((lo_shutdown != INVALID_THRESHOLD &&
   1199 			    current_val <= lo_shutdown) ||
   1200 			    (hi_shutdown != INVALID_THRESHOLD &&
   1201 			    current_val >= hi_shutdown)) {
   1202 				sensor_status = SENSOR_FAILED;
   1203 			} else if ((lo_warning != INVALID_THRESHOLD &&
   1204 			    current_val <= lo_warning) ||
   1205 			    (hi_warning != INVALID_THRESHOLD &&
   1206 			    current_val >= hi_warning)) {
   1207 				sensor_status = SENSOR_WARN;
   1208 			} else {
   1209 				sensor_status = SENSOR_OK;
   1210 			}
   1211 		}
   1212 	}
   1213 
   1214 	if (syserrlog == 0) {
   1215 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
   1216 			all_status_ok = 0;
   1217 			return (PICL_WALK_TERMINATE);
   1218 		}
   1219 		if (sensor_status == SENSOR_OK) {
   1220 			return (PICL_WALK_CONTINUE);
   1221 		}
   1222 	}
   1223 
   1224 	/*
   1225 	 * If we're here then prtdiag was invoked with "-v" or we have
   1226 	 * a sensor that is beyond a threshold, so give them a book to
   1227 	 * read instead of the Cliff Notes.
   1228 	 */
   1229 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
   1230 	    sizeof (parenth));
   1231 	if (err != PICL_SUCCESS) {
   1232 		log_printf("\n");
   1233 		return (PICL_WALK_CONTINUE);
   1234 	}
   1235 
   1236 	/* gather up the path name for the sensor */
   1237 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
   1238 		for (i = 0; i < PARENT_NAMES; i++) {
   1239 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
   1240 			    NULL) {
   1241 				while (--i > -1)
   1242 					free(names[i]);
   1243 				free(loc);
   1244 				loc = NULL;
   1245 			}
   1246 		}
   1247 	}
   1248 	i = 0;
   1249 	if (loc != 0) {
   1250 		while (err == PICL_SUCCESS) {
   1251 			if (parenth == phyplatformh)
   1252 				break;
   1253 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
   1254 			    names[i++], PICL_PROPNAMELEN_MAX);
   1255 			if (err != PICL_SUCCESS) {
   1256 				i--;
   1257 				break;
   1258 			}
   1259 			if (i == PARENT_NAMES)
   1260 				break;
   1261 			err = picl_get_propval_by_name(parenth,
   1262 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
   1263 		}
   1264 		loc[0] = '\0';
   1265 		if (--i > -1) {
   1266 			(void) strlcat(loc, names[i],
   1267 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
   1268 		}
   1269 		while (--i > -1) {
   1270 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
   1271 			    PARENT_NAMES);
   1272 			(void) strlcat(loc, names[i],
   1273 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
   1274 		}
   1275 		log_printf("%-35s", loc);
   1276 		for (i = 0; i < PARENT_NAMES; i++)
   1277 			free(names[i]);
   1278 		free(loc);
   1279 	} else {
   1280 		log_printf("%-35s", " ");
   1281 	}
   1282 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
   1283 	    sizeof (val));
   1284 	if (err == PICL_SUCCESS)
   1285 		log_printf("%-15s", val);
   1286 
   1287 	/*
   1288 	 * Get the exponent if present, and do a little math so that
   1289 	 * if we need to we can print a normalized value for the
   1290 	 * sensor reading.
   1291 	 */
   1292 	if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPONENT,
   1293 	    &exponent, sizeof (exponent)) != PICL_SUCCESS)
   1294 		exponent = 0;
   1295 	if (exponent == 0)
   1296 		display_val = (double)current_val;
   1297 	else {
   1298 		display_val = (double)current_val *
   1299 		    pow((double)10, (double)exponent);
   1300 
   1301 		/*
   1302 		 * Sometimes ILOM will scale a sensor reading but
   1303 		 * there will be nothing to the right of the decimal
   1304 		 * once that value is normalized.  Setting the
   1305 		 * exponent to zero will prevent the printf below
   1306 		 * from printing extraneous zeros.  Otherwise a
   1307 		 * negative exponent is used to set the precision
   1308 		 * for the printf.
   1309 		 */
   1310 		if ((int)display_val == display_val || exponent > 0)
   1311 			exponent = 0;
   1312 	}
   1313 
   1314 	err = picl_get_propval_by_name(nodeh, PICL_PROP_BASE_UNITS,
   1315 	    base_units, sizeof (base_units));
   1316 	if (err != PICL_SUCCESS)
   1317 		base_units[0] = '\0';
   1318 
   1319 	switch (sensor_status) {
   1320 	case SENSOR_FAILED:
   1321 		log_printf("%-s", "failed (");
   1322 		log_printf("%-.*f", abs(exponent), display_val);
   1323 		log_printf("%-s %s", base_units, ")");
   1324 		break;
   1325 	case SENSOR_WARN:
   1326 		log_printf("%-s", "warning (");
   1327 		log_printf("%-.*f", abs(exponent), display_val);
   1328 		log_printf("%-s %s", base_units, ")");
   1329 		break;
   1330 	case SENSOR_DISABLED:
   1331 		log_printf("%-s", "disabled");
   1332 		break;
   1333 	case SENSOR_OK:
   1334 		log_printf("%-s", "ok");
   1335 		break;
   1336 	default:
   1337 		log_printf("%-s", "unknown");
   1338 		break;
   1339 	}
   1340 
   1341 	log_printf("\n");
   1342 	return (PICL_WALK_CONTINUE);
   1343 }
   1344 
   1345 /*ARGSUSED*/
   1346 static int
   1347 sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args)
   1348 {
   1349 	char current_val[PICL_PROPNAMELEN_MAX];
   1350 	char expected_val[PICL_PROPNAMELEN_MAX];
   1351 	char label[PICL_PROPNAMELEN_MAX];
   1352 	picl_nodehdl_t parenth;
   1353 	char *names[PARENT_NAMES];
   1354 	char *loc;
   1355 	int i = 0;
   1356 	char *prop = (char *)args;
   1357 	picl_errno_t err = PICL_SUCCESS;
   1358 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
   1359 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
   1360 	sensor_status_t sensor_status = SENSOR_OK;
   1361 
   1362 	if (class_node_found == 0) {
   1363 		class_node_found = 1;
   1364 		return (PICL_WALK_TERMINATE);
   1365 	}
   1366 
   1367 	prop = (char *)args;
   1368 	if (!prop) {
   1369 		sensor_status = SENSOR_UNKNOWN;
   1370 		all_status_ok = 0;
   1371 	} else {
   1372 		err = picl_get_propval_by_name(nodeh,
   1373 		    PICL_PROP_OPERATIONAL_STATUS, current_val,
   1374 		    sizeof (current_val));
   1375 		if (err == PICL_SUCCESS) {
   1376 			if (strcmp(current_val, "disabled") == 0) {
   1377 				sensor_status = SENSOR_DISABLED;
   1378 			}
   1379 		}
   1380 	}
   1381 
   1382 	if (sensor_status != SENSOR_DISABLED &&
   1383 	    sensor_status != SENSOR_UNKNOWN) {
   1384 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
   1385 		    sizeof (current_val)) != PICL_SUCCESS) {
   1386 			(void) strlcpy(current_val, "unknown",
   1387 			    sizeof (current_val));
   1388 			sensor_status = SENSOR_UNKNOWN;
   1389 		} else {
   1390 			if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPECTED,
   1391 			    &expected_val, sizeof (expected_val)) !=
   1392 			    PICL_SUCCESS) {
   1393 				sensor_status = SENSOR_UNKNOWN;
   1394 			} else {
   1395 				if (strncmp(current_val, expected_val,
   1396 				    sizeof (current_val)) == 0) {
   1397 					sensor_status = SENSOR_OK;
   1398 				} else {
   1399 					sensor_status = SENSOR_FAILED;
   1400 				}
   1401 			}
   1402 		}
   1403 	}
   1404 
   1405 	if (syserrlog == 0) {
   1406 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
   1407 			all_status_ok = 0;
   1408 			return (PICL_WALK_TERMINATE);
   1409 		}
   1410 		if (sensor_status == SENSOR_OK) {
   1411 			return (PICL_WALK_CONTINUE);
   1412 		}
   1413 	}
   1414 
   1415 	/*
   1416 	 * If we're here then prtdiag was invoked with "-v" or we have
   1417 	 * a sensor that is beyond a threshold, so give them a book to
   1418 	 * read instead of the Cliff Notes.
   1419 	 */
   1420 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
   1421 	    sizeof (parenth));
   1422 	if (err != PICL_SUCCESS) {
   1423 		log_printf("\n");
   1424 		return (PICL_WALK_CONTINUE);
   1425 	}
   1426 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
   1427 		for (i = 0; i < PARENT_NAMES; i++) {
   1428 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
   1429 			    NULL) {
   1430 				while (--i > -1)
   1431 					free(names[i]);
   1432 				free(loc);
   1433 				loc = NULL;
   1434 			}
   1435 		}
   1436 	}
   1437 	i = 0;
   1438 	if (loc) {
   1439 		while (err == PICL_SUCCESS) {
   1440 			if (parenth == phyplatformh)
   1441 				break;
   1442 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
   1443 			    names[i++], PICL_PROPNAMELEN_MAX);
   1444 			if (err != PICL_SUCCESS) {
   1445 				i--;
   1446 				break;
   1447 			}
   1448 			if (i == PARENT_NAMES)
   1449 				break;
   1450 			err = picl_get_propval_by_name(parenth,
   1451 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
   1452 		}
   1453 		loc[0] = '\0';
   1454 		if (--i > -1) {
   1455 			(void) strlcat(loc, names[i],
   1456 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
   1457 		}
   1458 		while (--i > -1) {
   1459 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
   1460 			    PARENT_NAMES);
   1461 			(void) strlcat(loc, names[i],
   1462 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
   1463 		}
   1464 		log_printf("%-35s", loc);
   1465 		for (i = 0; i < PARENT_NAMES; i++)
   1466 			free(names[i]);
   1467 		free(loc);
   1468 	} else {
   1469 		log_printf("%-35s", "");
   1470 	}
   1471 
   1472 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
   1473 	    sizeof (label));
   1474 	if (err != PICL_SUCCESS)
   1475 		(void) strlcpy(label, "", sizeof (label));
   1476 	log_printf("%-15s", label);
   1477 
   1478 	log_printf("%-8s", current_val);
   1479 
   1480 	log_printf("\n");
   1481 	return (PICL_WALK_CONTINUE);
   1482 }
   1483 
   1484 static void
   1485 sun4v_env_print_fan_sensors()
   1486 {
   1487 	char *fmt = "%-34s %-14s %-10s\n";
   1488 	/*
   1489 	 * If there isn't any fan sensor node, return now.
   1490 	 */
   1491 	(void) picl_walk_tree_by_class(phyplatformh,
   1492 	    PICL_CLASS_RPM_SENSOR, (void *)PICL_PROP_SPEED,
   1493 	    sun4v_env_print_sensor_callback);
   1494 	if (!class_node_found)
   1495 		return;
   1496 	log_printf("Fan sensors:\n");
   1497 	if (syserrlog == 0) {
   1498 		(void) picl_walk_tree_by_class(phyplatformh,
   1499 		    PICL_CLASS_RPM_SENSOR,
   1500 		    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
   1501 		if (all_status_ok) {
   1502 			log_printf("All fan sensors are OK.\n");
   1503 			return;
   1504 		}
   1505 	}
   1506 	log_printf("-------------------------------------------------"
   1507 	    "-----------\n");
   1508 	log_printf(fmt, "Location", "Sensor", "Status", 0);
   1509 	log_printf("-------------------------------------------------"
   1510 	    "-----------\n");
   1511 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR,
   1512 	    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
   1513 }
   1514 
   1515 static void
   1516 sun4v_env_print_fan_indicators()
   1517 {
   1518 	char *fmt = "%-34s %-14s %-10s\n";
   1519 	(void) picl_walk_tree_by_class(phyplatformh,
   1520 	    PICL_CLASS_RPM_INDICATOR, (void *)PICL_PROP_CONDITION,
   1521 	    sun4v_env_print_indicator_callback);
   1522 	if (!class_node_found)
   1523 		return;
   1524 	log_printf("\nFan indicators:\n");
   1525 	if (syserrlog == 0) {
   1526 		(void) picl_walk_tree_by_class(phyplatformh,
   1527 		    PICL_CLASS_RPM_INDICATOR,
   1528 		    (void *)PICL_PROP_CONDITION,
   1529 		    sun4v_env_print_indicator_callback);
   1530 		if (all_status_ok) {
   1531 			log_printf("All fan indicators are OK.\n");
   1532 			return;
   1533 		}
   1534 	}
   1535 	log_printf("-------------------------------------------------"
   1536 	    "-----------\n");
   1537 	log_printf(fmt, "Location", "Sensor", "Condition", 0);
   1538 	log_printf("-------------------------------------------------"
   1539 	    "-----------\n");
   1540 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR,
   1541 	    (void *)PICL_PROP_CONDITION, sun4v_env_print_indicator_callback);
   1542 }
   1543 
   1544 static void
   1545 sun4v_env_print_temp_sensors()
   1546 {
   1547 	char *fmt = "%-34s %-14s %-10s\n";
   1548 	(void) picl_walk_tree_by_class(phyplatformh,
   1549 	    PICL_CLASS_TEMPERATURE_SENSOR,
   1550 	    (void *)PICL_PROP_TEMPERATURE,
   1551 	    sun4v_env_print_sensor_callback);
   1552 	if (!class_node_found)
   1553 		return;
   1554 
   1555 	log_printf("\nTemperature sensors:\n");
   1556 	if (syserrlog == 0) {
   1557 		(void) picl_walk_tree_by_class(phyplatformh,
   1558 		    PICL_CLASS_TEMPERATURE_SENSOR,
   1559 		    PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
   1560 		if (all_status_ok) {
   1561 			log_printf("All temperature sensors are OK.\n");
   1562 			return;
   1563 		}
   1564 	}
   1565 	log_printf("-------------------------------------------------"
   1566 	    "-----------\n");
   1567 	log_printf(fmt, "Location", "Sensor", "Status", 0);
   1568 	log_printf("-------------------------------------------------"
   1569 	    "-----------\n");
   1570 	(void) picl_walk_tree_by_class(phyplatformh,
   1571 	    PICL_CLASS_TEMPERATURE_SENSOR,
   1572 	    (void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
   1573 }
   1574 
   1575 static void
   1576 sun4v_env_print_temp_indicators()
   1577 {
   1578 	char *fmt = "%-34s %-14s %-8s\n";
   1579 	(void) picl_walk_tree_by_class(phyplatformh,
   1580 	    PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION,
   1581 	    sun4v_env_print_indicator_callback);
   1582 	if (!class_node_found)
   1583 		return;
   1584 	log_printf("\nTemperature indicators:\n");
   1585 	if (syserrlog == 0) {
   1586 		(void) picl_walk_tree_by_class(phyplatformh,
   1587 		    PICL_CLASS_TEMPERATURE_INDICATOR,
   1588 		    (void *)PICL_PROP_CONDITION,
   1589 		    sun4v_env_print_indicator_callback);
   1590 		if (all_status_ok) {
   1591 			log_printf("All temperature indicators are OK.\n");
   1592 			return;
   1593 		}
   1594 	}
   1595 	log_printf("-------------------------------------------------"
   1596 	    "-----------\n");
   1597 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
   1598 	log_printf("-------------------------------------------------"
   1599 	    "-----------\n");
   1600 	(void) picl_walk_tree_by_class(phyplatformh,
   1601 	    PICL_CLASS_TEMPERATURE_INDICATOR,
   1602 	    (void *)PICL_PROP_CONDITION,
   1603 	    sun4v_env_print_indicator_callback);
   1604 }
   1605 
   1606 static void
   1607 sun4v_env_print_current_sensors()
   1608 {
   1609 	char *fmt = "%-34s %-14s %-10s\n";
   1610 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR,
   1611 	    (void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
   1612 	if (!class_node_found)
   1613 		return;
   1614 	log_printf("\nCurrent sensors:\n");
   1615 	if (syserrlog == 0) {
   1616 		(void) picl_walk_tree_by_class(phyplatformh,
   1617 		    PICL_CLASS_CURRENT_SENSOR,
   1618 		    PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
   1619 		if (all_status_ok) {
   1620 			log_printf("All current sensors are OK.\n");
   1621 			return;
   1622 		}
   1623 	}
   1624 	log_printf("-------------------------------------------------"
   1625 	    "-----------\n");
   1626 	log_printf(fmt, "Location", "Sensor", "Status", 0);
   1627 	log_printf("-------------------------------------------------"
   1628 	    "-----------\n");
   1629 	(void) picl_walk_tree_by_class(phyplatformh,
   1630 	    PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT,
   1631 	    sun4v_env_print_sensor_callback);
   1632 }
   1633 
   1634 static void
   1635 sun4v_env_print_current_indicators()
   1636 {
   1637 	char *fmt = "%-34s %-14s %-8s\n";
   1638 	(void) picl_walk_tree_by_class(phyplatformh,
   1639 	    PICL_CLASS_CURRENT_INDICATOR,
   1640 	    (void *)PICL_PROP_CONDITION,
   1641 	    sun4v_env_print_indicator_callback);
   1642 	if (!class_node_found)
   1643 		return;
   1644 	log_printf("\nCurrent indicators:\n");
   1645 	if (syserrlog == 0) {
   1646 		(void) picl_walk_tree_by_class(phyplatformh,
   1647 		    PICL_CLASS_CURRENT_INDICATOR, (void *)PICL_PROP_CONDITION,
   1648 		    sun4v_env_print_indicator_callback);
   1649 		if (all_status_ok) {
   1650 			log_printf("All current indicators are OK.\n");
   1651 			return;
   1652 		}
   1653 	}
   1654 	log_printf("-------------------------------------------------"
   1655 	    "-----------\n");
   1656 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
   1657 	log_printf("-------------------------------------------------"
   1658 	    "-----------\n");
   1659 	(void) picl_walk_tree_by_class(phyplatformh,
   1660 	    PICL_CLASS_CURRENT_INDICATOR,
   1661 	    (void *)PICL_PROP_CONDITION,
   1662 	    sun4v_env_print_indicator_callback);
   1663 }
   1664 
   1665 static void
   1666 sun4v_env_print_voltage_sensors()
   1667 {
   1668 	char *fmt = "%-34s %-14s %-10s\n";
   1669 	(void) picl_walk_tree_by_class(phyplatformh,
   1670 	    PICL_CLASS_VOLTAGE_SENSOR,
   1671 	    PICL_PROP_VOLTAGE,
   1672 	    sun4v_env_print_sensor_callback);
   1673 	if (!class_node_found)
   1674 		return;
   1675 	log_printf("\nVoltage sensors:\n");
   1676 	if (syserrlog == 0) {
   1677 		(void) picl_walk_tree_by_class(phyplatformh,
   1678 		    PICL_CLASS_VOLTAGE_SENSOR,
   1679 		    PICL_PROP_VOLTAGE, sun4v_env_print_sensor_callback);
   1680 		if (all_status_ok) {
   1681 			log_printf("All voltage sensors are OK.\n");
   1682 			return;
   1683 		}
   1684 	}
   1685 	log_printf("-------------------------------------------------"
   1686 	    "-----------\n");
   1687 	log_printf(fmt, "Location", "Sensor", "Status", 0);
   1688 	log_printf("-------------------------------------------------"
   1689 	    "-----------\n");
   1690 	(void) picl_walk_tree_by_class(phyplatformh,
   1691 	    PICL_CLASS_VOLTAGE_SENSOR,
   1692 	    (void *)PICL_PROP_VOLTAGE,
   1693 	    sun4v_env_print_sensor_callback);
   1694 }
   1695 
   1696 static void
   1697 sun4v_env_print_voltage_indicators()
   1698 {
   1699 	char *fmt = "%-34s %-14s %-8s\n";
   1700 	(void) picl_walk_tree_by_class(phyplatformh,
   1701 	    PICL_CLASS_VOLTAGE_INDICATOR,
   1702 	    (void *)PICL_PROP_CONDITION,
   1703 	    sun4v_env_print_indicator_callback);
   1704 	if (!class_node_found)
   1705 		return;
   1706 	log_printf("\nVoltage indicators:\n");
   1707 	if (syserrlog == 0) {
   1708 		(void) picl_walk_tree_by_class(phyplatformh,
   1709 		    PICL_CLASS_VOLTAGE_INDICATOR, (void *)PICL_PROP_CONDITION,
   1710 		    sun4v_env_print_indicator_callback);
   1711 		if (all_status_ok) {
   1712 			log_printf("All voltage indicators are OK.\n");
   1713 			return;
   1714 		}
   1715 	}
   1716 	log_printf("-------------------------------------------------"
   1717 	    "-----------\n");
   1718 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
   1719 	log_printf("-------------------------------------------------"
   1720 	    "-----------\n");
   1721 	(void) picl_walk_tree_by_class(phyplatformh,
   1722 	    PICL_CLASS_VOLTAGE_INDICATOR,
   1723 	    (void *)PICL_PROP_CONDITION,
   1724 	    sun4v_env_print_indicator_callback);
   1725 }
   1726 
   1727 static void
   1728 sun4v_env_print_LEDs()
   1729 {
   1730 	char *fmt = "%-34s %-14s %-8s\n";
   1731 	if (syserrlog == 0)
   1732 		return;
   1733 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
   1734 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
   1735 	if (!class_node_found)
   1736 		return;
   1737 	log_printf("\nLEDs:\n");
   1738 	log_printf("-------------------------------------------------"
   1739 	    "-----------\n");
   1740 	log_printf(fmt, "Location", "LED", "State", 0);
   1741 	log_printf("-------------------------------------------------"
   1742 	    "-----------\n");
   1743 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
   1744 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
   1745 }
   1746 
   1747 /*ARGSUSED*/
   1748 static int
   1749 sun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args)
   1750 {
   1751 	char label[PICL_PROPNAMELEN_MAX];
   1752 	char status[PICL_PROPNAMELEN_MAX];
   1753 	picl_errno_t err;
   1754 	picl_prophdl_t proph;
   1755 	picl_nodehdl_t parenth;
   1756 	char *names[PARENT_NAMES];
   1757 	char *loc;
   1758 	int i;
   1759 
   1760 	if (!class_node_found) {
   1761 		class_node_found = 1;
   1762 		return (PICL_WALK_TERMINATE);
   1763 	}
   1764 	err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph);
   1765 	if (err != PICL_SUCCESS)
   1766 		return (PICL_WALK_CONTINUE);
   1767 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
   1768 	    sizeof (label));
   1769 	if (err != PICL_SUCCESS)
   1770 		return (PICL_WALK_CONTINUE);
   1771 	err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
   1772 	    status, sizeof (status));
   1773 	if (err != PICL_SUCCESS)
   1774 		return (PICL_WALK_CONTINUE);
   1775 	if (syserrlog == 0) {
   1776 		if (strcmp(status, "disabled") == 0) {
   1777 			if (all_status_ok) {
   1778 				all_status_ok = 0;
   1779 				return (PICL_WALK_TERMINATE);
   1780 			}
   1781 		} else
   1782 			return (PICL_WALK_CONTINUE);
   1783 	}
   1784 
   1785 	if (is_fru_absent(nodeh))
   1786 		strcpy(status, "Not present");
   1787 
   1788 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
   1789 	    sizeof (parenth));
   1790 	if (err != PICL_SUCCESS) {
   1791 		log_printf("\n");
   1792 		return (PICL_WALK_CONTINUE);
   1793 	}
   1794 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
   1795 		return (PICL_WALK_TERMINATE);
   1796 	for (i = 0; i < PARENT_NAMES; i++)
   1797 		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
   1798 			while (--i > -1)
   1799 				free(names[i]);
   1800 			free(loc);
   1801 			return (PICL_WALK_TERMINATE);
   1802 		}
   1803 	i = 0;
   1804 	while (err == PICL_SUCCESS) {
   1805 		if (parenth == phyplatformh)
   1806 			break;
   1807 		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
   1808 		    names[i++], PICL_PROPNAMELEN_MAX);
   1809 		if (err != PICL_SUCCESS) {
   1810 			i--;
   1811 			break;
   1812 		}
   1813 		if (i == PARENT_NAMES)
   1814 			break;
   1815 		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
   1816 		    &parenth, sizeof (parenth));
   1817 	}
   1818 	loc[0] = '\0';
   1819 	if (--i > -1) {
   1820 		(void) strlcat(loc, names[i],
   1821 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
   1822 	}
   1823 	while (--i > -1) {
   1824 		(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * PARENT_NAMES);
   1825 		(void) strlcat(loc, names[i],
   1826 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
   1827 	}
   1828 	log_printf("%-35s", loc);
   1829 	for (i = 0; i < PARENT_NAMES; i++)
   1830 		free(names[i]);
   1831 	free(loc);
   1832 	log_printf("%-10s", label);
   1833 	log_printf("%-9s", status);
   1834 	log_printf("\n");
   1835 	return (PICL_WALK_CONTINUE);
   1836 }
   1837 
   1838 static void
   1839 sun4v_print_fru_status()
   1840 {
   1841 	char *fmt = "%-34s %-9s %-8s\n";
   1842 
   1843 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
   1844 	    sun4v_print_fru_status_callback);
   1845 	if (!class_node_found)
   1846 		return;
   1847 
   1848 	log_printf("\n");
   1849 	log_printf("============================");
   1850 	log_printf(" FRU Status ");
   1851 	log_printf("============================");
   1852 	log_printf("\n");
   1853 
   1854 	if (syserrlog == 0) {
   1855 		(void) picl_walk_tree_by_class(phyplatformh,
   1856 		    NULL, NULL,
   1857 		    sun4v_print_fru_status_callback);
   1858 		if (all_status_ok) {
   1859 			log_printf("All FRUs are enabled.\n");
   1860 			return;
   1861 		}
   1862 	}
   1863 	log_printf(fmt, "Location", "Name", "Status", 0);
   1864 	log_printf("------------------------------------------------------\n");
   1865 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
   1866 	    sun4v_print_fru_status_callback);
   1867 }
   1868 
   1869 /*  Check the children of the FRU node for a presence indicator */
   1870 static int
   1871 is_fru_absent(picl_nodehdl_t fruh)
   1872 {
   1873 	char class [PICL_CLASSNAMELEN_MAX];
   1874 	char condition [PICL_PROPNAMELEN_MAX];
   1875 	picl_errno_t err;
   1876 	picl_nodehdl_t nodeh;
   1877 
   1878 	err = picl_get_propval_by_name(fruh, PICL_PROP_CHILD, &nodeh,
   1879 	    sizeof (picl_nodehdl_t));
   1880 	while (err == PICL_SUCCESS) {
   1881 		err = picl_get_propval_by_name(nodeh,
   1882 		    PICL_PROP_CLASSNAME, class, sizeof (class));
   1883 		if (err == PICL_SUCCESS &&
   1884 		    strcmp(class, "presence-indicator") == 0) {
   1885 			err = picl_get_propval_by_name(nodeh,
   1886 			    PICL_PROP_CONDITION, condition,
   1887 			    sizeof (condition));
   1888 			if (err == PICL_SUCCESS) {
   1889 				if (strcmp(condition, "Absent") == 0) {
   1890 					return (1);
   1891 				} else	{
   1892 					return (0);
   1893 				}
   1894 			}
   1895 		}
   1896 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
   1897 		    &nodeh, sizeof (picl_nodehdl_t));
   1898 	}
   1899 	return (0);
   1900 }
   1901 
   1902 /*ARGSUSED*/
   1903 static int
   1904 sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args)
   1905 {
   1906 	char rev[PICL_PROPNAMELEN_MAX];
   1907 	picl_errno_t err;
   1908 
   1909 	if (!class_node_found) {
   1910 		class_node_found = 1;
   1911 		return (PICL_WALK_TERMINATE);
   1912 	}
   1913 
   1914 	err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev,
   1915 	    sizeof (rev));
   1916 	if (err != PICL_SUCCESS)
   1917 		return (PICL_WALK_CONTINUE);
   1918 	if (strlen(rev) == 0)
   1919 		return (PICL_WALK_CONTINUE);
   1920 	log_printf("%s", rev);
   1921 	log_printf("\n");
   1922 	return (PICL_WALK_CONTINUE);
   1923 }
   1924 
   1925 static void
   1926 sun4v_print_fw_rev()
   1927 {
   1928 	if (syserrlog == 0)
   1929 		return;
   1930 
   1931 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
   1932 	    sun4v_print_fw_rev_callback);
   1933 	if (!class_node_found)
   1934 		return;
   1935 
   1936 	log_printf("\n");
   1937 	log_printf("============================");
   1938 	log_printf(" FW Version ");
   1939 	log_printf("============================");
   1940 	log_printf("\n");
   1941 	log_printf("Version\n");
   1942 	log_printf("-------------------------------------------------"
   1943 	    "-----------\n");
   1944 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
   1945 	    sun4v_print_fw_rev_callback);
   1946 }
   1947 
   1948 static void
   1949 sun4v_print_openprom_rev()
   1950 {
   1951 	if (syserrlog == 0)
   1952 		return;
   1953 
   1954 	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
   1955 	    openprom_callback);
   1956 	if (!class_node_found)
   1957 		return;
   1958 
   1959 	log_printf("\n");
   1960 	log_printf("======================");
   1961 	log_printf(" System PROM revisions ");
   1962 	log_printf("=======================");
   1963 	log_printf("\n");
   1964 	log_printf("Version\n");
   1965 	log_printf("-------------------------------------------------"
   1966 	    "-----------\n");
   1967 	(void) picl_walk_tree_by_class(rooth, "openprom", NULL,
   1968 	    openprom_callback);
   1969 }
   1970 
   1971 /*
   1972  * display the OBP and POST prom revisions (if present)
   1973  */
   1974 /* ARGSUSED */
   1975 static int
   1976 openprom_callback(picl_nodehdl_t openpromh, void *arg)
   1977 {
   1978 	picl_prophdl_t	proph;
   1979 	picl_prophdl_t	tblh;
   1980 	picl_prophdl_t	rowproph;
   1981 	picl_propinfo_t	pinfo;
   1982 	char		*prom_version = NULL;
   1983 	char		*obp_version = NULL;
   1984 	int		err;
   1985 
   1986 	if (!class_node_found) {
   1987 		class_node_found = 1;
   1988 		return (PICL_WALK_TERMINATE);
   1989 	}
   1990 
   1991 	err = picl_get_propinfo_by_name(openpromh, OBP_PROP_VERSION,
   1992 	    &pinfo, &proph);
   1993 	if (err == PICL_PROPNOTFOUND)
   1994 		return (PICL_WALK_TERMINATE);
   1995 	else if (err != PICL_SUCCESS)
   1996 		return (err);
   1997 
   1998 	/*
   1999 	 * If it's a table prop, the first element is OBP revision
   2000 	 * The second one is POST revision.
   2001 	 * If it's a charstring prop, the value will be only OBP revision
   2002 	 */
   2003 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
   2004 		prom_version = (char *)alloca(pinfo.size);
   2005 		if (prom_version == NULL)
   2006 			return (PICL_FAILURE);
   2007 		err = picl_get_propval(proph, prom_version, pinfo.size);
   2008 		if (err != PICL_SUCCESS)
   2009 			return (err);
   2010 		log_printf("%s\n", prom_version);
   2011 	}
   2012 
   2013 	if (pinfo.type != PICL_PTYPE_TABLE)	/* not supported type */
   2014 		return (PICL_WALK_TERMINATE);
   2015 
   2016 	err = picl_get_propval(proph, &tblh, pinfo.size);
   2017 	if (err != PICL_SUCCESS)
   2018 		return (err);
   2019 
   2020 	err = picl_get_next_by_row(tblh, &rowproph);
   2021 	if (err == PICL_SUCCESS) {
   2022 		/* get first row */
   2023 		err = picl_get_propinfo(rowproph, &pinfo);
   2024 		if (err != PICL_SUCCESS)
   2025 			return (err);
   2026 
   2027 		prom_version = (char *)alloca(pinfo.size);
   2028 		if (prom_version == NULL)
   2029 			return (PICL_FAILURE);
   2030 
   2031 		err = picl_get_propval(rowproph, prom_version, pinfo.size);
   2032 		if (err != PICL_SUCCESS)
   2033 			return (err);
   2034 		log_printf("%s\n", prom_version);
   2035 
   2036 		/* get second row */
   2037 		err = picl_get_next_by_col(rowproph, &rowproph);
   2038 		if (err == PICL_SUCCESS) {
   2039 			err = picl_get_propinfo(rowproph, &pinfo);
   2040 			if (err != PICL_SUCCESS)
   2041 				return (err);
   2042 
   2043 			obp_version = (char *)alloca(pinfo.size);
   2044 			if (obp_version == NULL)
   2045 				return (PICL_FAILURE);
   2046 			err = picl_get_propval(rowproph, obp_version,
   2047 			    pinfo.size);
   2048 			if (err != PICL_SUCCESS)
   2049 				return (err);
   2050 			log_printf("%s\n", obp_version);
   2051 		}
   2052 	}
   2053 
   2054 	return (PICL_WALK_TERMINATE);
   2055 }
   2056 
   2057 static void
   2058 sun4v_print_chassis_serial_no()
   2059 {
   2060 	char val[PICL_PROPNAMELEN_MAX];
   2061 	picl_errno_t err;
   2062 	if (syserrlog == 0 || chassish == 0)
   2063 		return;
   2064 
   2065 	log_printf("\n");
   2066 	log_printf("Chassis Serial Number");
   2067 	log_printf("\n");
   2068 	log_printf("---------------------\n");
   2069 	err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER,
   2070 	    val, sizeof (val));
   2071 	if (err == PICL_SUCCESS)
   2072 		log_printf("%s", val);
   2073 	log_printf("\n");
   2074 }
   2075