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