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