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