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