xref: /titanic_51/usr/src/lib/libprtdiag/common/display_sun4v.c (revision 843e19887f64dde75055cf8842fc4db2171eff45)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <kvm.h>
34 #include <varargs.h>
35 #include <time.h>
36 #include <dirent.h>
37 #include <fcntl.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/utsname.h>
42 #include <sys/openpromio.h>
43 #include <libintl.h>
44 #include <syslog.h>
45 #include <sys/dkio.h>
46 #include <sys/systeminfo.h>
47 #include <picldefs.h>
48 #include <math.h>
49 #include <errno.h>
50 #include "pdevinfo.h"
51 #include "display.h"
52 #include "display_sun4v.h"
53 #include "libprtdiag.h"
54 
55 #if !defined(TEXT_DOMAIN)
56 #define	TEXT_DOMAIN	"SYS_TEST"
57 #endif
58 
59 #define	MOTHERBOARD			"MB"
60 #define	NETWORK				"network"
61 #define	PCIE_COMPATIBLE_STR		"pciex"
62 #define	PCIX_COMPATIBLE_STR		"pci"
63 #define	SUN4V_MACHINE			"sun4v"
64 #define	PARENT_NAMES			10
65 
66 /*
67  * Additional OBP properties
68  */
69 #define	OBP_PROP_COMPATIBLE		"compatible"
70 #define	OBP_PROP_MODEL			"model"
71 #define	OBP_PROP_SLOT_NAMES		"slot-names"
72 
73 #define	PICL_NODE_PHYSICAL_PLATFORM	"physical-platform"
74 #define	PICL_NODE_CHASSIS		"chassis"
75 #define	MEMORY_SIZE_FIELD		11
76 #define	INVALID_THRESHOLD		1000000
77 
78 /*
79  * Additional picl classes
80  */
81 #ifndef	PICL_CLASS_SUN4V
82 #define	PICL_CLASS_SUN4V		"sun4v"
83 #endif
84 
85 #ifndef	PICL_PROP_NAC
86 #define	PICL_PROP_NAC			"nac"
87 #endif
88 
89 extern int sys_clk;
90 extern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *,
91 	picl_nodehdl_t *);
92 
93 static picl_nodehdl_t rooth = 0, phyplatformh = 0;
94 static picl_nodehdl_t chassish = 0;
95 static int class_node_found;
96 static int syserrlog;
97 static int all_status_ok;
98 
99 /* local functions */
100 static int sun4v_get_first_compatible_value(picl_nodehdl_t, char **);
101 static void sun4v_display_memory_conf(picl_nodehdl_t);
102 static void sun4v_disp_env_status();
103 static void sun4v_env_print_fan_sensors();
104 static void sun4v_env_print_fan_indicators();
105 static void sun4v_env_print_temp_sensors();
106 static void sun4v_env_print_temp_indicators();
107 static void sun4v_env_print_current_sensors();
108 static void sun4v_env_print_current_indicators();
109 static void sun4v_env_print_voltage_sensors();
110 static void sun4v_env_print_voltage_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 
116 int
117 sun4v_display(Sys_tree *tree, Prom_node *root, int log,
118 	picl_nodehdl_t plafh)
119 {
120 	void *value;		/* used for opaque PROM data */
121 	struct mem_total memory_total;	/* Total memory in system */
122 	struct grp_info grps;	/* Info on all groups in system */
123 	char machine[MAXSTRLEN];
124 
125 	if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1)
126 		return (1);
127 	if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0)
128 		return (1);
129 
130 	sys_clk = -1;  /* System clock freq. (in MHz) */
131 
132 	/*
133 	 * Now display the machine's configuration. We do this if we
134 	 * are not logging.
135 	 */
136 	if (!logging) {
137 		struct utsname uts_buf;
138 
139 		/*
140 		 * Display system banner
141 		 */
142 		(void) uname(&uts_buf);
143 
144 		log_printf(dgettext(TEXT_DOMAIN, "System Configuration:  "
145 		    "Sun Microsystems  %s %s\n"), uts_buf.machine,
146 		    get_prop_val(find_prop(root, "banner-name")), 0);
147 
148 		/* display system clock frequency */
149 		value = get_prop_val(find_prop(root, "clock-frequency"));
150 		if (value != NULL) {
151 			sys_clk = ((*((int *)value)) + 500000) / 1000000;
152 			log_printf(dgettext(TEXT_DOMAIN, "System clock "
153 			    "frequency: %d MHz\n"), sys_clk, 0);
154 		}
155 
156 		/* Display the Memory Size */
157 		display_memorysize(tree, NULL, &grps, &memory_total);
158 
159 		/* Display the CPU devices */
160 		sun4v_display_cpu_devices(plafh);
161 
162 		/* Display the Memory configuration */
163 		class_node_found = 0;
164 		sun4v_display_memory_conf(plafh);
165 
166 		/* Display all the IO cards. */
167 		(void) sun4v_display_pci(plafh);
168 		sun4v_display_diaginfo((log || (logging)), root, plafh);
169 
170 		if (picl_get_root(&rooth) != PICL_SUCCESS)
171 			return (1);
172 		if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM,
173 		    &phyplatformh) != PICL_SUCCESS)
174 			return (1);
175 
176 		if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME,
177 		    PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS,
178 		    strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS)
179 			return (1);
180 
181 		syserrlog = log;
182 		sun4v_disp_env_status();
183 	}
184 	return (0);
185 }
186 
187 static void
188 get_bus_type(picl_nodehdl_t nodeh, struct io_card *card)
189 {
190 	char *compatible;
191 
192 	(void) strlcpy(card->bus_type, "PCIX", sizeof (card->bus_type));
193 	if (sun4v_get_first_compatible_value(nodeh, &compatible)
194 	    == PICL_SUCCESS) {
195 		if (strncmp(compatible, PCIE_COMPATIBLE_STR,
196 		    strlen(PCIE_COMPATIBLE_STR)) == 0)
197 			(void) strlcpy(card->bus_type, "PCIE",
198 			    sizeof (card->bus_type));
199 		free(compatible);
200 	}
201 }
202 
203 static picl_errno_t
204 get_slot_label(picl_nodehdl_t nodeh, struct io_card *card)
205 {
206 	char val[PICL_PROPNAMELEN_MAX];
207 	picl_errno_t err;
208 
209 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
210 	    sizeof (val));
211 	if (err != PICL_SUCCESS)
212 		return (err);
213 
214 	(void) strlcpy(card->slot_str, val, sizeof (card->slot_str));
215 	card->slot = -1;
216 	return (PICL_SUCCESS);
217 }
218 
219 static void
220 get_slot_number(picl_nodehdl_t nodeh, struct io_card *card)
221 {
222 	picl_errno_t err;
223 	picl_prophdl_t proph;
224 	picl_propinfo_t pinfo;
225 	picl_nodehdl_t pnodeh;
226 	uint8_t *pval;
227 	uint32_t dev_mask;
228 	char uaddr[MAXSTRLEN];
229 	int i;
230 
231 	if (get_slot_label(nodeh, card) == PICL_SUCCESS)
232 		return;
233 	err = PICL_SUCCESS;
234 	while (err == PICL_SUCCESS) {
235 		if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh,
236 		    sizeof (pnodeh)) != PICL_SUCCESS) {
237 			(void) strlcpy(card->slot_str, MOTHERBOARD,
238 			    sizeof (card->slot_str));
239 			card->slot = -1;
240 			return;
241 		}
242 		if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES,
243 		    &pinfo, &proph) == PICL_SUCCESS) {
244 			break;
245 		}
246 		nodeh = pnodeh;
247 	}
248 	if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr,
249 	    sizeof (uaddr)) != PICL_SUCCESS) {
250 		(void) strlcpy(card->slot_str, MOTHERBOARD,
251 		    sizeof (card->slot_str));
252 		card->slot = -1;
253 		return;
254 	}
255 	pval = (uint8_t *)malloc(pinfo.size);
256 	if (!pval) {
257 		(void) strlcpy(card->slot_str, MOTHERBOARD,
258 		    sizeof (card->slot_str));
259 		card->slot = -1;
260 		return;
261 	}
262 	if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) {
263 		(void) strlcpy(card->slot_str, MOTHERBOARD,
264 		    sizeof (card->slot_str));
265 		card->slot = -1;
266 		free(pval);
267 		return;
268 	}
269 
270 	dev_mask = 0;
271 	for (i = 0; i < sizeof (dev_mask); i++)
272 		dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i));
273 	for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) {
274 		if (uaddr[i] == ',') {
275 			uaddr[i] = '\0';
276 			break;
277 		}
278 	}
279 	card->slot = atol(uaddr);
280 	if (((1 << card->slot) & dev_mask) == 0) {
281 		(void) strlcpy(card->slot_str, MOTHERBOARD,
282 		    sizeof (card->slot_str));
283 		card->slot = -1;
284 	} else {
285 		char *p = (char *)(pval+sizeof (dev_mask));
286 		int shift = sizeof (uint32_t)*8-1-card->slot;
287 		uint32_t x = (dev_mask << shift) >> shift;
288 		int count = 0;	/* count # of 1's in x */
289 		int i = 0;
290 		while (x != 0) {
291 			count++;
292 			x &= x-1;
293 		}
294 		while (count > 1) {
295 			while (p[i++] != '\0')
296 				;
297 			count--;
298 		}
299 		(void) strlcpy(card->slot_str, (char *)(p+i),
300 		    sizeof (card->slot_str));
301 	}
302 	free(pval);
303 }
304 
305 /*
306  * add all io devices under pci in io list
307  */
308 /* ARGSUSED */
309 static int
310 sun4v_pci_callback(picl_nodehdl_t pcih, void *args)
311 {
312 	char path[PICL_PROPNAMELEN_MAX];
313 	char class[PICL_CLASSNAMELEN_MAX];
314 	char name[PICL_PROPNAMELEN_MAX];
315 	char model[PICL_PROPNAMELEN_MAX];
316 	char binding_name[PICL_PROPNAMELEN_MAX];
317 	char val[PICL_PROPNAMELEN_MAX];
318 	char *compatible;
319 	picl_errno_t err;
320 	picl_nodehdl_t nodeh;
321 	struct io_card pci_card;
322 
323 	/* Walk through the children */
324 
325 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
326 	    sizeof (picl_nodehdl_t));
327 
328 	while (err == PICL_SUCCESS) {
329 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
330 		    class, sizeof (class));
331 		if (err !=  PICL_SUCCESS)
332 			return (err);
333 
334 		if (args) {
335 			char *val = args;
336 			if (strcmp(class, val) == 0) {
337 				err = picl_get_propval_by_name(nodeh,
338 				    PICL_PROP_PEER, &nodeh,
339 				    sizeof (picl_nodehdl_t));
340 				continue;
341 			} else if (strcmp(val, PICL_CLASS_PCIEX) == 0 &&
342 			    strcmp(class, PICL_CLASS_PCI) == 0) {
343 				err = picl_get_propval_by_name(nodeh,
344 				    PICL_PROP_PEER, &nodeh,
345 				    sizeof (picl_nodehdl_t));
346 				continue;
347 			} else if (strcmp(val, PICL_CLASS_PCI) == 0 &&
348 			    strcmp(class, PICL_CLASS_PCIEX) == 0) {
349 				err = picl_get_propval_by_name(nodeh,
350 				    PICL_PROP_PEER, &nodeh,
351 				    sizeof (picl_nodehdl_t));
352 				continue;
353 			}
354 		}
355 
356 		err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
357 		    path, sizeof (path));
358 		if (err != PICL_SUCCESS)
359 			return (err);
360 
361 		(void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
362 
363 		get_bus_type(nodeh, &pci_card);
364 		get_slot_number(nodeh, &pci_card);
365 
366 		err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name,
367 		    sizeof (name));
368 		if (err == PICL_PROPNOTFOUND)
369 			(void) strlcpy(name, "", sizeof (name));
370 		else if (err != PICL_SUCCESS)
371 			return (err);
372 
373 		err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val,
374 		    sizeof (val));
375 		if (err == PICL_PROPNOTFOUND)
376 			(void) strlcpy(val, "", sizeof (val));
377 		else if (err != PICL_SUCCESS)
378 			return (err);
379 
380 		/* Figure NAC name */
381 		if (pci_card.slot != -1)
382 			(void) snprintf(pci_card.status,
383 			    sizeof (pci_card.status),
384 			    "%s%d", pci_card.slot_str,
385 			    pci_card.slot);
386 		else
387 			(void) snprintf(pci_card.status,
388 			    sizeof (pci_card.status),
389 			    "%s", pci_card.slot_str);
390 
391 		/*
392 		 * Get the name of this card. If binding_name is found,
393 		 * name will be <nodename>-<binding_name>.
394 		 */
395 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
396 		    binding_name, sizeof (binding_name));
397 		if (err == PICL_SUCCESS) {
398 			if (strcmp(name, binding_name) != 0) {
399 				(void) strlcat(name, "-", sizeof (name));
400 				(void) strlcat(name, binding_name,
401 				    sizeof (name));
402 			}
403 		} else if (err == PICL_PROPNOTFOUND) {
404 			/*
405 			 * if compatible prop is not found, name will be
406 			 * <nodename>-<compatible>
407 			 */
408 			err = sun4v_get_first_compatible_value(nodeh,
409 			    &compatible);
410 			if (err == PICL_SUCCESS) {
411 				(void) strlcat(name, "-", sizeof (name));
412 				(void) strlcat(name, compatible,
413 				    sizeof (name));
414 				free(compatible);
415 			}
416 		} else
417 			return (err);
418 
419 		(void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
420 
421 		/* Get the model of this card */
422 
423 		err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
424 		    model, sizeof (model));
425 		if (err == PICL_PROPNOTFOUND)
426 			(void) strlcpy(model, "", sizeof (model));
427 		else if (err != PICL_SUCCESS)
428 			return (err);
429 		(void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
430 
431 		/* Print NAC name */
432 		log_printf("%-18s", pci_card.status);
433 		/* Print IO Type */
434 		log_printf("%-6s", pci_card.bus_type);
435 		/* Printf Card Name */
436 		log_printf("%-44s", pci_card.name);
437 		/* Print Card Model */
438 		log_printf("%-8s", pci_card.model);
439 		log_printf("\n");
440 		/* Print Status */
441 		log_printf("%-18s", val);
442 		/* Print IO Type */
443 		log_printf("%-6s", "");
444 		/* Print Parent Path */
445 		log_printf("%-44s", pci_card.notes);
446 		log_printf("\n");
447 
448 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
449 		    sizeof (picl_nodehdl_t));
450 	}
451 	return (PICL_WALK_CONTINUE);
452 }
453 
454 /*
455  * display_pci
456  * Display all the PCI IO cards on this board.
457  */
458 void
459 sun4v_display_pci(picl_nodehdl_t plafh)
460 {
461 	char *fmt = "%-17s %-5s %-44s %-8s";
462 	/* Have we printed the column headings? */
463 	static int banner = FALSE;
464 
465 	if (banner == FALSE) {
466 		log_printf("\n");
467 		log_printf("================================");
468 		log_printf(" IO Devices ");
469 		log_printf("================================");
470 		log_printf("\n");
471 		log_printf(fmt, "Slot +", "Bus", "Name +", "Model", 0);
472 		log_printf("\n");
473 		log_printf(fmt, "Status", "Type", "Path", "", 0);
474 		log_printf("\n");
475 		log_printf("---------------------------------"
476 		    "-------------------------------------------\n");
477 		banner = TRUE;
478 	}
479 
480 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
481 	    PICL_CLASS_PCIEX, sun4v_pci_callback);
482 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
483 	    PICL_CLASS_PCI, sun4v_pci_callback);
484 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V,
485 	    PICL_CLASS_SUN4V, sun4v_pci_callback);
486 }
487 
488 /*
489  * return the first compatible value
490  */
491 static int
492 sun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
493 {
494 	picl_errno_t err;
495 	picl_prophdl_t proph;
496 	picl_propinfo_t pinfo;
497 	picl_prophdl_t tblh;
498 	picl_prophdl_t rowproph;
499 	char *pval;
500 
501 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
502 	    &pinfo, &proph);
503 	if (err != PICL_SUCCESS)
504 		return (err);
505 
506 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
507 		pval = malloc(pinfo.size);
508 		if (pval == NULL)
509 			return (PICL_FAILURE);
510 		err = picl_get_propval(proph, pval, pinfo.size);
511 		if (err != PICL_SUCCESS) {
512 			free(pval);
513 			return (err);
514 		}
515 		*outbuf = pval;
516 		return (PICL_SUCCESS);
517 	}
518 
519 	if (pinfo.type != PICL_PTYPE_TABLE)
520 		return (PICL_FAILURE);
521 
522 	/* get first string from table */
523 	err = picl_get_propval(proph, &tblh, pinfo.size);
524 	if (err != PICL_SUCCESS)
525 		return (err);
526 
527 	err = picl_get_next_by_row(tblh, &rowproph);
528 	if (err != PICL_SUCCESS)
529 		return (err);
530 
531 	err = picl_get_propinfo(rowproph, &pinfo);
532 	if (err != PICL_SUCCESS)
533 		return (err);
534 
535 	pval = malloc(pinfo.size);
536 	if (pval == NULL)
537 		return (PICL_FAILURE);
538 
539 	err = picl_get_propval(rowproph, pval, pinfo.size);
540 	if (err != PICL_SUCCESS) {
541 		free(pval);
542 		return (err);
543 	}
544 
545 	*outbuf = pval;
546 	return (PICL_SUCCESS);
547 }
548 
549 /*
550  * print size of a memory segment
551  */
552 static void
553 print_memory_segment_size(uint64_t size)
554 {
555 	uint64_t kbyte = 1024;
556 	uint64_t mbyte = kbyte * kbyte;
557 	uint64_t gbyte = kbyte * mbyte;
558 	char buf[MEMORY_SIZE_FIELD];
559 
560 	if (size >= gbyte) {
561 		if (size % gbyte == 0)
562 			(void) snprintf(buf, sizeof (buf), "%d GB",
563 			    (int)(size / gbyte));
564 		else
565 			(void) snprintf(buf, sizeof (buf), "%.2f GB",
566 			    (float)size / gbyte);
567 	} else if (size >= mbyte) {
568 		if (size % mbyte == 0)
569 			(void) snprintf(buf, sizeof (buf), "%d MB",
570 			    (int)(size / mbyte));
571 		else
572 			(void) snprintf(buf, sizeof (buf), "%.2f MB",
573 			    (float)size / mbyte);
574 	} else {
575 		if (size % kbyte == 0)
576 			(void) snprintf(buf, sizeof (buf), "%d KB",
577 			    (int)(size / kbyte));
578 		else
579 			(void) snprintf(buf, sizeof (buf), "%.2f KB",
580 			    (float)size / kbyte);
581 	}
582 	log_printf("%-7s ", buf);
583 }
584 
585 /*
586  * Enumerate banks and dimms within a memory segment.  We're handed
587  * the first bank within the segment - we assume there are dimms
588  * (memory-module) nodes underneath.
589  */
590 static void
591 print_memory_segment_contain(picl_nodehdl_t bank_nodeh)
592 {
593 	char val[PICL_PROPNAMELEN_MAX];
594 	picl_nodehdl_t module_nodeh;
595 	int flag = 0;
596 
597 	do {
598 		if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_CHILD,
599 		    &module_nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
600 			continue;
601 		do {
602 			if (picl_get_propval_by_name(module_nodeh,
603 			    PICL_PROP_NAC, val, sizeof (val)) !=
604 			    PICL_SUCCESS)
605 				continue;
606 			else {
607 				if (!flag) {
608 					log_printf("%-30s\n", val);
609 					flag = 1;
610 				} else
611 					log_printf("%57s\n", val);
612 			}
613 		} while (picl_get_propval_by_name(module_nodeh, PICL_PROP_PEER,
614 		    &module_nodeh, sizeof (picl_nodehdl_t)) ==
615 		    PICL_SUCCESS);
616 	} while (picl_get_propval_by_name(bank_nodeh, PICL_PROP_PEER,
617 	    &bank_nodeh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS);
618 }
619 
620 /*
621  * Search node where _class=="memory-segment"
622  * print "Base Address", "Size", etc
623  */
624 /*ARGSUSED*/
625 static int
626 sun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args)
627 {
628 	uint64_t base;
629 	uint64_t size;
630 	uint64_t ifactor;
631 	picl_errno_t err = PICL_SUCCESS;
632 
633 	if (class_node_found == 0) {
634 		class_node_found = 1;
635 		return (PICL_WALK_TERMINATE);
636 	}
637 	while (err == PICL_SUCCESS) {
638 		err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS,
639 		    &base, sizeof (base));
640 		if (err !=  PICL_SUCCESS)
641 			break;
642 		err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE,
643 		    &size, sizeof (size));
644 		if (err !=  PICL_SUCCESS)
645 			break;
646 		err = picl_get_propval_by_name(nodeh,
647 		    PICL_PROP_INTERLEAVE_FACTOR, &ifactor,
648 		    sizeof (ifactor));
649 		if (err !=  PICL_SUCCESS)
650 			break;
651 		log_printf("%-13llx", base);
652 		print_memory_segment_size(size);
653 		log_printf("%-18lld", ifactor);
654 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
655 		    &nodeh, sizeof (nodeh));
656 		if (err ==  PICL_SUCCESS)
657 			print_memory_segment_contain(nodeh);
658 		log_printf("\n");
659 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
660 		    sizeof (picl_nodehdl_t));
661 	}
662 
663 	return (PICL_WALK_CONTINUE);
664 }
665 
666 /*ARGSUSED*/
667 void
668 sun4v_display_memory_conf(picl_nodehdl_t plafh)
669 {
670 	char *fmt = "%-12s %-7s %-9s %-20s";
671 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
672 	    NULL, sun4v_memory_conf_callback);
673 	if (class_node_found == 0)
674 		return;
675 	log_printf("\n");
676 	log_printf("============================");
677 	log_printf(" Memory Configuration ");
678 	log_printf("============================");
679 	log_printf("\n");
680 	log_printf("Segment Table:\n");
681 	log_printf(
682 	    "---------------------------------------------------------\n");
683 	log_printf(fmt, "Base Address", "Size", "Interleave Factor",
684 	    "Contains", 0);
685 	log_printf("\n");
686 	log_printf(
687 	    "---------------------------------------------------------\n");
688 	(void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
689 	    NULL, sun4v_memory_conf_callback);
690 }
691 
692 void
693 sun4v_display_cpu_devices(picl_nodehdl_t plafh)
694 {
695 	char *fmt = "%-12s %-5s %-8s %-19s %-5s";
696 
697 	/*
698 	 * Display the table header for CPUs . Then display the CPU
699 	 * frequency, cache size, and processor revision of all cpus.
700 	 */
701 	log_printf(dgettext(TEXT_DOMAIN,
702 	    "\n"
703 	    "========================="
704 	    " CPUs "
705 	    "==============================================="
706 	    "\n"
707 	    "\n"));
708 	log_printf(fmt, "", "", "", "CPU", "CPU", 0);
709 	log_printf("\n");
710 	log_printf(fmt, "Location", "CPU", "Freq",
711 	    "Implementation", "State", 0);
712 	log_printf("\n");
713 	log_printf(fmt, "------------", "-----", "--------",
714 	    "-------------------", "-----", 0);
715 	log_printf("\n");
716 
717 	(void) picl_walk_tree_by_class(plafh, "cpu", "cpu", sun4v_display_cpus);
718 }
719 
720 /*
721  * Display the CPUs present on this board.
722  */
723 /*ARGSUSED*/
724 int
725 sun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
726 {
727 	int status;
728 	picl_prophdl_t proph;
729 	picl_prophdl_t tblh;
730 	picl_prophdl_t rowproph;
731 	picl_propinfo_t propinfo;
732 	int *int_value;
733 	int cpuid;
734 	char *comp_value;
735 	char *no_prop_value = "   ";
736 	char freq_str[MAXSTRLEN];
737 	char fru_name[MAXSTRLEN];
738 	char state[MAXSTRLEN];
739 
740 	/*
741 	 * Get cpuid property and print it and the NAC name
742 	 */
743 	status = picl_get_propinfo_by_name(cpuh, "cpuid", &propinfo, &proph);
744 	if (status == PICL_SUCCESS) {
745 		status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
746 		if (status != PICL_SUCCESS) {
747 			log_printf("%-13s", no_prop_value);
748 			log_printf("%-6s", no_prop_value);
749 		} else {
750 			(void) snprintf(fru_name, sizeof (fru_name), "%s%d",
751 			    CPU_STRAND_NAC, cpuid);
752 			log_printf("%-13s", fru_name);
753 			log_printf("%-6d", cpuid);
754 		}
755 	} else {
756 		log_printf("%-13s", no_prop_value);
757 		log_printf("%-6s", no_prop_value);
758 	}
759 
760 clock_freq:
761 	status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
762 	    &proph);
763 	if (status == PICL_SUCCESS) {
764 		int_value = malloc(propinfo.size);
765 		if (int_value == NULL) {
766 			log_printf("%-9s", no_prop_value);
767 			goto compatible;
768 		}
769 		status = picl_get_propval(proph, int_value, propinfo.size);
770 		if (status != PICL_SUCCESS) {
771 			log_printf("%-9s", no_prop_value);
772 		} else {
773 			/* Running frequency */
774 			(void) snprintf(freq_str, sizeof (freq_str), "%d MHz",
775 			    CLK_FREQ_TO_MHZ(*int_value));
776 			log_printf("%-9s", freq_str);
777 		}
778 		free(int_value);
779 	} else
780 		log_printf("%-9s", no_prop_value);
781 
782 compatible:
783 	status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
784 	    &proph);
785 	if (status == PICL_SUCCESS) {
786 		if (propinfo.type == PICL_PTYPE_CHARSTRING) {
787 			/*
788 			 * Compatible Property only has 1 value
789 			 */
790 			comp_value = malloc(propinfo.size);
791 			if (comp_value == NULL) {
792 				log_printf("%-20s", no_prop_value, 0);
793 				goto state;
794 			}
795 			status = picl_get_propval(proph, comp_value,
796 			    propinfo.size);
797 			if (status != PICL_SUCCESS)
798 				log_printf("%-20s", no_prop_value, 0);
799 			else
800 				log_printf("%-20s", comp_value, 0);
801 			free(comp_value);
802 		} else if (propinfo.type == PICL_PTYPE_TABLE) {
803 			/*
804 			 * Compatible Property has multiple values
805 			 */
806 			status = picl_get_propval(proph, &tblh, propinfo.size);
807 			if (status != PICL_SUCCESS) {
808 				log_printf("%-20s", no_prop_value, 0);
809 				goto state;
810 			}
811 			status = picl_get_next_by_row(tblh, &rowproph);
812 			if (status != PICL_SUCCESS) {
813 				log_printf("%-20s", no_prop_value, 0);
814 				goto state;
815 			}
816 
817 			status = picl_get_propinfo(rowproph, &propinfo);
818 			if (status != PICL_SUCCESS) {
819 				log_printf("%-20s", no_prop_value, 0);
820 				goto state;
821 			}
822 
823 			comp_value = malloc(propinfo.size);
824 			if (comp_value == NULL) {
825 				log_printf("%-20s", no_prop_value, 0);
826 				goto state;
827 			}
828 			status = picl_get_propval(rowproph, comp_value,
829 			    propinfo.size);
830 			if (status != PICL_SUCCESS)
831 				log_printf("%-20s", no_prop_value, 0);
832 			else
833 				log_printf("%-20s", comp_value, 0);
834 			free(comp_value);
835 		}
836 	} else
837 		log_printf("%-20s", no_prop_value, 0);
838 
839 state:
840 	status = picl_get_propinfo_by_name(cpuh, PICL_PROP_STATE,
841 	    &propinfo, &proph);
842 	if (status == PICL_SUCCESS) {
843 		status = picl_get_propval(proph, state, sizeof (state));
844 		if (status != PICL_SUCCESS) {
845 			log_printf("%-9s", no_prop_value);
846 		} else {
847 			log_printf("%-9s", state);
848 		}
849 	} else
850 		log_printf("%-9s", no_prop_value);
851 
852 done:
853 	log_printf("\n");
854 	return (PICL_WALK_CONTINUE);
855 }
856 
857 void
858 sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
859 {
860 #ifdef	lint
861 	flag = flag;
862 	root = root;
863 	plafh = plafh;
864 #endif
865 	/*
866 	 * This function is intentionally empty
867 	 */
868 }
869 
870 void
871 display_boardnum(int num)
872 {
873 	log_printf("%2d   ", num, 0);
874 }
875 
876 static void
877 sun4v_disp_env_status()
878 {
879 	if (phyplatformh == 0)
880 		return;
881 	log_printf("\n");
882 	log_printf("============================");
883 	log_printf(" Environmental Status ");
884 	log_printf("============================");
885 	log_printf("\n");
886 
887 	class_node_found = 0;
888 	all_status_ok = 1;
889 	sun4v_env_print_fan_sensors();
890 
891 	class_node_found = 0;
892 	all_status_ok = 1;
893 	sun4v_env_print_fan_indicators();
894 
895 	class_node_found = 0;
896 	all_status_ok = 1;
897 	sun4v_env_print_temp_sensors();
898 
899 	class_node_found = 0;
900 	all_status_ok = 1;
901 	sun4v_env_print_temp_indicators();
902 
903 	class_node_found = 0;
904 	all_status_ok = 1;
905 	sun4v_env_print_current_sensors();
906 
907 	class_node_found = 0;
908 	all_status_ok = 1;
909 	sun4v_env_print_current_indicators();
910 
911 	class_node_found = 0;
912 	all_status_ok = 1;
913 	sun4v_env_print_voltage_sensors();
914 
915 	class_node_found = 0;
916 	all_status_ok = 1;
917 	sun4v_env_print_voltage_indicators();
918 
919 	class_node_found = 0;
920 	sun4v_env_print_LEDs();
921 
922 	class_node_found = 0;
923 	all_status_ok = 1;
924 	sun4v_print_fru_status();
925 
926 	class_node_found = 0;
927 	sun4v_print_fw_rev();
928 
929 	sun4v_print_chassis_serial_no();
930 }
931 
932 /*ARGSUSED*/
933 static int
934 sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args)
935 {
936 	char val[PICL_PROPNAMELEN_MAX];
937 	picl_nodehdl_t parenth;
938 	char *names[PARENT_NAMES];
939 	char *base_units[PICL_PROPNAMELEN_MAX];
940 	char *loc;
941 	int i;
942 	char *prop;
943 	picl_errno_t err;
944 	int32_t lo_warning, lo_shutdown;
945 	int32_t hi_warning, hi_shutdown;
946 	int32_t current_val;
947 	int32_t exponent;
948 	double display_val;
949 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
950 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
951 	sensor_status_t sensor_status = SENSOR_OK;
952 
953 	if (class_node_found == 0) {
954 		class_node_found = 1;
955 		return (PICL_WALK_TERMINATE);
956 	}
957 
958 	prop = (char *)args;
959 	if (!prop) {
960 		sensor_status = SENSOR_UNKNOWN;
961 		all_status_ok = 0;
962 	} else {
963 		err = picl_get_propval_by_name(nodeh,
964 		    PICL_PROP_OPERATIONAL_STATUS, val,
965 		    sizeof (val));
966 		if (err == PICL_SUCCESS) {
967 			if (strcmp(val, "disabled") == 0) {
968 				sensor_status = SENSOR_DISABLED;
969 			}
970 		}
971 	}
972 
973 	if (sensor_status != SENSOR_DISABLED &&
974 	    sensor_status != SENSOR_UNKNOWN) {
975 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
976 		    sizeof (current_val)) != PICL_SUCCESS) {
977 			sensor_status = SENSOR_UNKNOWN;
978 		}
979 		if (picl_get_propval_by_name(nodeh, PICL_PROP_LOW_WARNING,
980 		    &lo_warning, sizeof (lo_warning)) != PICL_SUCCESS)
981 			lo_warning = INVALID_THRESHOLD;
982 		if (picl_get_propval_by_name(nodeh, PICL_PROP_LOW_SHUTDOWN,
983 		    &lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS)
984 			lo_shutdown = INVALID_THRESHOLD;
985 		if (picl_get_propval_by_name(nodeh, PICL_PROP_HIGH_WARNING,
986 		    &hi_warning, sizeof (hi_warning)) != PICL_SUCCESS)
987 			hi_warning = INVALID_THRESHOLD;
988 		if (picl_get_propval_by_name(nodeh, PICL_PROP_HIGH_SHUTDOWN,
989 		    &hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS)
990 			hi_shutdown = INVALID_THRESHOLD;
991 
992 		if ((lo_shutdown != INVALID_THRESHOLD &&
993 		    current_val <= lo_shutdown) ||
994 		    (hi_shutdown != INVALID_THRESHOLD &&
995 		    current_val >= hi_shutdown)) {
996 			sensor_status = SENSOR_FAILED;
997 		} else if ((lo_warning != INVALID_THRESHOLD &&
998 		    current_val <= lo_warning) ||
999 		    (hi_warning != INVALID_THRESHOLD &&
1000 		    current_val >= hi_warning)) {
1001 			sensor_status = SENSOR_WARN;
1002 		} else {
1003 			sensor_status = SENSOR_OK;
1004 		}
1005 	}
1006 
1007 	if (syserrlog == 0) {
1008 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
1009 			all_status_ok = 0;
1010 			return (PICL_WALK_TERMINATE);
1011 		}
1012 		if (sensor_status == SENSOR_OK) {
1013 			return (PICL_WALK_CONTINUE);
1014 		}
1015 	}
1016 
1017 	/*
1018 	 * If we're here then prtdiag was invoked with "-v" or we have
1019 	 * a sensor that is beyond a threshold, so give them a book to
1020 	 * read instead of the Cliff Notes.
1021 	 */
1022 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1023 	    sizeof (parenth));
1024 	if (err != PICL_SUCCESS) {
1025 		log_printf("\n");
1026 		return (PICL_WALK_CONTINUE);
1027 	}
1028 
1029 	/* gather up the path name for the sensor */
1030 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
1031 		for (i = 0; i < PARENT_NAMES; i++) {
1032 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
1033 			    NULL) {
1034 				while (--i > -1)
1035 					free(names[i]);
1036 				free(loc);
1037 				loc = NULL;
1038 			}
1039 		}
1040 	}
1041 	i = 0;
1042 	if (loc != 0) {
1043 		while (err == PICL_SUCCESS) {
1044 			if (parenth == phyplatformh)
1045 				break;
1046 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1047 			    names[i++], PICL_PROPNAMELEN_MAX);
1048 			if (err != PICL_SUCCESS) {
1049 				i--;
1050 				break;
1051 			}
1052 			if (i == PARENT_NAMES)
1053 				break;
1054 			err = picl_get_propval_by_name(parenth,
1055 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
1056 		}
1057 		loc[0] = '\0';
1058 		if (--i > -1) {
1059 			(void) strlcat(loc, names[i],
1060 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1061 		}
1062 		while (--i > -1) {
1063 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
1064 			    PARENT_NAMES);
1065 			(void) strlcat(loc, names[i],
1066 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1067 		}
1068 		log_printf("%-35s", loc);
1069 		for (i = 0; i < PARENT_NAMES; i++)
1070 			free(names[i]);
1071 		free(loc);
1072 	} else {
1073 		log_printf("%-35s", " ");
1074 	}
1075 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val,
1076 	    sizeof (val));
1077 	if (err == PICL_SUCCESS)
1078 		log_printf("%-15s", val);
1079 
1080 	/*
1081 	 * Get the exponent if present, and do a little math so that
1082 	 * if we need to we can print a normalized value for the
1083 	 * sensor reading.
1084 	 */
1085 	if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPONENT,
1086 	    &exponent, sizeof (exponent)) != PICL_SUCCESS)
1087 		exponent = 0;
1088 	if (exponent == 0)
1089 		display_val = (double)current_val;
1090 	else
1091 		display_val = (double)current_val *
1092 		    pow((double)10, (double)exponent);
1093 	err = picl_get_propval_by_name(nodeh, PICL_PROP_BASE_UNITS,
1094 	    base_units, sizeof (base_units));
1095 	if (err != PICL_SUCCESS)
1096 		base_units[0] = '\0';
1097 
1098 	switch (sensor_status) {
1099 	case SENSOR_FAILED:
1100 		log_printf("%-s", "failed (");
1101 		log_printf("%-.*f", abs(exponent), display_val);
1102 		log_printf("%-s %s", base_units, ")");
1103 		break;
1104 	case SENSOR_WARN:
1105 		log_printf("%-s", "warning (");
1106 		log_printf("%-.*f", abs(exponent), display_val);
1107 		log_printf("%-s %s", base_units, ")");
1108 		break;
1109 	case SENSOR_DISABLED:
1110 		log_printf("%-s", "disabled");
1111 		break;
1112 	case SENSOR_OK:
1113 		log_printf("%-s", "ok");
1114 		break;
1115 	default:
1116 		log_printf("%-s", "unknown");
1117 		break;
1118 	}
1119 
1120 	log_printf("\n");
1121 	return (PICL_WALK_CONTINUE);
1122 }
1123 
1124 /*ARGSUSED*/
1125 static int
1126 sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args)
1127 {
1128 	char current_val[PICL_PROPNAMELEN_MAX];
1129 	char expected_val[PICL_PROPNAMELEN_MAX];
1130 	char label[PICL_PROPNAMELEN_MAX];
1131 	picl_nodehdl_t parenth;
1132 	char *names[PARENT_NAMES];
1133 	char *loc;
1134 	int i = 0;
1135 	char *prop = (char *)args;
1136 	picl_errno_t err = PICL_SUCCESS;
1137 	typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED,
1138 	    SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t;
1139 	sensor_status_t sensor_status = SENSOR_OK;
1140 
1141 	if (class_node_found == 0) {
1142 		class_node_found = 1;
1143 		return (PICL_WALK_TERMINATE);
1144 	}
1145 
1146 	prop = (char *)args;
1147 	if (!prop) {
1148 		sensor_status = SENSOR_UNKNOWN;
1149 		all_status_ok = 0;
1150 	} else {
1151 		err = picl_get_propval_by_name(nodeh,
1152 		    PICL_PROP_OPERATIONAL_STATUS, current_val,
1153 		    sizeof (current_val));
1154 		if (err == PICL_SUCCESS) {
1155 			if (strcmp(current_val, "disabled") == 0) {
1156 				sensor_status = SENSOR_DISABLED;
1157 			}
1158 		}
1159 	}
1160 
1161 	if (sensor_status != SENSOR_DISABLED &&
1162 	    sensor_status != SENSOR_UNKNOWN) {
1163 		if (picl_get_propval_by_name(nodeh, prop, &current_val,
1164 		    sizeof (current_val)) != PICL_SUCCESS) {
1165 			(void) strlcpy(current_val, "unknown",
1166 			    sizeof (current_val));
1167 			sensor_status = SENSOR_UNKNOWN;
1168 		} else {
1169 			if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPECTED,
1170 			    &expected_val, sizeof (expected_val)) !=
1171 			    PICL_SUCCESS) {
1172 				sensor_status = SENSOR_UNKNOWN;
1173 			} else {
1174 				if (strncmp(current_val, expected_val,
1175 				    sizeof (current_val)) == 0) {
1176 					sensor_status = SENSOR_OK;
1177 				} else {
1178 					sensor_status = SENSOR_FAILED;
1179 				}
1180 			}
1181 		}
1182 	}
1183 
1184 	if (syserrlog == 0) {
1185 		if (sensor_status != SENSOR_OK && all_status_ok == 1) {
1186 			all_status_ok = 0;
1187 			return (PICL_WALK_TERMINATE);
1188 		}
1189 		if (sensor_status == SENSOR_OK) {
1190 			return (PICL_WALK_CONTINUE);
1191 		}
1192 	}
1193 
1194 	/*
1195 	 * If we're here then prtdiag was invoked with "-v" or we have
1196 	 * a sensor that is beyond a threshold, so give them a book to
1197 	 * read instead of the Cliff Notes.
1198 	 */
1199 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1200 	    sizeof (parenth));
1201 	if (err != PICL_SUCCESS) {
1202 		log_printf("\n");
1203 		return (PICL_WALK_CONTINUE);
1204 	}
1205 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) {
1206 		for (i = 0; i < PARENT_NAMES; i++) {
1207 			if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) ==
1208 			    NULL) {
1209 				while (--i > -1)
1210 					free(names[i]);
1211 				free(loc);
1212 				loc = NULL;
1213 			}
1214 		}
1215 	}
1216 	i = 0;
1217 	if (loc) {
1218 		while (err == PICL_SUCCESS) {
1219 			if (parenth == phyplatformh)
1220 				break;
1221 			err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1222 			    names[i++], PICL_PROPNAMELEN_MAX);
1223 			if (err != PICL_SUCCESS) {
1224 				i--;
1225 				break;
1226 			}
1227 			if (i == PARENT_NAMES)
1228 				break;
1229 			err = picl_get_propval_by_name(parenth,
1230 			    PICL_PROP_PARENT, &parenth, sizeof (parenth));
1231 		}
1232 		loc[0] = '\0';
1233 		if (--i > -1) {
1234 			(void) strlcat(loc, names[i],
1235 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1236 		}
1237 		while (--i > -1) {
1238 			(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX *
1239 			    PARENT_NAMES);
1240 			(void) strlcat(loc, names[i],
1241 			    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1242 		}
1243 		log_printf("%-35s", loc);
1244 		for (i = 0; i < PARENT_NAMES; i++)
1245 			free(names[i]);
1246 		free(loc);
1247 	} else {
1248 		log_printf("%-35s", "");
1249 	}
1250 
1251 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
1252 	    sizeof (label));
1253 	if (err != PICL_SUCCESS)
1254 		(void) strlcpy(label, "", sizeof (label));
1255 	log_printf("%-15s", label);
1256 
1257 	log_printf("%-8s", current_val);
1258 
1259 	log_printf("\n");
1260 	return (PICL_WALK_CONTINUE);
1261 }
1262 
1263 static void
1264 sun4v_env_print_fan_sensors()
1265 {
1266 	char *fmt = "%-34s %-14s %-10s\n";
1267 	/*
1268 	 * If there isn't any fan sensor node, return now.
1269 	 */
1270 	(void) picl_walk_tree_by_class(phyplatformh,
1271 	    PICL_CLASS_RPM_SENSOR, (void *)PICL_PROP_SPEED,
1272 	    sun4v_env_print_sensor_callback);
1273 	if (!class_node_found)
1274 		return;
1275 	log_printf("Fan sensors:\n");
1276 	if (syserrlog == 0) {
1277 		(void) picl_walk_tree_by_class(phyplatformh,
1278 		    PICL_CLASS_RPM_SENSOR,
1279 		    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
1280 		if (all_status_ok) {
1281 			log_printf("All fan sensors are OK.\n");
1282 			return;
1283 		}
1284 	}
1285 	log_printf("-------------------------------------------------"
1286 	    "-----------\n");
1287 	log_printf(fmt, "Location", "Sensor", "Status", 0);
1288 	log_printf("-------------------------------------------------"
1289 	    "-----------\n");
1290 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR,
1291 	    PICL_PROP_SPEED, sun4v_env_print_sensor_callback);
1292 }
1293 
1294 static void
1295 sun4v_env_print_fan_indicators()
1296 {
1297 	char *fmt = "%-34s %-14s %-10s\n";
1298 	(void) picl_walk_tree_by_class(phyplatformh,
1299 	    PICL_CLASS_RPM_INDICATOR, (void *)PICL_PROP_CONDITION,
1300 	    sun4v_env_print_indicator_callback);
1301 	if (!class_node_found)
1302 		return;
1303 	log_printf("\nFan indicators:\n");
1304 	if (syserrlog == 0) {
1305 		(void) picl_walk_tree_by_class(phyplatformh,
1306 		    PICL_CLASS_RPM_INDICATOR,
1307 		    (void *)PICL_PROP_CONDITION,
1308 		    sun4v_env_print_indicator_callback);
1309 		if (all_status_ok) {
1310 			log_printf("All fan indicators are OK.\n");
1311 			return;
1312 		}
1313 	}
1314 	log_printf("-------------------------------------------------"
1315 	    "-----------\n");
1316 	log_printf(fmt, "Location", "Sensor", "Condition", 0);
1317 	log_printf("-------------------------------------------------"
1318 	    "-----------\n");
1319 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR,
1320 	    (void *)PICL_PROP_CONDITION, sun4v_env_print_indicator_callback);
1321 }
1322 
1323 static void
1324 sun4v_env_print_temp_sensors()
1325 {
1326 	char *fmt = "%-34s %-14s %-10s\n";
1327 	(void) picl_walk_tree_by_class(phyplatformh,
1328 	    PICL_CLASS_TEMPERATURE_SENSOR,
1329 	    (void *)PICL_PROP_TEMPERATURE,
1330 	    sun4v_env_print_sensor_callback);
1331 	if (!class_node_found)
1332 		return;
1333 
1334 	log_printf("\nTemperature sensors:\n");
1335 	if (syserrlog == 0) {
1336 		(void) picl_walk_tree_by_class(phyplatformh,
1337 		    PICL_CLASS_TEMPERATURE_SENSOR,
1338 		    PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
1339 		if (all_status_ok) {
1340 			log_printf("All temperature sensors are OK.\n");
1341 			return;
1342 		}
1343 	}
1344 	log_printf("-------------------------------------------------"
1345 	    "-----------\n");
1346 	log_printf(fmt, "Location", "Sensor", "Status", 0);
1347 	log_printf("-------------------------------------------------"
1348 	    "-----------\n");
1349 	(void) picl_walk_tree_by_class(phyplatformh,
1350 	    PICL_CLASS_TEMPERATURE_SENSOR,
1351 	    (void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback);
1352 }
1353 
1354 static void
1355 sun4v_env_print_temp_indicators()
1356 {
1357 	char *fmt = "%-34s %-14s %-8s\n";
1358 	(void) picl_walk_tree_by_class(phyplatformh,
1359 	    PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION,
1360 	    sun4v_env_print_indicator_callback);
1361 	if (!class_node_found)
1362 		return;
1363 	log_printf("\nTemperature indicators:\n");
1364 	if (syserrlog == 0) {
1365 		(void) picl_walk_tree_by_class(phyplatformh,
1366 		    PICL_CLASS_TEMPERATURE_INDICATOR,
1367 		    (void *)PICL_PROP_CONDITION,
1368 		    sun4v_env_print_indicator_callback);
1369 		if (all_status_ok) {
1370 			log_printf("All temperature indicators are OK.\n");
1371 			return;
1372 		}
1373 	}
1374 	log_printf("-------------------------------------------------"
1375 	    "-----------\n");
1376 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
1377 	log_printf("-------------------------------------------------"
1378 	    "-----------\n");
1379 	(void) picl_walk_tree_by_class(phyplatformh,
1380 	    PICL_CLASS_TEMPERATURE_INDICATOR,
1381 	    (void *)PICL_PROP_CONDITION,
1382 	    sun4v_env_print_indicator_callback);
1383 }
1384 
1385 static void
1386 sun4v_env_print_current_sensors()
1387 {
1388 	char *fmt = "%-34s %-14s %-10s\n";
1389 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR,
1390 	    (void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
1391 	if (!class_node_found)
1392 		return;
1393 	log_printf("\nCurrent sensors:\n");
1394 	if (syserrlog == 0) {
1395 		(void) picl_walk_tree_by_class(phyplatformh,
1396 		    PICL_CLASS_CURRENT_SENSOR,
1397 		    PICL_PROP_CURRENT, sun4v_env_print_sensor_callback);
1398 		if (all_status_ok) {
1399 			log_printf("All current sensors are OK.\n");
1400 			return;
1401 		}
1402 	}
1403 	log_printf("-------------------------------------------------"
1404 	    "-----------\n");
1405 	log_printf(fmt, "Location", "Sensor", "Status", 0);
1406 	log_printf("-------------------------------------------------"
1407 	    "-----------\n");
1408 	(void) picl_walk_tree_by_class(phyplatformh,
1409 	    PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT,
1410 	    sun4v_env_print_sensor_callback);
1411 }
1412 
1413 static void
1414 sun4v_env_print_current_indicators()
1415 {
1416 	char *fmt = "%-34s %-14s %-8s\n";
1417 	(void) picl_walk_tree_by_class(phyplatformh,
1418 	    PICL_CLASS_CURRENT_INDICATOR,
1419 	    (void *)PICL_PROP_CONDITION,
1420 	    sun4v_env_print_indicator_callback);
1421 	if (!class_node_found)
1422 		return;
1423 	log_printf("\nCurrent indicators:\n");
1424 	if (syserrlog == 0) {
1425 		(void) picl_walk_tree_by_class(phyplatformh,
1426 		    PICL_CLASS_CURRENT_INDICATOR, (void *)PICL_PROP_CONDITION,
1427 		    sun4v_env_print_indicator_callback);
1428 		if (all_status_ok) {
1429 			log_printf("All current indicators are OK.\n");
1430 			return;
1431 		}
1432 	}
1433 	log_printf("-------------------------------------------------"
1434 	    "-----------\n");
1435 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
1436 	log_printf("-------------------------------------------------"
1437 	    "-----------\n");
1438 	(void) picl_walk_tree_by_class(phyplatformh,
1439 	    PICL_CLASS_CURRENT_INDICATOR,
1440 	    (void *)PICL_PROP_CONDITION,
1441 	    sun4v_env_print_indicator_callback);
1442 }
1443 
1444 static void
1445 sun4v_env_print_voltage_sensors()
1446 {
1447 	char *fmt = "%-34s %-14s %-10s\n";
1448 	(void) picl_walk_tree_by_class(phyplatformh,
1449 	    PICL_CLASS_VOLTAGE_SENSOR,
1450 	    PICL_PROP_VOLTAGE,
1451 	    sun4v_env_print_sensor_callback);
1452 	if (!class_node_found)
1453 		return;
1454 	log_printf("\nVoltage sensors:\n");
1455 	if (syserrlog == 0) {
1456 		(void) picl_walk_tree_by_class(phyplatformh,
1457 		    PICL_CLASS_VOLTAGE_SENSOR,
1458 		    PICL_PROP_VOLTAGE, sun4v_env_print_sensor_callback);
1459 		if (all_status_ok) {
1460 			log_printf("All voltage sensors are OK.\n");
1461 			return;
1462 		}
1463 	}
1464 	log_printf("-------------------------------------------------"
1465 	    "-----------\n");
1466 	log_printf(fmt, "Location", "Sensor", "Status", 0);
1467 	log_printf("-------------------------------------------------"
1468 	    "-----------\n");
1469 	(void) picl_walk_tree_by_class(phyplatformh,
1470 	    PICL_CLASS_VOLTAGE_SENSOR,
1471 	    (void *)PICL_PROP_VOLTAGE,
1472 	    sun4v_env_print_sensor_callback);
1473 }
1474 
1475 static void
1476 sun4v_env_print_voltage_indicators()
1477 {
1478 	char *fmt = "%-34s %-14s %-8s\n";
1479 	(void) picl_walk_tree_by_class(phyplatformh,
1480 	    PICL_CLASS_VOLTAGE_INDICATOR,
1481 	    (void *)PICL_PROP_CONDITION,
1482 	    sun4v_env_print_indicator_callback);
1483 	if (!class_node_found)
1484 		return;
1485 	log_printf("\nVoltage indicators:\n");
1486 	if (syserrlog == 0) {
1487 		(void) picl_walk_tree_by_class(phyplatformh,
1488 		    PICL_CLASS_VOLTAGE_INDICATOR, (void *)PICL_PROP_CONDITION,
1489 		    sun4v_env_print_indicator_callback);
1490 		if (all_status_ok) {
1491 			log_printf("All voltage indicators are OK.\n");
1492 			return;
1493 		}
1494 	}
1495 	log_printf("-------------------------------------------------"
1496 	    "-----------\n");
1497 	log_printf(fmt, "Location", "Indicator", "Condition", 0);
1498 	log_printf("-------------------------------------------------"
1499 	    "-----------\n");
1500 	(void) picl_walk_tree_by_class(phyplatformh,
1501 	    PICL_CLASS_VOLTAGE_INDICATOR,
1502 	    (void *)PICL_PROP_CONDITION,
1503 	    sun4v_env_print_indicator_callback);
1504 }
1505 
1506 static void
1507 sun4v_env_print_LEDs()
1508 {
1509 	char *fmt = "%-34s %-14s %-8s\n";
1510 	if (syserrlog == 0)
1511 		return;
1512 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
1513 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
1514 	if (!class_node_found)
1515 		return;
1516 	log_printf("\nLEDs:\n");
1517 	log_printf("-------------------------------------------------"
1518 	    "-----------\n");
1519 	log_printf(fmt, "Location", "LED", "State", 0);
1520 	log_printf("-------------------------------------------------"
1521 	    "-----------\n");
1522 	(void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED,
1523 	    (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback);
1524 }
1525 
1526 /*ARGSUSED*/
1527 static int
1528 sun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args)
1529 {
1530 	char label[PICL_PROPNAMELEN_MAX];
1531 	char status[PICL_PROPNAMELEN_MAX];
1532 	picl_errno_t err;
1533 	picl_prophdl_t proph;
1534 	picl_nodehdl_t parenth;
1535 	char *names[PARENT_NAMES];
1536 	char *loc;
1537 	int i;
1538 
1539 	if (!class_node_found) {
1540 		class_node_found = 1;
1541 		return (PICL_WALK_TERMINATE);
1542 	}
1543 	err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph);
1544 	if (err != PICL_SUCCESS)
1545 		return (PICL_WALK_CONTINUE);
1546 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
1547 	    sizeof (label));
1548 	if (err != PICL_SUCCESS)
1549 		return (PICL_WALK_CONTINUE);
1550 	err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
1551 	    status, sizeof (status));
1552 	if (err != PICL_SUCCESS)
1553 		return (PICL_WALK_CONTINUE);
1554 	if (syserrlog == 0) {
1555 		if (strcmp(status, "disabled") == 0) {
1556 			if (all_status_ok) {
1557 				all_status_ok = 0;
1558 				return (PICL_WALK_TERMINATE);
1559 			}
1560 		} else
1561 			return (PICL_WALK_CONTINUE);
1562 	}
1563 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth,
1564 	    sizeof (parenth));
1565 	if (err != PICL_SUCCESS) {
1566 		log_printf("\n");
1567 		return (PICL_WALK_CONTINUE);
1568 	}
1569 	if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL)
1570 		return (PICL_WALK_TERMINATE);
1571 	for (i = 0; i < PARENT_NAMES; i++)
1572 		if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) {
1573 			while (--i > -1)
1574 				free(names[i]);
1575 			free(loc);
1576 			return (PICL_WALK_TERMINATE);
1577 		}
1578 	i = 0;
1579 	while (err == PICL_SUCCESS) {
1580 		if (parenth == phyplatformh)
1581 			break;
1582 		err = picl_get_propval_by_name(parenth, PICL_PROP_NAME,
1583 		    names[i++], PICL_PROPNAMELEN_MAX);
1584 		if (err != PICL_SUCCESS) {
1585 			i--;
1586 			break;
1587 		}
1588 		if (i == PARENT_NAMES)
1589 			break;
1590 		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
1591 		    &parenth, sizeof (parenth));
1592 	}
1593 	loc[0] = '\0';
1594 	if (--i > -1) {
1595 		(void) strlcat(loc, names[i],
1596 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1597 	}
1598 	while (--i > -1) {
1599 		(void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1600 		(void) strlcat(loc, names[i],
1601 		    PICL_PROPNAMELEN_MAX * PARENT_NAMES);
1602 	}
1603 	log_printf("%-35s", loc);
1604 	for (i = 0; i < PARENT_NAMES; i++)
1605 		free(names[i]);
1606 	free(loc);
1607 	log_printf("%-10s", label);
1608 	log_printf("%-9s", status);
1609 	log_printf("\n");
1610 	return (PICL_WALK_CONTINUE);
1611 }
1612 
1613 static void
1614 sun4v_print_fru_status()
1615 {
1616 	char *fmt = "%-34s %-9s %-8s\n";
1617 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1618 	    sun4v_print_fru_status_callback);
1619 	if (!class_node_found)
1620 		return;
1621 	log_printf("\n");
1622 	log_printf("============================");
1623 	log_printf(" FRU Status ");
1624 	log_printf("============================");
1625 	log_printf("\n");
1626 
1627 	if (syserrlog == 0) {
1628 		(void) picl_walk_tree_by_class(phyplatformh,
1629 		    NULL, NULL,
1630 		    sun4v_print_fru_status_callback);
1631 		if (all_status_ok) {
1632 			log_printf("All FRUs are enabled.\n");
1633 			return;
1634 		}
1635 	}
1636 	log_printf(fmt, "Location", "Name", "Status", 0);
1637 	log_printf("------------------------------------------------------\n");
1638 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1639 	    sun4v_print_fru_status_callback);
1640 }
1641 
1642 /*ARGSUSED*/
1643 static int
1644 sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args)
1645 {
1646 	char label[PICL_PROPNAMELEN_MAX];
1647 	char rev[PICL_PROPNAMELEN_MAX];
1648 	picl_errno_t err;
1649 
1650 	if (!class_node_found) {
1651 		class_node_found = 1;
1652 		return (PICL_WALK_TERMINATE);
1653 	}
1654 	err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label,
1655 	    sizeof (label));
1656 	if (err != PICL_SUCCESS)
1657 		return (PICL_WALK_CONTINUE);
1658 	err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev,
1659 	    sizeof (rev));
1660 	if (err != PICL_SUCCESS)
1661 		return (PICL_WALK_CONTINUE);
1662 	if (strlen(rev) == 0)
1663 		return (PICL_WALK_CONTINUE);
1664 	log_printf("%-21s", label);
1665 	log_printf("%-35s", rev);
1666 	log_printf("\n");
1667 	return (PICL_WALK_CONTINUE);
1668 }
1669 
1670 static void
1671 sun4v_print_fw_rev()
1672 {
1673 	char *fmt = "%-20s %-10s\n";
1674 	if (syserrlog == 0)
1675 		return;
1676 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1677 	    sun4v_print_fw_rev_callback);
1678 	if (!class_node_found)
1679 		return;
1680 	log_printf("\n");
1681 	log_printf("============================");
1682 	log_printf(" FW Version ");
1683 	log_printf("============================");
1684 	log_printf("\n");
1685 	log_printf(fmt, "Name", "Version", 0);
1686 	log_printf("-------------------------------------------------"
1687 	    "-----------\n");
1688 	(void) picl_walk_tree_by_class(phyplatformh, NULL, NULL,
1689 	    sun4v_print_fw_rev_callback);
1690 }
1691 
1692 static void
1693 sun4v_print_chassis_serial_no()
1694 {
1695 	char val[PICL_PROPNAMELEN_MAX];
1696 	picl_errno_t err;
1697 	if (syserrlog == 0 || chassish == 0)
1698 		return;
1699 
1700 	log_printf("\n");
1701 	log_printf("Chassis Serial Number");
1702 	log_printf("\n");
1703 	log_printf("---------------------\n");
1704 	err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER,
1705 	    val, sizeof (val));
1706 	if (err == PICL_SUCCESS)
1707 		log_printf("%s", val);
1708 	log_printf("\n");
1709 }
1710