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