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