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