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