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