xref: /illumos-gate/usr/src/lib/libprtdiag_psr/sparc/desktop/common/picldiag.c (revision 60405de4d8688d96dd05157c28db3ade5c9bc234)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <alloca.h>
33 #include <errno.h>
34 #include <libintl.h>
35 #include <sys/utsname.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/openpromio.h>
39 #include <sys/ddi.h>
40 #include <syslog.h>
41 #include <fcntl.h>
42 #include <dirent.h>
43 #include <unistd.h>
44 #include <locale.h>
45 #include <picl.h>
46 #include "pdevinfo.h"
47 #include "display.h"
48 #include "display_sun4u.h"
49 #include "picldefs.h"
50 #include "libprtdiag.h"
51 
52 #if !defined(TEXT_DOMAIN)
53 #define	TEXT_DOMAIN	"SYS_TEST"
54 #endif
55 
56 #define	EM_INIT_FAIL		dgettext(TEXT_DOMAIN,\
57 	"picl_initialize failed: %s\n")
58 #define	EM_GET_ROOT_FAIL	dgettext(TEXT_DOMAIN,\
59 	"Getting root node failed: %s\n")
60 #define	EM_PRTDIAG_FAIL		dgettext(TEXT_DOMAIN, "Prtdiag failed!\n")
61 
62 #define	SIGN_ON_MSG	dgettext(TEXT_DOMAIN,\
63 	"System Configuration: Sun Microsystems ")
64 #define	SYSCLK_FREQ_MSG	dgettext(TEXT_DOMAIN,\
65 	"System clock frequency: %d MHZ\n")
66 #define	SERIAL_NUM_MSG	dgettext(TEXT_DOMAIN,\
67 	"Chassis Serial Number:\n")
68 #define	MEM_SIZE_MSG	dgettext(TEXT_DOMAIN, "Memory size: ")
69 #define	FFB_DOUBLE_BUF	dgettext(TEXT_DOMAIN, "FFB, Double Buffered")
70 #define	FFB_SINGLE_BUF	dgettext(TEXT_DOMAIN, "FFB, Single Buffered")
71 
72 #define	DEFAULT_BOARD_NUM	0
73 #define	DEFAULT_PORTID		0
74 #define	CLK_FREQ_66MHZ		66
75 #define	USB			-1
76 #define	HUB			-2
77 
78 /* bus id */
79 #define	SBUS_TYPE		0
80 #define	PCI_TYPE		1
81 #define	UPA_TYPE		2
82 #define	PCIEX_TYPE		3
83 
84 #define	UPA_NAME		"upa"
85 #define	PCIEX_NAME		"pciex"
86 
87 /*
88  * PICL classes
89  */
90 #define	PICL_CLASS_OPTIONS		"options"
91 
92 /*
93  * Property names
94  */
95 
96 #define	OBP_PROP_REG			"reg"
97 #define	OBP_PROP_CLOCK_FREQ		"clock-frequency"
98 #define	OBP_PROP_BOARD_NUM		"board#"
99 #define	OBP_PROP_REVISION_ID		"revision-id"
100 #define	OBP_PROP_VERSION_NUM		"version#"
101 #define	OBP_PROP_MODREV_NUM		"module-revision#"
102 #define	OBP_PROP_BOARD_TYPE		"board_type"
103 #define	OBP_PROP_ECACHE_SIZE		"ecache-size"
104 #define	OBP_PROP_IMPLEMENTATION		"implementation#"
105 #define	OBP_PROP_MASK			"mask#"
106 #define	OBP_PROP_COMPATIBLE		"compatible"
107 #define	OBP_PROP_BANNER_NAME		"banner-name"
108 #define	OBP_PROP_MODEL			"model"
109 #define	OBP_PROP_66MHZ_CAPABLE		"66mhz-capable"
110 #define	OBP_PROP_FBC_REG_ID		"fbc_reg_id"
111 #define	OBP_PROP_VERSION		"version"
112 
113 #define	PROP_POWERFAIL_TIME		"powerfail-time"
114 #define	PICL_PROP_LOW_WARNING_THRESHOLD	"LowWarningThreshold"
115 
116 #define	DEFAULT_LINE_WIDTH		78
117 #define	HEADING_SYMBOL			"="
118 
119 #define	MAX_IWAYS			32
120 
121 typedef struct bank_list {
122 	picl_nodehdl_t		nodeh;
123 	uint32_t		iway_count;
124 	uint32_t		iway[MAX_IWAYS];
125 	struct bank_list	*next;
126 } bank_list_t;
127 
128 typedef struct {
129 	uint64_t	base;
130 	uint64_t	size;
131 	int		ifactor;
132 	int		bank_count;
133 } seg_info_t;
134 
135 static struct io_card	*io_card_list = NULL; /* The head of the IO card list */
136 static bank_list_t	*mem_banks = NULL;
137 static	int		mem_xfersize;
138 static	int		no_xfer_size = 0;
139 
140 static char *io_device_table[] = {
141 	"block",
142 	"disk",
143 	"cdrom",
144 	"floppy",
145 	"tape",
146 	"network",
147 	"display",
148 	"serial",
149 	"parallel",
150 	"scsi",
151 	"scsi-2",
152 	"scsi-3",
153 	"ide",
154 	"fcal",
155 	"keyboard",
156 	"mouse",
157 	"dma"
158 };
159 
160 #define	NIODEVICE	sizeof (io_device_table) / sizeof (io_device_table[0])
161 
162 static char *bus_table[] = {
163 	"ebus",
164 	"isa",
165 	"pmu",
166 	"pci",
167 	"pciex"
168 };
169 
170 #define	NBUS	sizeof (bus_table) / sizeof (bus_table[0])
171 
172 /* prtdiag exit codes */
173 #define	PD_SUCCESS		0
174 #define	PD_SYSTEM_FAILURE	1
175 #define	PD_INTERNAL_FAILURE	2
176 
177 /*
178  * Use of global assumes do_prominfo only called from main in prtdiag and
179  * access does not need to be multi-thread safe.
180  */
181 static int	exit_code = PD_SUCCESS;
182 
183 /*
184  * This function is called from every location where a status value is output.
185  * It checks the status arg and sets exit_code if an error is detected.
186  * The status is typically returned from a PICL query. A case-insensitive
187  * string comparison is done to check for any status that starts with "fail"
188  * or "fault".
189  */
190 static void
191 set_exit_code(char *status)
192 {
193 	if (status == NULL)
194 		return;
195 
196 	if (strncasecmp(status, "fail", 4) == 0 ||
197 	    strncasecmp(status, "fault", 5) == 0)
198 		exit_code = PD_SYSTEM_FAILURE;
199 }
200 
201 /*
202  * check if it is an IO deice
203  */
204 static int
205 is_io_device(char *device_class)
206 {
207 	int i;
208 
209 	for (i = 0; i < NIODEVICE; i++) {
210 	    if (strcmp(device_class, io_device_table[i]) == 0)
211 		return (1);
212 	}
213 
214 	return (0);
215 }
216 
217 /*
218  * check if it is a bus
219  */
220 static int
221 is_bus(char *device_class)
222 {
223 	int i;
224 
225 	for (i = 0; i < NBUS; i++) {
226 	    if (strcmp(device_class, bus_table[i]) == 0)
227 		return (1);
228 	}
229 
230 	return (0);
231 }
232 
233 /*
234  * search children to get the node by the nodename
235  */
236 static int
237 picldiag_get_node_by_name(picl_nodehdl_t rooth, char *name,
238     picl_nodehdl_t *nodeh)
239 {
240 	picl_nodehdl_t	childh;
241 	int		err;
242 	char		*nodename;
243 
244 	nodename = alloca(strlen(name) + 1);
245 	if (nodename == NULL)
246 		return (PICL_FAILURE);
247 
248 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
249 	    sizeof (picl_nodehdl_t));
250 
251 	while (err == PICL_SUCCESS) {
252 		err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
253 		    nodename, (strlen(name) + 1));
254 		if (err != PICL_SUCCESS) {
255 			err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
256 				&childh, sizeof (picl_nodehdl_t));
257 			continue;
258 		}
259 
260 		if (strcmp(nodename, name) == 0) {
261 			*nodeh = childh;
262 			return (PICL_SUCCESS);
263 		}
264 
265 		err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
266 		    &childh, sizeof (picl_nodehdl_t));
267 	}
268 
269 	return (err);
270 }
271 
272 /*
273  * get the value by the property name of the string prop
274  * Caller must free the outbuf
275  */
276 static int
277 picldiag_get_string_propval(picl_nodehdl_t modh, char *prop_name, char **outbuf)
278 {
279 	int		err;
280 	picl_prophdl_t	proph;
281 	picl_propinfo_t	pinfo;
282 	char		*prop_value;
283 
284 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
285 	if (err != PICL_SUCCESS)
286 		return (err);
287 
288 	/*
289 	 * If it is not a string prop, return NULL
290 	 */
291 	if (pinfo.type != PICL_PTYPE_CHARSTRING)
292 	    return (PICL_FAILURE);
293 
294 	prop_value = malloc(pinfo.size);
295 	if (prop_value == NULL)
296 		return (PICL_FAILURE);
297 
298 	err = picl_get_propval(proph, prop_value, pinfo.size);
299 	if (err != PICL_SUCCESS) {
300 		free(prop_value);
301 		return (err);
302 	}
303 
304 	*outbuf = prop_value;
305 	return (PICL_SUCCESS);
306 }
307 
308 
309 /*
310  * return the value as a signed integer
311  */
312 
313 static int64_t
314 picldiag_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
315 {
316 	int		err;
317 	picl_prophdl_t	proph;
318 	picl_propinfo_t	pinfo;
319 	int8_t		int8v;
320 	int16_t		int16v;
321 	int32_t		int32v;
322 	int64_t		int64v;
323 
324 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
325 	if (err != PICL_SUCCESS) {
326 		*ret = err;
327 		return (0);
328 	}
329 
330 	/*
331 	 * If it is not an int, uint or byte array prop, return failure
332 	 */
333 	if ((pinfo.type != PICL_PTYPE_INT) &&
334 		(pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
335 		(pinfo.type != PICL_PTYPE_BYTEARRAY)) {
336 		*ret = PICL_FAILURE;
337 		return (0);
338 	}
339 
340 	switch (pinfo.size) {
341 	case sizeof (int8_t):
342 		err = picl_get_propval(proph, &int8v, sizeof (int8v));
343 		*ret = err;
344 		return (int8v);
345 	case sizeof (int16_t):
346 		err = picl_get_propval(proph, &int16v, sizeof (int16v));
347 		*ret = err;
348 		return (int16v);
349 	case sizeof (int32_t):
350 		err = picl_get_propval(proph, &int32v, sizeof (int32v));
351 		*ret = err;
352 		return (int32v);
353 	case sizeof (int64_t):
354 		err = picl_get_propval(proph, &int64v, sizeof (int64v));
355 		*ret = err;
356 		return (int64v);
357 	default:	/* not supported size */
358 		*ret = PICL_FAILURE;
359 		return (0);
360 	}
361 }
362 
363 /*
364  * return the value of the uint prop
365  */
366 static uint64_t
367 picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
368 {
369 	int		err;
370 	picl_prophdl_t	proph;
371 	picl_propinfo_t	pinfo;
372 	uint8_t		uint8v;
373 	uint16_t	uint16v;
374 	uint32_t	uint32v;
375 	uint64_t	uint64v;
376 
377 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
378 	if (err != PICL_SUCCESS) {
379 		*ret = err;
380 		return (0);
381 	}
382 
383 	/*
384 	 * If it is not an int or uint prop, return failure
385 	 */
386 	if ((pinfo.type != PICL_PTYPE_INT) &&
387 		(pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
388 		*ret = PICL_FAILURE;
389 		return (0);
390 	}
391 
392 	/* uint prop */
393 
394 	switch (pinfo.size) {
395 	case sizeof (uint8_t):
396 		err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
397 		*ret = err;
398 		return (uint8v);
399 	case sizeof (uint16_t):
400 		err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
401 		*ret = err;
402 		return (uint16v);
403 	case sizeof (uint32_t):
404 		err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
405 		*ret = err;
406 		return (uint32v);
407 	case sizeof (uint64_t):
408 		err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
409 		*ret = err;
410 		return (uint64v);
411 	default:	/* not supported size */
412 		*ret = PICL_FAILURE;
413 		return (0);
414 	}
415 }
416 
417 /*
418  * return the value of the float prop
419  */
420 static float
421 picldiag_get_float_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
422 {
423 	int		err;
424 	picl_prophdl_t	proph;
425 	picl_propinfo_t	pinfo;
426 	float		floatv;
427 
428 	err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
429 	if (err != PICL_SUCCESS) {
430 		*ret = err;
431 		return ((float)0);
432 	}
433 
434 	/*
435 	 * If it is not a float prop, return failure
436 	 */
437 	if (pinfo.type != PICL_PTYPE_FLOAT) {
438 		*ret = PICL_FAILURE;
439 		return ((float)0);
440 	}
441 
442 	*ret = picl_get_propval(proph, &floatv, sizeof (floatv));
443 	return (floatv);
444 }
445 
446 /*
447  * get the clock frequency
448  */
449 static int
450 picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
451 {
452 #define	ROUND_TO_MHZ(x)	(((x) + 500000)/ 1000000)
453 	int		err;
454 	uint64_t	clk_freq;
455 
456 	clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
457 	if (err != PICL_SUCCESS)
458 		return (err);
459 
460 	*freq = ROUND_TO_MHZ(clk_freq);
461 
462 	return (PICL_SUCCESS);
463 }
464 
465 /*
466  * get the clock frequency from parent
467  */
468 static int
469 picldiag_get_clock_from_parent(picl_nodehdl_t nodeh, uint32_t *clk)
470 {
471 	picl_nodehdl_t	parenth;
472 	int		err;
473 
474 
475 	err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
476 	    &parenth, sizeof (parenth));
477 
478 	while (err == PICL_SUCCESS) {
479 		err = picldiag_get_clock_freq(parenth, clk);
480 		if (err != PICL_PROPNOTFOUND)
481 			return (err);
482 
483 		err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
484 		    &parenth, sizeof (parenth));
485 	}
486 
487 	return (err);
488 }
489 
490 /*
491  * get _fru_parent prop
492  * If not found, then travese superiors (parent nodes) until
493  * a _fru_parent property is found.
494  * If not found, no fru parent
495  */
496 static int
497 picldiag_get_fru_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruparenth)
498 {
499 	picl_nodehdl_t	fruh;
500 	int		err;
501 
502 	/* find fru parent */
503 	err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
504 	    &fruh, sizeof (fruh));
505 	if (err != PICL_SUCCESS)
506 		err = picl_get_propval_by_name(nodeh, PICL_REFPROP_LOC_PARENT,
507 		    &fruh, sizeof (fruh));
508 
509 	while (err == PICL_PROPNOTFOUND) {
510 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
511 		    &nodeh, sizeof (nodeh));
512 		if (err != PICL_SUCCESS)
513 			return (err);
514 
515 		err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
516 		    &fruh, sizeof (fruh));
517 		if (err != PICL_SUCCESS)
518 			err = picl_get_propval_by_name(nodeh,
519 			    PICL_REFPROP_LOC_PARENT, &fruh, sizeof (fruh));
520 	}
521 
522 	if (err == PICL_SUCCESS)
523 		*fruparenth = fruh;
524 
525 	return (err);
526 }
527 
528 /*
529  * get label
530  *
531  * To get the label, use the following algorithm:
532  * Lookup "Label" property in the fru node itself. If no
533  * Label found, then traverse superiors (parent nodes) until
534  * a Label property is found.
535  * if not found, then no label
536  */
537 static int
538 picldiag_get_label(picl_nodehdl_t nodeh, char **label)
539 {
540 	int		err;
541 
542 	err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, label);
543 
544 	while (err == PICL_PROPNOTFOUND) {
545 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
546 		    &nodeh, sizeof (nodeh));
547 		if (err != PICL_SUCCESS)
548 			return (err);
549 
550 		err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL,
551 		    label);
552 	}
553 
554 	return (err);
555 }
556 
557 /*
558  * get combined label
559  *
560  * like picldiag_get_label, except concatenates the labels of parent locations
561  * eg SB0/P3 for processor P3 on system board SB0
562  *
563  * if caller specifies non-zero label length, label will be cut to specified
564  * length.
565  * negative length is left justified, non-negative length is right justified
566  */
567 static int
568 picldiag_get_combined_label(picl_nodehdl_t nodeh, char **label, int lablen)
569 {
570 	int	err;
571 	char	*ptr;
572 	char	*ptr1 = NULL;
573 	char	*ptr2;
574 	int	len;
575 
576 	err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr1);
577 	if (err != PICL_PROPNOTFOUND && err != PICL_SUCCESS)
578 		return (err);
579 
580 	for (;;) {
581 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
582 		    &nodeh, sizeof (nodeh));
583 		if (err == PICL_PROPNOTFOUND)
584 			break;
585 		if (err != PICL_SUCCESS)
586 			return (err);
587 
588 		err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr);
589 		if (err == PICL_SUCCESS) {
590 			if (ptr1 == NULL) {
591 				ptr1 = ptr;
592 			} else {
593 				ptr2 = malloc(strlen(ptr1) + strlen(ptr) + 2);
594 				if (ptr2 == NULL)
595 					return (PICL_FAILURE);
596 				(void) strcpy(ptr2, ptr);
597 				(void) strcat(ptr2, "/");
598 				(void) strcat(ptr2, ptr1);
599 				(void) free(ptr);
600 				(void) free(ptr1);
601 				ptr1 = ptr2;
602 			}
603 		} else if (err != PICL_PROPNOTFOUND) {
604 			return (err);
605 		}
606 	}
607 
608 	if (ptr1 == NULL)
609 		return (PICL_PROPNOTFOUND);
610 
611 	len = strlen(ptr1);
612 	/* if no string truncation is desired or required */
613 	if ((lablen == 0) || (len <= abs(lablen))) {
614 		*label = ptr1;
615 		return (PICL_SUCCESS);
616 	}
617 
618 	/* string truncation is required; alloc space for (lablen + \0) */
619 	ptr = malloc(abs(lablen) + 1);
620 	if (ptr == 0)
621 		return (PICL_FAILURE);
622 	if (lablen > 0) {
623 		/* right justification; label = "+<string>\0" */
624 		strcpy(ptr, "+");
625 		strncat(ptr, ptr1 + len - lablen + 1, lablen + 1);
626 	} else {
627 		/* left justification; label = "<string>+\0" */
628 		strncpy(ptr, ptr1, abs(lablen) - 1);
629 		strcat(ptr, "+");
630 	}
631 
632 	*label = ptr;
633 	return (PICL_SUCCESS);
634 }
635 
636 /*
637  * return the first compatible value
638  */
639 static int
640 picldiag_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
641 {
642 	int		err;
643 	picl_prophdl_t	proph;
644 	picl_propinfo_t	pinfo;
645 	picl_prophdl_t	tblh;
646 	picl_prophdl_t	rowproph;
647 	char		*pval;
648 
649 	err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
650 	    &pinfo, &proph);
651 	if (err != PICL_SUCCESS)
652 	    return (err);
653 
654 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
655 		pval = malloc(pinfo.size);
656 		if (pval == NULL)
657 			return (PICL_FAILURE);
658 		err = picl_get_propval(proph, pval, pinfo.size);
659 		if (err != PICL_SUCCESS) {
660 			free(pval);
661 			return (err);
662 		}
663 		*outbuf = pval;
664 		return (PICL_SUCCESS);
665 	}
666 
667 	if (pinfo.type != PICL_PTYPE_TABLE)
668 		return (PICL_FAILURE);
669 
670 	/* get first string from table */
671 	err = picl_get_propval(proph, &tblh, pinfo.size);
672 	if (err != PICL_SUCCESS)
673 		return (err);
674 
675 	err = picl_get_next_by_row(tblh, &rowproph);
676 	if (err != PICL_SUCCESS)
677 		return (err);
678 
679 	err = picl_get_propinfo(rowproph, &pinfo);
680 	if (err != PICL_SUCCESS)
681 	    return (err);
682 
683 	pval = malloc(pinfo.size);
684 	if (pval == NULL)
685 		return (PICL_FAILURE);
686 
687 	err = picl_get_propval(rowproph, pval, pinfo.size);
688 	if (err != PICL_SUCCESS) {
689 		free(pval);
690 		return (err);
691 	}
692 
693 	*outbuf = pval;
694 	return (PICL_SUCCESS);
695 }
696 
697 /*
698  * print the header in the center
699  */
700 static void
701 logprintf_header(char *header, size_t line_width)
702 {
703 	size_t	start_pos;
704 	size_t	i;
705 
706 	log_printf("\n");
707 	start_pos = (line_width - strlen(header) - 2) / 2;
708 
709 	for (i = 0; i < start_pos; i++)
710 		log_printf("%s", HEADING_SYMBOL);
711 
712 	log_printf(" %s ", header);
713 
714 	for (i = 0; i < start_pos; i++)
715 		log_printf("%s", HEADING_SYMBOL);
716 
717 	log_printf("\n");
718 }
719 
720 /*
721  * print the size
722  */
723 static void
724 logprintf_size(uint64_t size)
725 {
726 #define	SIZE_FIELD	11
727 
728 	uint64_t	kbyte = 1024;
729 	uint64_t	mbyte = 1024 * 1024;
730 	uint64_t	gbyte = 1024 * 1024 * 1024;
731 	uint64_t	residue;
732 	char		buf[SIZE_FIELD];
733 
734 	if (size >= gbyte) {
735 		residue = size % gbyte;
736 		if (residue == 0)
737 			snprintf(buf, sizeof (buf), "%dGB",
738 			    (int)(size / gbyte));
739 		else
740 			snprintf(buf, sizeof (buf), "%.2fGB",
741 			    (float)size / gbyte);
742 	} else if (size >= mbyte) {
743 		residue = size % mbyte;
744 		if (residue == 0)
745 			snprintf(buf, sizeof (buf), "%dMB",
746 			    (int)(size / mbyte));
747 		else
748 			snprintf(buf, sizeof (buf), "%.2fMB",
749 			    (float)size / mbyte);
750 	} else {
751 		residue = size % kbyte;
752 		if (residue == 0)
753 			snprintf(buf, sizeof (buf), "%dKB",
754 			    (int)(size / kbyte));
755 		else
756 			snprintf(buf, sizeof (buf), "%.2fKB",
757 			    (float)size / kbyte);
758 	}
759 
760 	log_printf("%-10s ", buf);
761 }
762 
763 /*
764  * display platform banner
765  */
766 static int
767 display_platform_banner(picl_nodehdl_t plafh)
768 {
769 	char	*platform;
770 	char	*banner_name;
771 	int	err;
772 
773 	/*
774 	 * get PICL_PROP_MACHINE and PICL_PROP_BANNER_NAME
775 	 */
776 	log_printf(SIGN_ON_MSG);
777 	err = picldiag_get_string_propval(plafh, PICL_PROP_MACHINE,
778 	    &platform);
779 	if (err != PICL_SUCCESS)
780 		return (err);
781 	log_printf(" %s", platform);
782 	free(platform);
783 
784 	err = picldiag_get_string_propval(plafh, OBP_PROP_BANNER_NAME,
785 	    &banner_name);
786 	if (err != PICL_SUCCESS)
787 		return (err);
788 	log_printf(" %s", banner_name);
789 	free(banner_name);
790 
791 	log_printf("\n");
792 	return (PICL_SUCCESS);
793 }
794 
795 static int
796 serialnum_callback(picl_nodehdl_t serialh, void *arg)
797 {
798 	int		*countp = arg;
799 	int		err;
800 	picl_nodehdl_t	fruph;
801 	char		*buf;
802 
803 	err = picl_get_propval_by_name(serialh, PICL_REFPROP_FRU_PARENT,
804 	    &fruph, sizeof (fruph));
805 	if (err == PICL_PROPNOTFOUND) {
806 		err = picl_get_propval_by_name(serialh,
807 		    PICL_REFPROP_LOC_PARENT, &fruph, sizeof (fruph));
808 	}
809 	if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE)
810 		return (PICL_WALK_CONTINUE);
811 	if (err != PICL_SUCCESS)
812 		return (err);
813 
814 	err = picldiag_get_string_propval(serialh,
815 	    PICL_PROP_SERIAL_NUMBER, &buf);
816 	if (err == PICL_SUCCESS)	{
817 		log_printf("\n");
818 		log_printf(SERIAL_NUM_MSG);
819 		log_printf("----------------------\n");
820 		log_printf("%s\n", buf);
821 		free(buf);
822 		return (PICL_WALK_TERMINATE);
823 	}
824 	return (err);
825 }
826 
827 /*
828  * display the chassis serial number
829  */
830 static int
831 display_serial_number(picl_nodehdl_t plafh)
832 {
833 	int		print_header;
834 
835 	picl_walk_tree_by_class(plafh, PICL_CLASS_CHASSIS_SERIAL_NUM,
836 	    &print_header, serialnum_callback);
837 	return (PICL_SUCCESS);
838 }
839 
840 /*
841  * display the clock frequency
842  */
843 static int
844 display_system_clock(picl_nodehdl_t plafh)
845 {
846 	uint32_t	system_clk;
847 	int		err;
848 
849 	err = picldiag_get_clock_freq(plafh, &system_clk);
850 	if (err != PICL_SUCCESS)
851 		return (err);
852 
853 	log_printf(SYSCLK_FREQ_MSG, system_clk);
854 
855 	return (PICL_SUCCESS);
856 }
857 
858 /*
859  * callback function to display the memory size
860  */
861 /*ARGSUSED*/
862 static int
863 memory_callback(picl_nodehdl_t memh, void *args)
864 {
865 	uint64_t	mem_size;
866 	int		err;
867 
868 	log_printf(MEM_SIZE_MSG);
869 	mem_size = picldiag_get_uint_propval(memh, PICL_PROP_SIZE, &err);
870 	if (err == PICL_SUCCESS)
871 		logprintf_size(mem_size);
872 	log_printf("\n");
873 	no_xfer_size = 0;
874 	mem_xfersize = picldiag_get_uint_propval(memh, PICL_PROP_TRANSFER_SIZE,
875 	    &err);
876 	if (err == PICL_PROPNOTFOUND)
877 		no_xfer_size = 1;
878 	return (PICL_WALK_TERMINATE);
879 }
880 
881 /*
882  * callback function to print cpu information
883  */
884 /*ARGSUSED*/
885 static int
886 cpu_callback(picl_nodehdl_t nodeh, void *args)
887 {
888 	int		err;
889 	int		id;
890 	uint64_t 	uintval;
891 	uint32_t	freq;
892 	char		*impl_name;
893 	char		*status;
894 	picl_prophdl_t	parenth;
895 	char		*label;
896 
897 	/*
898 	 * If no ID is found, return
899 	 */
900 	id = picldiag_get_uint_propval(nodeh, PICL_PROP_ID, &err);
901 	if (err == PICL_PROPNOTFOUND)
902 		return (PICL_WALK_CONTINUE);
903 	else if (err != PICL_SUCCESS)
904 		return (err);
905 	log_printf("%-3d  ", id);
906 
907 	/*
908 	 * If no freq is found, return
909 	 */
910 	err = picldiag_get_clock_freq(nodeh, &freq);
911 	if (err == PICL_PROPNOTFOUND)
912 		return (PICL_WALK_CONTINUE);
913 	else if (err != PICL_SUCCESS)
914 		return (err);
915 	log_printf("%4d MHz  ", freq);
916 
917 	/* Ecache size */
918 	uintval = picldiag_get_uint_propval(nodeh, OBP_PROP_ECACHE_SIZE, &err);
919 	if (err == PICL_PROPNOTFOUND)
920 		log_printf(" -          ");
921 	else if (err == PICL_SUCCESS)
922 		logprintf_size(uintval);
923 	else
924 		return (err);
925 
926 	/* Implementation */
927 	impl_name = NULL;
928 	err = picldiag_get_string_propval(nodeh, PICL_PROP_NAME, &impl_name);
929 	if (err != PICL_SUCCESS)
930 		log_printf("  <unknown>           ");
931 	else
932 		log_printf(" %-22s ", impl_name);
933 
934 	/* CPU Mask */
935 	uintval = picldiag_get_uint_propval(nodeh, OBP_PROP_MASK, &err);
936 	if (err == PICL_PROPNOTFOUND)
937 		log_printf("  -     ");
938 	else if (err == PICL_SUCCESS)
939 		log_printf("%2lld.%-2lld   ", (uintval >> 4) & 0xf,
940 		    uintval & 0xf);
941 	else
942 		return (err);
943 
944 	/*
945 	 * Status - if the node has a status property then display that
946 	 * otherwise display the State property
947 	 */
948 	err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
949 	if (err == PICL_SUCCESS) {
950 		log_printf("%-12s", status);
951 		set_exit_code(status);
952 		free(status);
953 	} else if (err != PICL_PROPNOTFOUND && err !=
954 	    PICL_PROPVALUNAVAILABLE && err != PICL_ENDOFLIST) {
955 		return (err);
956 	} else {
957 		err = picldiag_get_string_propval(nodeh,
958 		    PICL_PROP_STATE, &status);
959 		if (err == PICL_SUCCESS) {
960 			log_printf("%-12s", status);
961 			set_exit_code(status);
962 			free(status);
963 		} else if (err != PICL_PROPNOTFOUND && err !=
964 		    PICL_PROPVALUNAVAILABLE && err !=
965 		    PICL_ENDOFLIST) {
966 			return (err);
967 		} else {
968 			log_printf("unknown    ");
969 		}
970 	}
971 
972 	/*
973 	 * Location: use label of fru parent
974 	 */
975 	err = picldiag_get_fru_parent(nodeh, &parenth);
976 	if (err == PICL_PROPNOTFOUND) {
977 		log_printf(" -      ");
978 	} else if (err == PICL_SUCCESS) {
979 		err = picldiag_get_combined_label(parenth, &label, 12);
980 		if (err == PICL_PROPNOTFOUND)
981 			log_printf(" -      ");
982 		else if (err == PICL_SUCCESS) {
983 			log_printf("%s", label);
984 			free(label);
985 		} else
986 			return (err);
987 	} else
988 		return (err);
989 
990 	log_printf("\n");
991 	return (PICL_WALK_CONTINUE);
992 }
993 
994 /*
995  * display cpu information
996  */
997 static int
998 display_cpu_info(picl_nodehdl_t plafh)
999 {
1000 	int	err;
1001 
1002 	/*
1003 	 * Display the table header for CPUs . Then display the CPU
1004 	 * frequency, cache size, and processor revision  on all the boards.
1005 	 */
1006 	logprintf_header(dgettext(TEXT_DOMAIN, "CPUs"), DEFAULT_LINE_WIDTH);
1007 	log_printf("               E$          CPU                    "
1008 		"CPU\n");
1009 	log_printf("CPU  Freq      Size        Implementation         "
1010 		"Mask    Status      Location\n");
1011 	log_printf("---  --------  ----------  ---------------------  "
1012 		"-----   ------      --------\n");
1013 
1014 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
1015 	    cpu_callback);
1016 	return (err);
1017 }
1018 
1019 /*
1020  * Inserts an io_card structure into the list.
1021  */
1022 static void
1023 add_io_card(uint32_t board, uint32_t bus_id, uint32_t slot, char *label,
1024     uint32_t freq, char *name, char *model, char *status, char *devfs_path)
1025 {
1026 	struct io_card card;
1027 
1028 	card.display = 1;
1029 	card.board = board;
1030 	switch (bus_id) {
1031 	case SBUS_TYPE:
1032 		strlcpy(card.bus_type, SBUS_NAME, MAXSTRLEN);
1033 		break;
1034 	case PCI_TYPE:
1035 		strlcpy(card.bus_type, PCI_NAME, MAXSTRLEN);
1036 		break;
1037 	case PCIEX_TYPE:
1038 		strlcpy(card.bus_type, PCIEX_NAME, MAXSTRLEN);
1039 		break;
1040 	case UPA_TYPE:
1041 		strlcpy(card.bus_type, UPA_NAME, MAXSTRLEN);
1042 		break;
1043 	default: /* won't reach here */
1044 		strlcpy(card.bus_type, "", MAXSTRLEN);
1045 		break;
1046 	}
1047 	if (label == NULL)
1048 		card.slot = slot;
1049 	else {
1050 		card.slot = PCI_SLOT_IS_STRING;
1051 		(void) strlcpy(card.slot_str, label, MAXSTRLEN);
1052 	}
1053 	card.freq = freq;
1054 	card.status[0] = '\0';
1055 	card.name[0] = '\0';
1056 	card.model[0] = '\0';
1057 	card.notes[0] = '\0';
1058 	if (status != NULL)
1059 		strlcpy(card.status, status, MAXSTRLEN);
1060 	if (name != NULL)
1061 		strlcpy(card.name, name, MAXSTRLEN);
1062 	if (model != NULL)
1063 		strlcpy(card.model, model, MAXSTRLEN);
1064 	if (status != NULL)
1065 		strlcpy(card.status, status, MAXSTRLEN);
1066 	if (devfs_path != NULL)
1067 		strlcpy(card.notes, devfs_path, MAXSTRLEN);
1068 
1069 	io_card_list = insert_io_card(io_card_list, &card);
1070 }
1071 
1072 static void
1073 append_to_bank_list(bank_list_t *newptr)
1074 {
1075 	bank_list_t	*ptr;
1076 
1077 	if (mem_banks == NULL) {
1078 		mem_banks = newptr;
1079 		return;
1080 	}
1081 	ptr = mem_banks;
1082 	while (ptr->next != NULL)
1083 		ptr = ptr->next;
1084 
1085 	ptr->next = newptr;
1086 }
1087 
1088 static void
1089 free_bank_list(void)
1090 {
1091 	bank_list_t	*ptr;
1092 	bank_list_t	*tmp;
1093 
1094 	for (ptr = mem_banks; ptr != NULL; ptr = tmp) {
1095 		tmp = ptr->next;
1096 		free(ptr);
1097 	}
1098 	mem_banks = NULL;
1099 }
1100 
1101 
1102 /*
1103  * print label for memory module
1104  */
1105 static int
1106 logprintf_memory_module_label(picl_nodehdl_t moduleh)
1107 {
1108 	picl_nodehdl_t	fruparenth;
1109 	int		err;
1110 	char		*label;
1111 
1112 	err = picldiag_get_fru_parent(moduleh, &fruparenth);
1113 	if (err == PICL_PROPNOTFOUND) {
1114 		log_printf("-");
1115 		return (PICL_SUCCESS);
1116 	} else if (err != PICL_SUCCESS)
1117 		return (err);
1118 
1119 	err = picldiag_get_combined_label(fruparenth, &label, 30);
1120 	if (err == PICL_PROPNOTFOUND)
1121 		log_printf("-");
1122 	else if (err == PICL_SUCCESS) {
1123 		log_printf("%-15s", label);
1124 		free(label);
1125 	} else
1126 		return (err);
1127 
1128 	return (PICL_SUCCESS);
1129 }
1130 
1131 /*
1132  * print the bank id and add the bank handle in the bank list
1133  * return the head of the bank list
1134  */
1135 static int
1136 membank_callback(picl_nodehdl_t bankh, void *args)
1137 {
1138 	int		err;
1139 	int64_t		id;
1140 	uint64_t	match;
1141 	uint64_t	mask;
1142 	int		i;
1143 	bank_list_t	*newptr;
1144 	seg_info_t	*segp = args;
1145 
1146 	/*
1147 	 * print the bank id in the segment table contains column
1148 	 */
1149 	id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
1150 	if (segp->bank_count > 0)
1151 		log_printf(",");
1152 	if (err == PICL_PROPNOTFOUND)
1153 		log_printf("-");
1154 	else if (err == PICL_SUCCESS)
1155 		log_printf("%-lld", id);
1156 	else
1157 		return (err);
1158 	segp->bank_count++;
1159 
1160 	/*
1161 	 * Save the bank information for later (print_bank_table)
1162 	 */
1163 	newptr = malloc(sizeof (*newptr));
1164 	if (newptr == NULL)
1165 		return (PICL_FAILURE);
1166 
1167 	newptr->nodeh = bankh;
1168 	newptr->iway_count = 0;
1169 	newptr->next = NULL;
1170 	append_to_bank_list(newptr);
1171 
1172 	/*
1173 	 * Compute the way numbers for the bank
1174 	 */
1175 	if (no_xfer_size)
1176 		return (PICL_WALK_CONTINUE);
1177 
1178 	match = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMATCH, &err);
1179 	if (err == PICL_PROPNOTFOUND)
1180 		return (PICL_WALK_CONTINUE);
1181 	else if (err != PICL_SUCCESS)
1182 		return (err);
1183 
1184 	mask = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMASK, &err);
1185 	if (err == PICL_PROPNOTFOUND)
1186 		return (PICL_WALK_CONTINUE);
1187 	else if (err != PICL_SUCCESS)
1188 		return (err);
1189 
1190 	i = 0;
1191 	while ((i < segp->ifactor) && (newptr->iway_count < MAX_IWAYS)) {
1192 		if (((segp->base + i * mem_xfersize) & mask) == match)
1193 			newptr->iway[newptr->iway_count++] = i;
1194 		++i;
1195 	}
1196 	return (PICL_WALK_CONTINUE);
1197 }
1198 
1199 
1200 /*
1201  * find the memory bank and add the bank handle in the bank list
1202  * return the head of the bank list
1203  */
1204 static int
1205 logprintf_bankinfo(picl_nodehdl_t segh, seg_info_t *segp)
1206 {
1207 	int		err;
1208 
1209 	log_printf("BankIDs ");
1210 	/*
1211 	 * find memory-bank
1212 	 */
1213 	segp->bank_count = 0;
1214 	err = picl_walk_tree_by_class(segh, PICL_CLASS_MEMORY_BANK, segp,
1215 	    membank_callback);
1216 	log_printf("\n");
1217 	return (err);
1218 }
1219 
1220 /*
1221  * print the label of memory module or the memory module bank ids
1222  */
1223 static int
1224 logprintf_seg_contains_col(picl_nodehdl_t nodeh, seg_info_t *segp)
1225 {
1226 	picl_nodehdl_t	moduleh;
1227 	int		err;
1228 
1229 	/*
1230 	 * find memory-module if referenced directly from the memory-segment
1231 	 * (ie no memory banks)
1232 	 */
1233 	err = picl_get_propval_by_name(nodeh, PICL_REFPROP_MEMORY_MODULE,
1234 	    &moduleh, sizeof (moduleh));
1235 	if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
1236 		return (err);
1237 	if (err == PICL_SUCCESS) {
1238 		err = logprintf_memory_module_label(moduleh);
1239 		log_printf("\n");
1240 		return (err);
1241 	}
1242 
1243 	/*
1244 	 * memory-module not referenced directly from the memory segment
1245 	 * so list memory banks instead
1246 	 */
1247 	err = logprintf_bankinfo(nodeh, segp);
1248 	return (err);
1249 }
1250 
1251 /*
1252  * find all memory modules under the given memory module group
1253  * and print its label
1254  */
1255 static int
1256 logprintf_memory_module_group_info(picl_nodehdl_t memgrph, uint64_t mcid)
1257 {
1258 	int		err;
1259 	int64_t		id;
1260 	boolean_t	got_status;
1261 	picl_nodehdl_t	moduleh;
1262 	char		piclclass[PICL_CLASSNAMELEN_MAX];
1263 	picl_nodehdl_t	fruparenth;
1264 	char		*status;
1265 
1266 	id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID, &err);
1267 	if (err == PICL_PROPNOTFOUND)
1268 		id = -1;
1269 	else if (err != PICL_SUCCESS)
1270 		return (err);
1271 
1272 	err = picl_get_propval_by_name(memgrph, PICL_PROP_CHILD, &moduleh,
1273 	    sizeof (picl_nodehdl_t));
1274 
1275 	while (err == PICL_SUCCESS) {
1276 		/* controller id */
1277 		log_printf("%-8lld       ", mcid);
1278 
1279 		/* group id */
1280 		if (id == -1) {
1281 			log_printf("-         ");
1282 		} else {
1283 			log_printf("%-8lld ", id);
1284 		}
1285 
1286 		err = picl_get_propval_by_name(moduleh, PICL_PROP_CLASSNAME,
1287 		    piclclass, sizeof (piclclass));
1288 		if (err != PICL_SUCCESS)
1289 			return (err);
1290 
1291 		if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE) == 0) {
1292 			err = logprintf_memory_module_label(moduleh);
1293 			if (err != PICL_SUCCESS)
1294 				return (err);
1295 		}
1296 
1297 		got_status = B_FALSE;
1298 		err = picldiag_get_fru_parent(moduleh, &fruparenth);
1299 		if (err == PICL_SUCCESS) {
1300 			err = picldiag_get_string_propval(fruparenth,
1301 			    PICL_PROP_OPERATIONAL_STATUS, &status);
1302 			if (err == PICL_SUCCESS) {
1303 				got_status = B_TRUE;
1304 			} else if (err != PICL_PROPNOTFOUND)
1305 				return (err);
1306 		} else if (err != PICL_PROPNOTFOUND)
1307 			return (err);
1308 
1309 		if (!got_status) {
1310 			err = picldiag_get_string_propval(moduleh,
1311 			    PICL_PROP_STATUS, &status);
1312 			if (err == PICL_SUCCESS)
1313 				got_status = B_TRUE;
1314 			else if (err != PICL_PROPNOTFOUND)
1315 				return (err);
1316 		}
1317 		if (got_status) {
1318 			log_printf("%s", status);
1319 			set_exit_code(status);
1320 			free(status);
1321 		}
1322 		err = picl_get_propval_by_name(moduleh, PICL_PROP_PEER,
1323 		    &moduleh, sizeof (picl_nodehdl_t));
1324 
1325 		log_printf("\n");
1326 	}
1327 	if (err == PICL_PROPNOTFOUND)
1328 		return (PICL_SUCCESS);
1329 	return (err);
1330 }
1331 
1332 /*
1333  * search children to find memory module group under memory-controller
1334  */
1335 static int
1336 find_memory_module_group(picl_nodehdl_t mch, int *print_header)
1337 {
1338 	picl_nodehdl_t	memgrph;
1339 	uint64_t	mcid;
1340 	int		err;
1341 	char		piclclass[PICL_CLASSNAMELEN_MAX];
1342 
1343 	mcid = picldiag_get_uint_propval(mch, OBP_PROP_PORTID, &err);
1344 	if (err == PICL_PROPNOTFOUND)
1345 		mcid = DEFAULT_PORTID;
1346 	else if (err != PICL_SUCCESS)
1347 		return (err);
1348 
1349 	err = picl_get_propval_by_name(mch, PICL_PROP_CHILD,
1350 	    &memgrph, sizeof (picl_nodehdl_t));
1351 	while (err == PICL_SUCCESS) {
1352 		err = picl_get_propval_by_name(memgrph,
1353 		    PICL_PROP_CLASSNAME, piclclass, sizeof (piclclass));
1354 		if (err != PICL_SUCCESS)
1355 			return (err);
1356 
1357 		if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE_GROUP) == 0) {
1358 			if (*print_header == 1) {
1359 				log_printf(
1360 				    dgettext(TEXT_DOMAIN,
1361 					"\nMemory Module Groups:\n"));
1362 				log_printf("--------------------------");
1363 				log_printf("------------------------\n");
1364 				log_printf("ControllerID   GroupID  Labels");
1365 				log_printf("         Status\n");
1366 				log_printf("--------------------------");
1367 				log_printf("------------------------\n");
1368 				*print_header = 0;
1369 			}
1370 			err = logprintf_memory_module_group_info(memgrph, mcid);
1371 			if (err != PICL_SUCCESS)
1372 				return (err);
1373 		}
1374 
1375 		err = picl_get_propval_by_name(memgrph, PICL_PROP_PEER,
1376 		    &memgrph, sizeof (picl_nodehdl_t));
1377 	}
1378 	if (err == PICL_PROPNOTFOUND)
1379 		return (PICL_SUCCESS);
1380 	return (err);
1381 }
1382 
1383 /*
1384  * print memory module group table per memory-controller
1385  */
1386 static int
1387 print_memory_module_group_table(picl_nodehdl_t plafh)
1388 {
1389 	picl_nodehdl_t	mch;
1390 	int		err;
1391 	char		piclclass[PICL_CLASSNAMELEN_MAX];
1392 	int		print_header;
1393 
1394 	print_header = 1;
1395 
1396 	/*
1397 	 * find memory-controller
1398 	 */
1399 	err = picl_get_propval_by_name(plafh, PICL_PROP_CHILD, &mch,
1400 	    sizeof (picl_nodehdl_t));
1401 	while (err == PICL_SUCCESS) {
1402 		err = picl_get_propval_by_name(mch, PICL_PROP_CLASSNAME,
1403 		    piclclass, sizeof (piclclass));
1404 		if (err != PICL_SUCCESS)
1405 			return (err);
1406 
1407 		if (strcmp(piclclass, PICL_CLASS_MEMORY_CONTROLLER) != 0) {
1408 			err = print_memory_module_group_table(mch);
1409 			if (err != PICL_SUCCESS)
1410 				return (err);
1411 			err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
1412 			    &mch, sizeof (picl_nodehdl_t));
1413 			continue;
1414 		}
1415 
1416 		err = find_memory_module_group(mch, &print_header);
1417 		if (err != PICL_SUCCESS)
1418 			return (err);
1419 
1420 		err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
1421 		    &mch, sizeof (picl_nodehdl_t));
1422 	}
1423 	if (err == PICL_PROPNOTFOUND)
1424 		return (PICL_SUCCESS);
1425 
1426 	return (err);
1427 }
1428 
1429 /*
1430  * print bank table
1431  */
1432 static int
1433 print_bank_table(void)
1434 {
1435 	bank_list_t	*ptr;
1436 	picl_nodehdl_t	bankh;
1437 	picl_nodehdl_t	memgrph;
1438 	picl_nodehdl_t	mch;
1439 	int		err;
1440 	int32_t		i;
1441 	uint64_t	size;
1442 	int		id;
1443 
1444 	log_printf(dgettext(TEXT_DOMAIN, "\nBank Table:\n"));
1445 	log_printf("---------------------------------------");
1446 	log_printf("--------------------\n");
1447 	log_printf(dgettext(TEXT_DOMAIN, "           Physical Location\n"));
1448 	log_printf(dgettext(TEXT_DOMAIN, "ID       ControllerID  GroupID   "));
1449 	log_printf(dgettext(TEXT_DOMAIN, "Size       Interleave Way\n"));
1450 	log_printf("---------------------------------------");
1451 	log_printf("--------------------\n");
1452 
1453 	for (ptr = mem_banks; ptr != NULL; ptr = ptr->next) {
1454 		bankh = ptr->nodeh;
1455 		id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
1456 		if (err != PICL_SUCCESS)
1457 			log_printf("%-8s ", "-");
1458 		else
1459 			log_printf("%-8d ", id);
1460 
1461 		/* find memory-module-group */
1462 		err = picl_get_propval_by_name(bankh,
1463 		    PICL_REFPROP_MEMORY_MODULE_GROUP, &memgrph,
1464 		    sizeof (memgrph));
1465 		if (err == PICL_PROPNOTFOUND) {
1466 			log_printf("%-8s      ", "-");
1467 			log_printf("%-8s  ", "-");
1468 		} else if (err != PICL_SUCCESS)
1469 			return (err);
1470 		else {
1471 			/*
1472 			 * get controller id
1473 			 */
1474 			err = picl_get_propval_by_name(memgrph,
1475 			    PICL_PROP_PARENT, &mch, sizeof (picl_nodehdl_t));
1476 			if (err != PICL_SUCCESS)
1477 				return (err);
1478 
1479 			id = picldiag_get_uint_propval(mch, OBP_PROP_PORTID,
1480 			    &err);
1481 			if (err == PICL_PROPNOTFOUND)
1482 				id = DEFAULT_PORTID; /* use default */
1483 			else if (err != PICL_SUCCESS)
1484 				return (err);
1485 
1486 			log_printf("%-8d      ", id);
1487 
1488 			/* get group id */
1489 			id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID,
1490 			    &err);
1491 			if (err == PICL_PROPNOTFOUND)
1492 				log_printf("-          ");
1493 			else if (err == PICL_SUCCESS)
1494 				log_printf("%-8d  ", id);
1495 			else
1496 				return (err);
1497 		}
1498 
1499 		size = picldiag_get_uint_propval(bankh, PICL_PROP_SIZE, &err);
1500 		if (err == PICL_PROPNOTFOUND)
1501 			log_printf("-        	 ");
1502 		else if (err == PICL_SUCCESS)
1503 			logprintf_size(size);
1504 		else
1505 			return (err);
1506 
1507 		log_printf("     ");
1508 		for (i = 0; i < ptr->iway_count; i++) {
1509 			if (i != 0)
1510 				log_printf(",");
1511 			log_printf("%d", ptr->iway[i]);
1512 		}
1513 
1514 		log_printf("\n");
1515 	}
1516 	return (PICL_SUCCESS);
1517 }
1518 
1519 /*
1520  * callback function to print segment, add the bank in the list and
1521  * return the bank list
1522  */
1523 /* ARGSUSED */
1524 static int
1525 memseg_callback(picl_nodehdl_t segh, void *args)
1526 {
1527 	seg_info_t	seginfo;
1528 	int		err;
1529 
1530 	/* get base address */
1531 	seginfo.base = picldiag_get_uint_propval(segh, PICL_PROP_BASEADDRESS,
1532 	    &err);
1533 	if (err == PICL_PROPNOTFOUND) {
1534 		log_printf("-\n");
1535 		return (PICL_WALK_CONTINUE);
1536 	} else if (err == PICL_SUCCESS)
1537 		log_printf("0x%-16llx ", seginfo.base);
1538 	else
1539 		return (err);
1540 
1541 	/* get size */
1542 	seginfo.size = picldiag_get_uint_propval(segh, PICL_PROP_SIZE, &err);
1543 	if (err == PICL_PROPNOTFOUND) {
1544 		log_printf("-\n");
1545 		return (PICL_WALK_CONTINUE);
1546 	} else if (err == PICL_SUCCESS)
1547 		logprintf_size(seginfo.size);
1548 	else
1549 		return (err);
1550 
1551 	/* get interleave factor */
1552 	seginfo.ifactor = picldiag_get_uint_propval(segh,
1553 	    PICL_PROP_INTERLEAVE_FACTOR, &err);
1554 
1555 	if (err == PICL_PROPNOTFOUND) {
1556 		log_printf("       -\n");
1557 		return (PICL_WALK_CONTINUE);
1558 	} else if (err == PICL_SUCCESS)
1559 		log_printf("       %-2d          ", seginfo.ifactor);
1560 	else
1561 		return (err);
1562 
1563 	seginfo.bank_count = 0;
1564 	err = logprintf_seg_contains_col(segh, &seginfo);
1565 	if (err != PICL_SUCCESS)
1566 		return (err);
1567 	return (PICL_WALK_CONTINUE);
1568 }
1569 
1570 /*
1571  * search children to find memory-segment and set up the bank list
1572  */
1573 static int
1574 find_segments(picl_nodehdl_t plafh)
1575 {
1576 	int		err;
1577 
1578 	log_printf(dgettext(TEXT_DOMAIN, "Segment Table:\n"));
1579 	log_printf("------------------------------");
1580 	log_printf("-----------------------------------------\n");
1581 	log_printf(dgettext(TEXT_DOMAIN, "Base Address       Size       "));
1582 	log_printf(dgettext(TEXT_DOMAIN, "Interleave Factor  Contains\n"));
1583 	log_printf("------------------------------");
1584 	log_printf("-----------------------------------------\n");
1585 
1586 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
1587 	    NULL, memseg_callback);
1588 	return (err);
1589 }
1590 
1591 /*
1592  * display memory configuration
1593  */
1594 static int
1595 display_memory_config(picl_nodehdl_t plafh)
1596 {
1597 	int		err;
1598 
1599 	logprintf_header(dgettext(TEXT_DOMAIN, "Memory Configuration"),
1600 	    DEFAULT_LINE_WIDTH);
1601 
1602 	mem_banks = NULL;
1603 	err = find_segments(plafh);
1604 
1605 	if ((err == PICL_SUCCESS) && (mem_banks != NULL))
1606 		print_bank_table();
1607 
1608 	free_bank_list();
1609 
1610 	return (print_memory_module_group_table(plafh));
1611 }
1612 
1613 /*
1614  * print the hub device
1615  */
1616 static int
1617 logprintf_hub_devices(picl_nodehdl_t hubh)
1618 {
1619 	char		*name;
1620 	int		portnum;
1621 	char		*labelp;
1622 	picl_nodehdl_t	parenth;
1623 	int		err;
1624 
1625 	err = picldiag_get_string_propval(hubh, PICL_PROP_NAME, &name);
1626 	if (err != PICL_SUCCESS)
1627 		return (err);
1628 	log_printf("%-12.12s  ", name);
1629 	free(name);
1630 
1631 	err = picl_get_propval_by_name(hubh, PICL_REFPROP_LOC_PARENT, &parenth,
1632 	    sizeof (picl_nodehdl_t));
1633 
1634 	if (err == PICL_SUCCESS) {
1635 		/* Read the Label */
1636 		err = picldiag_get_label(parenth, &labelp);
1637 		if (err == PICL_SUCCESS) {
1638 			log_printf("%s\n", labelp);
1639 			free(labelp);
1640 			return (PICL_SUCCESS);
1641 		} else if (err != PICL_PROPNOTFOUND) {
1642 			log_printf("\n");
1643 			return (err);
1644 		}
1645 	} else if (err != PICL_PROPNOTFOUND) {
1646 		log_printf("\n");
1647 		return (err);
1648 	}
1649 
1650 	/* No Label, try the reg */
1651 	err = picl_get_propval_by_name(hubh, OBP_PROP_REG, &portnum,
1652 	    sizeof (portnum));
1653 	if (err == PICL_PROPNOTFOUND)
1654 		log_printf("  -\n");
1655 	else if (err != PICL_SUCCESS) {
1656 		log_printf("\n");
1657 		return (err);
1658 	} else
1659 		log_printf("%3d\n", portnum);
1660 
1661 	return (PICL_SUCCESS);
1662 }
1663 
1664 /*
1665  * callback functions to display hub devices
1666  */
1667 /* ARGSUSED */
1668 static int
1669 print_usb_devices(picl_nodehdl_t hubh, void *arg)
1670 {
1671 	picl_nodehdl_t	chdh;
1672 	char		*rootname;
1673 	int		type = *(int *)arg;
1674 	int		hubnum;
1675 	int		err;
1676 
1677 	err = picl_get_propval_by_name(hubh, PICL_PROP_CHILD, &chdh,
1678 	    sizeof (picl_nodehdl_t));
1679 
1680 	/* print header */
1681 	if (err == PICL_SUCCESS) {
1682 		err = picldiag_get_string_propval(hubh, PICL_PROP_NAME,
1683 		    &rootname);
1684 		if (err != PICL_SUCCESS)
1685 			return (err);
1686 
1687 		if (type == USB) {
1688 			log_printf("\n===============================");
1689 			log_printf(dgettext(TEXT_DOMAIN,
1690 			    " %s Devices "), rootname);
1691 		} else {
1692 			/* Get its hub number */
1693 			err = picl_get_propval_by_name(hubh,
1694 			    OBP_PROP_REG, &hubnum, sizeof (hubnum));
1695 			if ((err != PICL_SUCCESS) &&
1696 			    (err != PICL_PROPNOTFOUND)) {
1697 				free(rootname);
1698 				return (err);
1699 			}
1700 
1701 			log_printf("\n===============================");
1702 			if (err == PICL_SUCCESS)
1703 				log_printf(dgettext(TEXT_DOMAIN,
1704 				    " %s#%d Devices "),
1705 				    rootname, hubnum);
1706 			else
1707 				log_printf(dgettext(TEXT_DOMAIN,
1708 				    " %s Devices "), rootname);
1709 		}
1710 
1711 		log_printf("===============================\n\n");
1712 		log_printf("Name          Port#\n");
1713 		log_printf("------------  -----\n");
1714 		free(rootname);
1715 
1716 		do {
1717 			logprintf_hub_devices(chdh);
1718 
1719 			err = picl_get_propval_by_name(chdh, PICL_PROP_PEER,
1720 			    &chdh, sizeof (picl_nodehdl_t));
1721 		} while (err == PICL_SUCCESS);
1722 	}
1723 
1724 
1725 	if (err == PICL_PROPNOTFOUND)
1726 		return (PICL_WALK_CONTINUE);
1727 	return (err);
1728 }
1729 
1730 /*
1731  * callback functions to display usb devices
1732  */
1733 /* ARGSUSED */
1734 static int
1735 usb_callback(picl_nodehdl_t usbh, void *args)
1736 {
1737 	int		err;
1738 	int		type;
1739 
1740 	type = USB;
1741 	err = print_usb_devices(usbh, &type);
1742 	if (err != PICL_WALK_CONTINUE)
1743 		return (err);
1744 	type = HUB;
1745 	err = picl_walk_tree_by_class(usbh, NULL, &type, print_usb_devices);
1746 	if (err == PICL_SUCCESS)
1747 		err = PICL_WALK_CONTINUE;
1748 	return (err);
1749 }
1750 
1751 
1752 /*
1753  * find usb devices and print its information
1754  */
1755 static int
1756 display_usb_devices(picl_nodehdl_t plafh)
1757 {
1758 	int err;
1759 
1760 	/*
1761 	 * get the usb node
1762 	 */
1763 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_USB, NULL,
1764 	    usb_callback);
1765 	return (err);
1766 }
1767 
1768 
1769 
1770 /*
1771  * If nodeh is the io device, add it into the io list and return
1772  * If it is not an io device and it has the subtree, traverse the subtree
1773  * and add all leaf io devices
1774  */
1775 static int
1776 add_io_leaves(picl_nodehdl_t nodeh, char *parentname, uint32_t board,
1777     uint32_t bus_id, uint64_t slot, uint32_t freq, char *model, char *status)
1778 {
1779 	picl_nodehdl_t	childh;
1780 	picl_prophdl_t	proph;
1781 	picl_propinfo_t	pinfo;
1782 	int		err;
1783 	char		*nameval;
1784 	char		piclclass[PICL_CLASSNAMELEN_MAX];
1785 	char		nodename[MAXSTRLEN];
1786 	char		name[MAXSTRLEN];
1787 	char		*devfs_path;
1788 	char		*compatible;
1789 	picl_nodehdl_t	fruparenth;
1790 	char		*label;
1791 	char		binding_name[MAXSTRLEN];
1792 
1793 	err = picl_get_propinfo_by_name(nodeh, PICL_PROP_NAME, &pinfo,
1794 	    &proph);
1795 	if (err != PICL_SUCCESS)
1796 		return (err);
1797 
1798 	nameval = alloca(pinfo.size);
1799 	if (nameval == NULL)
1800 		return (PICL_FAILURE);
1801 
1802 	err = picl_get_propval(proph, nameval, pinfo.size);
1803 	if (err != PICL_SUCCESS)
1804 		return (err);
1805 
1806 	(void) strlcpy(nodename, nameval, MAXSTRLEN);
1807 
1808 	err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
1809 	    piclclass, sizeof (piclclass));
1810 	if (err != PICL_SUCCESS)
1811 		return (err);
1812 
1813 	/* if binding_name is found, name will be <nodename>-<binding_name> */
1814 	err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
1815 	    binding_name, sizeof (binding_name));
1816 	if (err == PICL_PROPNOTFOUND) {
1817 		/*
1818 		 * if compatible prop is found, name will be
1819 		 * <nodename>-<compatible>
1820 		 */
1821 		err = picldiag_get_first_compatible_value(nodeh, &compatible);
1822 		if (err == PICL_SUCCESS) {
1823 			strlcat(nodename, "-", MAXSTRLEN);
1824 			strlcat(nodename, compatible, MAXSTRLEN);
1825 			free(compatible);
1826 		} else if (err != PICL_PROPNOTFOUND) {
1827 			return (err);
1828 		}
1829 	} else if (err != PICL_SUCCESS) {
1830 		return (err);
1831 	} else if (strcmp(nodename, binding_name) != 0) {
1832 		if (strcmp(nodename, piclclass) == 0) {
1833 			/*
1834 			 * nodename same as binding name -
1835 			 * no need to display twice
1836 			 */
1837 			strlcpy(nodename, binding_name, MAXSTRLEN);
1838 		} else {
1839 			strlcat(nodename, "-", MAXSTRLEN);
1840 			strlcat(nodename, binding_name, MAXSTRLEN);
1841 		}
1842 	}
1843 
1844 	/*
1845 	 * If it is an immediate child under pci/pciex/sbus/upa and not
1846 	 * a bus node, add it to the io list.
1847 	 * If it is a child under sub-bus and it is in an io
1848 	 * device, add it to the io list.
1849 	 */
1850 	if (((parentname == NULL) && (!is_bus(piclclass))) ||
1851 	    ((parentname != NULL) && (is_io_device(piclclass)))) {
1852 		if (parentname == NULL)
1853 			(void) snprintf(name, MAXSTRLEN, "%s", nodename);
1854 		else
1855 			(void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
1856 			    nodename);
1857 
1858 		/*
1859 		 * append the class if its class is not a generic
1860 		 * obp-device class
1861 		 */
1862 		if (strcmp(piclclass, PICL_CLASS_OBP_DEVICE))
1863 			(void) snprintf(name, MAXSTRLEN, "%s (%s)", name,
1864 			    piclclass);
1865 
1866 		err = picldiag_get_fru_parent(nodeh, &fruparenth);
1867 		if (err == PICL_PROPNOTFOUND) {
1868 			label = NULL;
1869 		} else if (err != PICL_SUCCESS) {
1870 			return (err);
1871 		} else {
1872 			err = picldiag_get_combined_label(fruparenth, &label,
1873 			    15);
1874 			if (err == PICL_PROPNOTFOUND)
1875 				label = NULL;
1876 			else if (err != PICL_SUCCESS)
1877 				return (err);
1878 		}
1879 		/* devfs-path */
1880 		err =  picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH,
1881 		    &devfs_path);
1882 		if (err == PICL_PROPNOTFOUND)
1883 			devfs_path = NULL;
1884 		else if (err != PICL_SUCCESS)
1885 			return (err);
1886 
1887 		add_io_card(board, bus_id, slot, label, freq, name,
1888 		    model, status, devfs_path);
1889 		if (label != NULL)
1890 			free(label);
1891 		if (devfs_path != NULL)
1892 			free(devfs_path);
1893 		return (PICL_SUCCESS);
1894 	}
1895 
1896 	/*
1897 	 * If there is any child, Go through each child.
1898 	 */
1899 
1900 	err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
1901 	    &childh, sizeof (picl_nodehdl_t));
1902 
1903 	/* there is a child */
1904 	while (err == PICL_SUCCESS) {
1905 		if (parentname == NULL)
1906 			(void) strlcpy(name, nodename, MAXSTRLEN);
1907 		else
1908 			(void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
1909 			    nodename);
1910 
1911 		err = add_io_leaves(childh, name, board, bus_id, slot, freq,
1912 		    model, status);
1913 		if (err != PICL_SUCCESS)
1914 			return (err);
1915 		/*
1916 		 * get next child
1917 		 */
1918 		err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
1919 		    &childh, sizeof (picl_nodehdl_t));
1920 	}
1921 
1922 	if (err == PICL_PROPNOTFOUND)
1923 		return (PICL_SUCCESS);
1924 	return (err);
1925 }
1926 
1927 /*
1928  * callback function to add all io devices under sbus in io list
1929  */
1930 /*ARGSUSED*/
1931 static int
1932 sbus_callback(picl_nodehdl_t sbush, void *args)
1933 {
1934 	picl_nodehdl_t	nodeh;
1935 	int		err;
1936 	uint32_t	boardnum;
1937 	uint32_t	bus_id;
1938 	uint32_t	slot;
1939 	uint32_t	freq;
1940 	char		*model;
1941 	char		*status;
1942 
1943 	/* Fill in common infomation */
1944 	bus_id = SBUS_TYPE;
1945 
1946 	err = picldiag_get_clock_freq(sbush, &freq);
1947 	if (err == PICL_PROPNOTFOUND)
1948 		return (PICL_WALK_CONTINUE);
1949 	else if (err != PICL_SUCCESS)
1950 		return (err);
1951 	/*
1952 	 * If no board# is found, set boardnum to 0
1953 	 */
1954 	boardnum = picldiag_get_uint_propval(sbush, OBP_PROP_BOARD_NUM, &err);
1955 	if (err == PICL_PROPNOTFOUND)
1956 		boardnum = DEFAULT_BOARD_NUM;
1957 	else if (err != PICL_SUCCESS)
1958 		return (err);
1959 
1960 	err = picl_get_propval_by_name(sbush, PICL_PROP_CHILD, &nodeh,
1961 	    sizeof (picl_nodehdl_t));
1962 
1963 	while (err == PICL_SUCCESS) {
1964 		slot = picldiag_get_uint_propval(nodeh,
1965 		    PICL_PROP_SLOT, &err);
1966 		if (err == PICL_PROPNOTFOUND) {
1967 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
1968 			    &nodeh, sizeof (picl_nodehdl_t));
1969 			continue;
1970 		} else if (err != PICL_SUCCESS)
1971 			return (err);
1972 
1973 		err =  picldiag_get_string_propval(nodeh, OBP_PROP_MODEL,
1974 		    &model);
1975 		if (err == PICL_PROPNOTFOUND)
1976 			model = NULL;
1977 		else if (err != PICL_SUCCESS)
1978 			return (err);
1979 
1980 		err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS,
1981 		    &status);
1982 		if (err == PICL_PROPNOTFOUND) {
1983 			status = malloc(5);
1984 			if (status == NULL)
1985 				return (PICL_FAILURE);
1986 			strncpy(status, "okay", 5);
1987 		} else if (err != PICL_SUCCESS)
1988 			return (err);
1989 
1990 		err = add_io_leaves(nodeh, NULL, boardnum, bus_id, slot, freq,
1991 		    model, status);
1992 		if (model != NULL)
1993 			free(model);
1994 		if (status != NULL)
1995 			free(status);
1996 		if (err != PICL_SUCCESS)
1997 			return (err);
1998 
1999 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
2000 		    sizeof (picl_nodehdl_t));
2001 	}
2002 	if (err == PICL_PROPNOTFOUND)
2003 		return (PICL_WALK_CONTINUE);
2004 	return (err);
2005 }
2006 
2007 /*
2008  * add all io devices under pci/pciex in io list
2009  */
2010 /* ARGSUSED */
2011 static int
2012 pci_pciex_callback(picl_nodehdl_t pcih, void *args)
2013 {
2014 	picl_nodehdl_t	nodeh;
2015 	int		err;
2016 	char		piclclass[PICL_CLASSNAMELEN_MAX];
2017 	uint32_t	boardnum;
2018 	uint32_t	bus_id;
2019 	uint32_t	slot;
2020 	uint32_t	freq;
2021 	char		*model;
2022 	char		*status;
2023 
2024 	if (strcmp(args, PICL_CLASS_PCIEX) == 0)
2025 		bus_id = PCIEX_TYPE;
2026 	else
2027 		bus_id = PCI_TYPE;
2028 
2029 	/*
2030 	 * Check if it has the freq, if not,
2031 	 * If not, use its parent's freq
2032 	 * if its parent's freq is not found, return
2033 	 */
2034 	err = picldiag_get_clock_freq(pcih, &freq);
2035 	if (err == PICL_PROPNOTFOUND) {
2036 		err = picldiag_get_clock_from_parent(pcih, &freq);
2037 		if (err == PICL_PROPNOTFOUND)
2038 			return (PICL_WALK_CONTINUE);
2039 		else if (err != PICL_SUCCESS)
2040 			return (err);
2041 	} else if (err != PICL_SUCCESS)
2042 		return (err);
2043 
2044 	/*
2045 	 * If no board# is found, set boardnum to 0
2046 	 */
2047 	boardnum = picldiag_get_uint_propval(pcih, OBP_PROP_BOARD_NUM, &err);
2048 	if (err == PICL_PROPNOTFOUND)
2049 		boardnum = DEFAULT_BOARD_NUM;
2050 	else if (err != PICL_SUCCESS)
2051 		return (err);
2052 
2053 	/* Walk through the children */
2054 
2055 	err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
2056 	    sizeof (picl_nodehdl_t));
2057 	while (err == PICL_SUCCESS) {
2058 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2059 		    piclclass, sizeof (piclclass));
2060 		if (err != PICL_SUCCESS)
2061 			return (err);
2062 
2063 		/*
2064 		 * Skip PCIEX, PCI bridge and USB devices because they will be
2065 		 * processed later
2066 		 */
2067 		if ((strcmp(piclclass, PICL_CLASS_PCI) == 0) ||
2068 		    (strcmp(piclclass, PICL_CLASS_PCIEX) == 0) ||
2069 		    (strcmp(piclclass, PICL_CLASS_USB) == 0)) {
2070 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
2071 			    &nodeh, sizeof (picl_nodehdl_t));
2072 			continue;
2073 		}
2074 
2075 		/* Get the device id for pci card */
2076 		slot = picldiag_get_uint_propval(nodeh,
2077 		    PICL_PROP_DEVICE_ID, &err);
2078 		if (err == PICL_PROPNOTFOUND) {
2079 			err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
2080 			    &nodeh, sizeof (picl_nodehdl_t));
2081 			continue;
2082 		} else if (err != PICL_SUCCESS)
2083 			return (err);
2084 
2085 		/* Get the model of this card */
2086 		err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL,
2087 		    &model);
2088 		if (err == PICL_PROPNOTFOUND)
2089 			model = NULL;
2090 		else if (err != PICL_SUCCESS)
2091 			return (err);
2092 
2093 		err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS,
2094 		    &status);
2095 		if (err == PICL_PROPNOTFOUND) {
2096 			status = malloc(5);
2097 			if (status == NULL)
2098 				return (PICL_FAILURE);
2099 			strncpy(status, "okay", 5);
2100 		} else if (err != PICL_SUCCESS)
2101 			return (err);
2102 
2103 		err = add_io_leaves(nodeh, NULL, boardnum, bus_id, slot,
2104 		    freq, model, status);
2105 
2106 		if (model != NULL)
2107 			free(model);
2108 
2109 		if (status != NULL)
2110 			free(status);
2111 
2112 		if (err != PICL_SUCCESS)
2113 			return (err);
2114 
2115 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
2116 		    sizeof (picl_nodehdl_t));
2117 
2118 	}
2119 
2120 	if (err == PICL_PROPNOTFOUND)
2121 		return (PICL_WALK_CONTINUE);
2122 
2123 	return (err);
2124 }
2125 
2126 /*
2127  * add io devices in io list
2128  * Its slot number is drived from upa-portid
2129  */
2130 static int
2131 add_io_devices(picl_nodehdl_t nodeh)
2132 {
2133 	int		err;
2134 	uint64_t	board_type;
2135 	char 		piclclass[PICL_CLASSNAMELEN_MAX];
2136 	char 		name[MAXSTRLEN];
2137 	char 		*devfs_path;
2138 	char		*nameval;
2139 	uint32_t	boardnum;
2140 	uint32_t	bus_id;
2141 	uint32_t	slot;
2142 	uint32_t	freq;
2143 	char		*model;
2144 	char		*status;
2145 	picl_prophdl_t  proph;
2146 	picl_propinfo_t	pinfo;
2147 	picl_nodehdl_t	fruparenth;
2148 	char		*label;
2149 
2150 
2151 	bus_id = UPA_TYPE;
2152 
2153 	/*
2154 	 * If clock frequency can't be found from its parent, don't add
2155 	 */
2156 	err = picldiag_get_clock_from_parent(nodeh, &freq);
2157 	if (err == PICL_PROPNOTFOUND)
2158 		return (PICL_SUCCESS);
2159 	else if (err != PICL_SUCCESS)
2160 		return (err);
2161 
2162 	/*
2163 	 * If no board# is found, set boardnum to 0
2164 	 */
2165 	boardnum = picldiag_get_uint_propval(nodeh, OBP_PROP_BOARD_NUM, &err);
2166 	if (err == PICL_PROPNOTFOUND)
2167 		boardnum = DEFAULT_BOARD_NUM;
2168 	else if (err != PICL_SUCCESS)
2169 		return (err);
2170 
2171 	/*
2172 	 * get upa portid as slot number
2173 	 * If upa portid is not found, don't add the card.
2174 	 */
2175 	slot = picldiag_get_uint_propval(nodeh, OBP_PROP_UPA_PORTID,
2176 	    &err);
2177 	if (err == PICL_PROPNOTFOUND)
2178 		return (PICL_SUCCESS);
2179 	else if (err != PICL_SUCCESS)
2180 		return (err);
2181 
2182 	/* Get the model of this card */
2183 	err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL, &model);
2184 	if (err == PICL_PROPNOTFOUND)
2185 		model = NULL;
2186 	else if (err != PICL_SUCCESS)
2187 		return (err);
2188 
2189 	/*
2190 	 * check if it is a ffb device
2191 	 * If it's a ffb device, append its board type to name
2192 	 * otherwise, use its nodename
2193 	 */
2194 	err = picl_get_prop_by_name(nodeh, PICL_PROP_FFB_BOARD_REV, &proph);
2195 	if (err == PICL_PROPNOTFOUND) {
2196 		err = picl_get_propinfo_by_name(nodeh, PICL_PROP_NAME,
2197 		    &pinfo, &proph);
2198 		if (err != PICL_SUCCESS)
2199 			return (err);
2200 
2201 		nameval = alloca(pinfo.size);
2202 		if (nameval == NULL)
2203 			return (PICL_FAILURE);
2204 
2205 		err = picl_get_propval(proph, nameval, pinfo.size);
2206 		if (err != PICL_SUCCESS)
2207 			return (err);
2208 
2209 		(void) strlcpy(name, nameval, MAXSTRLEN);
2210 	} else if (err == PICL_SUCCESS) {
2211 		/* Find out if it's single or double buffered */
2212 		board_type = picldiag_get_uint_propval(nodeh,
2213 		    OBP_PROP_BOARD_TYPE, &err);
2214 		if (err == PICL_PROPNOTFOUND)
2215 			(void) strlcpy(name, FFB_NAME, sizeof (name));
2216 		if (err == PICL_SUCCESS) {
2217 			if (board_type & FFB_B_BUFF)
2218 				(void) strlcpy(name, FFB_DOUBLE_BUF,
2219 				    sizeof (name));
2220 			else
2221 				(void) strlcpy(name, FFB_SINGLE_BUF,
2222 				    sizeof (name));
2223 		} else
2224 			return (err);
2225 	} else
2226 		return (err);
2227 
2228 	err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2229 	    piclclass, sizeof (piclclass));
2230 	if (err != PICL_SUCCESS)
2231 		return (err);
2232 
2233 	(void) snprintf(name, sizeof (name), "%s (%s)", name, piclclass);
2234 
2235 	err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
2236 	if (err == PICL_PROPNOTFOUND) {
2237 		status = malloc(5);
2238 		if (status == NULL)
2239 			return (PICL_FAILURE);
2240 		strncpy(status, "okay", 5);
2241 	} else if (err != PICL_SUCCESS)
2242 		return (err);
2243 
2244 	err = picldiag_get_fru_parent(nodeh, &fruparenth);
2245 	if (err == PICL_PROPNOTFOUND) {
2246 		label = NULL;
2247 	} else if (err != PICL_SUCCESS) {
2248 		return (err);
2249 	} else {
2250 		err = picldiag_get_combined_label(fruparenth, &label, 15);
2251 		if (err == PICL_PROPNOTFOUND)
2252 			label = NULL;
2253 		else if (err != PICL_SUCCESS)
2254 			return (err);
2255 	}
2256 	/* devfs-path */
2257 	err =  picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH,
2258 	    &devfs_path);
2259 	if (err == PICL_PROPNOTFOUND)
2260 		devfs_path = NULL;
2261 	else if (err != PICL_SUCCESS)
2262 		return (err);
2263 
2264 	add_io_card(boardnum, bus_id, slot, label, freq, name, model, status,
2265 	    devfs_path);
2266 	if (label != NULL)
2267 		free(label);
2268 	if (model != NULL)
2269 		free(model);
2270 	if (status != NULL)
2271 		free(status);
2272 	if (devfs_path != NULL)
2273 		free(devfs_path);
2274 
2275 	return (PICL_SUCCESS);
2276 }
2277 
2278 /*
2279  * loop through all children and add io devices in io list
2280  */
2281 static int
2282 process_io_leaves(picl_nodehdl_t rooth)
2283 {
2284 	picl_nodehdl_t	nodeh;
2285 	char		classval[PICL_CLASSNAMELEN_MAX];
2286 	int		err;
2287 
2288 	err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh,
2289 	    sizeof (picl_nodehdl_t));
2290 	while (err == PICL_SUCCESS) {
2291 		err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2292 		    classval, sizeof (classval));
2293 		if (err != PICL_SUCCESS)
2294 			return (err);
2295 
2296 		if (is_io_device(classval))
2297 			err = add_io_devices(nodeh);
2298 
2299 		if (err != PICL_SUCCESS)
2300 			return (err);
2301 
2302 		err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
2303 		    sizeof (picl_nodehdl_t));
2304 	}
2305 
2306 	if (err == PICL_PROPNOTFOUND)
2307 		return (PICL_SUCCESS);
2308 
2309 	return (err);
2310 }
2311 
2312 /*
2313  * callback function to add all io devices under upa in io list
2314  */
2315 /*ARGSUSED*/
2316 static int
2317 upa_callback(picl_nodehdl_t upah, void *args)
2318 {
2319 	int		err;
2320 
2321 	err = process_io_leaves(upah);
2322 
2323 	if (err == PICL_SUCCESS)
2324 		return (PICL_WALK_CONTINUE);
2325 	return (err);
2326 }
2327 
2328 /*
2329  * display ffb hardware configuration
2330  */
2331 /* ARGSUSED */
2332 static int
2333 ffbconfig_callback(picl_nodehdl_t ffbh, void *arg)
2334 {
2335 	int		err;
2336 	uint64_t	board_rev;
2337 	uint64_t	fbc_ver;
2338 	char		*dac_ver;
2339 	char		*fbram_ver;
2340 
2341 	/*
2342 	 * If it has PICL_PROP_FFB_BOARD_REV, it is a ffb device
2343 	 * Otherwise, return.
2344 	 */
2345 	board_rev = picldiag_get_uint_propval(ffbh, PICL_PROP_FFB_BOARD_REV,
2346 	    &err);
2347 	if (err == PICL_PROPNOTFOUND)
2348 		return (PICL_WALK_CONTINUE);
2349 	else if (err != PICL_SUCCESS)
2350 		return (err);
2351 
2352 	log_printf("FFB Hardware Configuration:\n");
2353 	log_printf("-----------------------------------\n");
2354 	log_printf("Board rev: %lld\n", board_rev);
2355 
2356 	fbc_ver = picldiag_get_uint_propval(ffbh, OBP_PROP_FBC_REG_ID,
2357 	    &err);
2358 	if (err == PICL_SUCCESS)
2359 		log_printf("FBC version: 0x%llx\n", fbc_ver);
2360 	else if (err != PICL_PROPNOTFOUND)
2361 		return (err);
2362 
2363 	err = picldiag_get_string_propval(ffbh, PICL_PROP_FFB_DAC_VER,
2364 	    &dac_ver);
2365 	if (err == PICL_SUCCESS) {
2366 		log_printf("DAC: %s\n", dac_ver);
2367 		free(dac_ver);
2368 	} else if (err != PICL_PROPNOTFOUND)
2369 		return (err);
2370 
2371 	err = picldiag_get_string_propval(ffbh, PICL_PROP_FFB_FBRAM_VER,
2372 	    &fbram_ver);
2373 	if (err  == PICL_SUCCESS) {
2374 		log_printf("3DRAM: %s\n", fbram_ver);
2375 		free(fbram_ver);
2376 	} else if (err != PICL_PROPNOTFOUND)
2377 		return (err);
2378 
2379 	log_printf("\n");
2380 	return (PICL_WALK_CONTINUE);
2381 }
2382 
2383 /*
2384  * find all io devices and add them in the io list
2385  */
2386 static int
2387 gather_io_cards(picl_nodehdl_t plafh)
2388 {
2389 	int		err;
2390 
2391 	/*
2392 	 * look for io devices under the immediate children of platform
2393 	 */
2394 	err = process_io_leaves(plafh);
2395 	if (err != PICL_SUCCESS)
2396 		return (err);
2397 
2398 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_SBUS,
2399 	    PICL_CLASS_SBUS, sbus_callback);
2400 	if (err != PICL_SUCCESS)
2401 		return (err);
2402 
2403 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
2404 	    PICL_CLASS_PCI, pci_pciex_callback);
2405 	if (err != PICL_SUCCESS)
2406 		return (err);
2407 
2408 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
2409 		PICL_CLASS_PCIEX, pci_pciex_callback);
2410 	if (err != PICL_SUCCESS)
2411 		return (err);
2412 
2413 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_UPA,
2414 	    PICL_CLASS_UPA, upa_callback);
2415 
2416 	return (err);
2417 }
2418 
2419 static void
2420 picldiag_display_io_cards(struct io_card *list)
2421 {
2422 	static int banner = 0; /* Have we printed the column headings? */
2423 	struct io_card *p;
2424 
2425 	if (list == NULL)
2426 		return;
2427 
2428 	if (banner == 0) {
2429 		log_printf("Bus     Freq  Slot +      Name +\n", 0);
2430 		log_printf("Type    MHz   Status      Path"
2431 			"                          Model", 0);
2432 		log_printf("\n", 0);
2433 		log_printf("------  ----  ----------  "
2434 			"----------------------------  "
2435 			"--------------------", 0);
2436 		log_printf("\n", 0);
2437 		banner = 1;
2438 	}
2439 
2440 	for (p = list; p != NULL; p = p -> next) {
2441 		log_printf("%-6s  ", p->bus_type, 0);
2442 		log_printf("%-3d   ", p->freq, 0);
2443 		/*
2444 		 * We check to see if it's an int or
2445 		 * a char string to display for slot.
2446 		 */
2447 		if (p->slot == PCI_SLOT_IS_STRING)
2448 			log_printf("%-10s  ", p->slot_str, 0);
2449 		else
2450 			log_printf("%-10d  ", p->slot, 0);
2451 
2452 		log_printf("%-28.28s", p->name, 0);
2453 		if (strlen(p->name) > 28)
2454 			log_printf("+ ", 0);
2455 		else
2456 			log_printf("  ", 0);
2457 		log_printf("%-19.19s", p->model, 0);
2458 		if (strlen(p->model) > 19)
2459 			log_printf("+", 0);
2460 		log_printf("\n", 0);
2461 		log_printf("              %-10s  ", p->status, 0);
2462 		set_exit_code(p->status);
2463 		if (strlen(p->notes) > 0)
2464 			log_printf("%s", p->notes, 0);
2465 		log_printf("\n\n", 0);
2466 	}
2467 }
2468 
2469 /*
2470  * display all io devices
2471  */
2472 static int
2473 display_io_device_info(picl_nodehdl_t plafh)
2474 {
2475 	int	err;
2476 
2477 	err = gather_io_cards(plafh);
2478 	if (err != PICL_SUCCESS)
2479 		return (err);
2480 
2481 	logprintf_header(dgettext(TEXT_DOMAIN, "IO Devices"),
2482 	    DEFAULT_LINE_WIDTH);
2483 
2484 	picldiag_display_io_cards(io_card_list);
2485 
2486 	free_io_cards(io_card_list);
2487 
2488 	return (PICL_SUCCESS);
2489 }
2490 
2491 /*
2492  * print fan device information
2493  */
2494 static int
2495 logprintf_fan_info(picl_nodehdl_t fanh)
2496 {
2497 	int		err;
2498 	char		*label;
2499 	char		*unit;
2500 	int64_t		speed;
2501 	int64_t		min_speed;
2502 	picl_nodehdl_t	fruph;
2503 
2504 	err = picldiag_get_fru_parent(fanh, &fruph);
2505 	if (err != PICL_SUCCESS)
2506 		return (err);
2507 
2508 	err = picldiag_get_combined_label(fruph, &label, 20);
2509 	if (err != PICL_SUCCESS)
2510 		return (err);
2511 
2512 	log_printf("%-20s ", label);
2513 	free(label);
2514 
2515 	err = picldiag_get_label(fanh, &label);
2516 	if (err == PICL_SUCCESS) {
2517 		log_printf("%-14s  ", label);
2518 		free(label);
2519 	} else if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
2520 		log_printf("  -           ");
2521 	} else
2522 		return (err);
2523 
2524 	speed = picldiag_get_uint_propval(fanh, PICL_PROP_FAN_SPEED, &err);
2525 	if (err == PICL_SUCCESS) {
2526 		min_speed = picldiag_get_uint_propval(fanh,
2527 		    PICL_PROP_LOW_WARNING_THRESHOLD, &err);
2528 		if (err != PICL_SUCCESS)
2529 			min_speed = 0;
2530 
2531 		if (speed < min_speed) {
2532 			log_printf("failed (%lld", speed);
2533 			err = picldiag_get_string_propval(fanh,
2534 			    PICL_PROP_FAN_SPEED_UNIT, &unit);
2535 			if (err == PICL_SUCCESS) {
2536 				log_printf("%s", unit);
2537 				free(unit);
2538 			}
2539 			log_printf(")");
2540 			exit_code = PD_SYSTEM_FAILURE;
2541 		} else {
2542 			log_printf("okay");
2543 		}
2544 	} else {
2545 		err = picldiag_get_string_propval(fanh,
2546 		    PICL_PROP_FAN_SPEED_UNIT, &unit);
2547 		if (err == PICL_SUCCESS) {
2548 			log_printf("%-12s ", unit);
2549 			free(unit);
2550 		}
2551 	}
2552 
2553 	log_printf("\n");
2554 	return (PICL_SUCCESS);
2555 }
2556 
2557 static int
2558 fan_callback(picl_nodehdl_t fanh, void *arg)
2559 {
2560 	int	*countp = arg;
2561 
2562 	if (*countp == 0) {
2563 		log_printf(dgettext(TEXT_DOMAIN, "Fan Status:\n"));
2564 		log_printf("-------------------------------------------\n");
2565 		log_printf("Location             Sensor          Status\n");
2566 		log_printf("-------------------------------------------\n");
2567 	}
2568 	*countp += 1;
2569 
2570 	(void) logprintf_fan_info(fanh);
2571 
2572 	return (PICL_WALK_CONTINUE);
2573 }
2574 
2575 /*
2576  * callback function search children to find fan device and print its speed
2577  */
2578 static int
2579 display_fan_speed(picl_nodehdl_t plafh)
2580 {
2581 	int		err;
2582 	int		print_header;
2583 
2584 	print_header = 0;
2585 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_FAN,
2586 	    &print_header, fan_callback);
2587 	return (err);
2588 }
2589 
2590 /*
2591  * print temperature sensor information
2592  */
2593 static int
2594 logprintf_temp_info(picl_nodehdl_t temph)
2595 {
2596 	int		err;
2597 	char		*label;
2598 	int64_t		temperature;
2599 	int64_t		threshold;
2600 	picl_nodehdl_t	fruph;
2601 	char		*status = "unknown";
2602 	int		got_temp = 0;
2603 
2604 	err = picldiag_get_fru_parent(temph, &fruph);
2605 	if (err != PICL_SUCCESS)
2606 		return (err);
2607 
2608 	err = picldiag_get_combined_label(fruph, &label, 14);
2609 	if (err != PICL_SUCCESS)
2610 		return (err);
2611 
2612 	log_printf("%-14s ", label);
2613 	free(label);
2614 
2615 	err = picldiag_get_label(temph, &label);
2616 	if (err != PICL_SUCCESS)
2617 		return (err);
2618 	log_printf("%-19s ", label);
2619 	free(label);
2620 
2621 	temperature = picldiag_get_int_propval(temph, PICL_PROP_TEMPERATURE,
2622 	    &err);
2623 	if (err == PICL_SUCCESS) {
2624 		got_temp = 1;
2625 		status = "okay";
2626 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2627 		return (err);
2628 	}
2629 
2630 	threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_WARNING,
2631 	    &err);
2632 	if (err == PICL_SUCCESS) {
2633 		if (got_temp && temperature < threshold)
2634 			status = "warning";
2635 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2636 		return (err);
2637 	}
2638 
2639 	threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_SHUTDOWN,
2640 	    &err);
2641 	if (err == PICL_SUCCESS) {
2642 		if (got_temp && temperature < threshold)
2643 			status = "failed";
2644 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2645 		return (err);
2646 	}
2647 
2648 	threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_WARNING,
2649 	    &err);
2650 	if (err == PICL_SUCCESS) {
2651 		if (got_temp && temperature > threshold)
2652 			status = "warning";
2653 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2654 		return (err);
2655 	}
2656 
2657 	threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_SHUTDOWN,
2658 	    &err);
2659 	if (err == PICL_SUCCESS) {
2660 		if (got_temp && temperature > threshold)
2661 			status = "failed";
2662 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2663 		return (err);
2664 	}
2665 
2666 	err = picldiag_get_string_propval(temph, PICL_PROP_CONDITION, &status);
2667 	if (err == PICL_SUCCESS) {
2668 		log_printf("%s", status);
2669 		set_exit_code(status);
2670 		free(status);
2671 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2672 		return (err);
2673 	} else {
2674 		log_printf("%s ", status);
2675 		set_exit_code(status);
2676 		if (strcmp(status, "failed") == 0 ||
2677 		    strcmp(status, "warning") == 0)
2678 			log_printf("(%.2lldC)", temperature);
2679 	}
2680 
2681 	log_printf("\n");
2682 	return (PICL_SUCCESS);
2683 }
2684 
2685 static int
2686 temp_callback(picl_nodehdl_t temph, void *arg)
2687 {
2688 	int		err;
2689 	int	*countp = arg;
2690 
2691 	if (*countp == 0) {
2692 		log_printf("\n");
2693 		log_printf(dgettext(TEXT_DOMAIN, "Temperature sensors:\n"));
2694 		log_printf("-----------------------------------------\n");
2695 		log_printf("Location       Sensor              Status\n");
2696 		log_printf("-----------------------------------------\n");
2697 	}
2698 	*countp += 1;
2699 	err = logprintf_temp_info(temph);
2700 	if (err == PICL_SUCCESS)
2701 		return (PICL_WALK_CONTINUE);
2702 	return (err);
2703 }
2704 
2705 /*
2706  * callback function search children to find temp sensors and print the temp
2707  */
2708 /* ARGSUSED */
2709 static int
2710 display_temp(picl_nodehdl_t plafh)
2711 {
2712 	int		err;
2713 	int		print_header;
2714 
2715 	print_header = 0;
2716 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_SENSOR,
2717 	    &print_header, temp_callback);
2718 	if (err != PICL_SUCCESS)
2719 		return (err);
2720 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_INDICATOR,
2721 	    &print_header, temp_callback);
2722 	return (err);
2723 }
2724 
2725 /*
2726  * print current sensor information
2727  */
2728 static int
2729 logprintf_current_info(picl_nodehdl_t currenth)
2730 {
2731 	int		err;
2732 	char		*label;
2733 	float		current;
2734 	float		threshold;
2735 	picl_nodehdl_t	fruph;
2736 	char		*status = "unknown";
2737 	int		got_current = 0;
2738 
2739 	err = picldiag_get_fru_parent(currenth, &fruph);
2740 	if (err != PICL_SUCCESS)
2741 		return (err);
2742 
2743 	err = picldiag_get_combined_label(fruph, &label, 20);
2744 	if (err != PICL_SUCCESS)
2745 		return (err);
2746 
2747 	log_printf("%-20s ", label);
2748 	free(label);
2749 
2750 	err = picldiag_get_label(currenth, &label);
2751 	if (err != PICL_SUCCESS)
2752 		return (err);
2753 	log_printf("%-10s  ", label);
2754 	free(label);
2755 
2756 	current = picldiag_get_float_propval(currenth, PICL_PROP_CURRENT, &err);
2757 	if (err == PICL_SUCCESS) {
2758 		status = "okay";
2759 		got_current = 1;
2760 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2761 		return (err);
2762 	}
2763 
2764 	threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_WARNING,
2765 	    &err);
2766 	if (err == PICL_SUCCESS) {
2767 		if (got_current && current < threshold)
2768 			status = "warning";
2769 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2770 		return (err);
2771 	}
2772 
2773 	threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_SHUTDOWN,
2774 	    &err);
2775 	if (err == PICL_SUCCESS) {
2776 		if (got_current && current < threshold)
2777 			status = "failed";
2778 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2779 		return (err);
2780 	}
2781 
2782 	threshold = picldiag_get_float_propval(currenth, PICL_PROP_HIGH_WARNING,
2783 	    &err);
2784 	if (err == PICL_SUCCESS) {
2785 		if (got_current && current > threshold)
2786 			status = "warning";
2787 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2788 		return (err);
2789 	}
2790 
2791 	threshold = picldiag_get_float_propval(currenth,
2792 	    PICL_PROP_HIGH_SHUTDOWN, &err);
2793 	if (err == PICL_SUCCESS) {
2794 		if (got_current && current > threshold)
2795 			status = "failed";
2796 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2797 		return (err);
2798 	}
2799 
2800 	err = picldiag_get_string_propval(currenth,
2801 	    PICL_PROP_CONDITION, &status);
2802 	if (err == PICL_SUCCESS) {
2803 		log_printf(" %s", status);
2804 		set_exit_code(status);
2805 		free(status);
2806 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2807 		return (err);
2808 	} else {
2809 		log_printf("%s ", status);
2810 		set_exit_code(status);
2811 		if (strcmp(status, "failed") == 0 ||
2812 		    strcmp(status, "warning") == 0)
2813 			log_printf("(%.2fA)", current);
2814 	}
2815 
2816 	log_printf("\n");
2817 	return (PICL_SUCCESS);
2818 }
2819 
2820 static int
2821 current_callback(picl_nodehdl_t currh, void *arg)
2822 {
2823 	int		err;
2824 	int	*countp = arg;
2825 
2826 	if (*countp == 0) {
2827 		log_printf("------------------------------------\n");
2828 		log_printf(dgettext(TEXT_DOMAIN, "Current sensors:\n"));
2829 		log_printf("----------------------------------------\n");
2830 		log_printf("Location             Sensor       Status\n");
2831 		log_printf("----------------------------------------\n");
2832 	}
2833 	*countp += 1;
2834 	err = logprintf_current_info(currh);
2835 	if (err == PICL_SUCCESS)
2836 		return (PICL_WALK_CONTINUE);
2837 	return (err);
2838 }
2839 
2840 /*
2841  * callback function search children to find curr sensors and print the curr
2842  */
2843 /* ARGSUSED */
2844 static int
2845 display_current(picl_nodehdl_t plafh)
2846 {
2847 	int		err;
2848 	int		print_header;
2849 
2850 	print_header = 0;
2851 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_SENSOR,
2852 	    &print_header, current_callback);
2853 	if (err != PICL_SUCCESS)
2854 		return (err);
2855 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_INDICATOR,
2856 	    &print_header, current_callback);
2857 	return (err);
2858 }
2859 
2860 /*
2861  * print voltage sensor information
2862  */
2863 static int
2864 logprintf_voltage_info(picl_nodehdl_t voltageh)
2865 {
2866 	int		err;
2867 	char		*label;
2868 	float		voltage;
2869 	float		threshold;
2870 	picl_nodehdl_t	fruph;
2871 	char		*status = "unknown";
2872 	int		got_voltage = 0;
2873 
2874 	err = picldiag_get_fru_parent(voltageh, &fruph);
2875 	if (err != PICL_SUCCESS)
2876 		return (err);
2877 
2878 	err = picldiag_get_combined_label(fruph, &label, 14);
2879 	if (err != PICL_SUCCESS)
2880 		return (err);
2881 
2882 	log_printf("%-14s ", label);
2883 	free(label);
2884 
2885 	err = picldiag_get_label(voltageh, &label);
2886 	if (err != PICL_SUCCESS)
2887 		return (err);
2888 	log_printf("%-12s  ", label);
2889 	free(label);
2890 
2891 	voltage = picldiag_get_float_propval(voltageh, PICL_PROP_VOLTAGE, &err);
2892 	if (err == PICL_SUCCESS) {
2893 		status = "okay";
2894 		got_voltage = 1;
2895 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2896 		return (err);
2897 	}
2898 
2899 	threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_WARNING,
2900 	    &err);
2901 	if (err == PICL_SUCCESS) {
2902 		if (got_voltage && voltage < threshold)
2903 			status = "warning";
2904 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2905 		return (err);
2906 	}
2907 
2908 	threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_SHUTDOWN,
2909 	    &err);
2910 	if (err == PICL_SUCCESS) {
2911 		if (got_voltage && voltage < threshold)
2912 			status = "failed";
2913 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2914 		return (err);
2915 	}
2916 
2917 	threshold = picldiag_get_float_propval(voltageh, PICL_PROP_HIGH_WARNING,
2918 	    &err);
2919 	if (err == PICL_SUCCESS) {
2920 		if (got_voltage && voltage > threshold)
2921 			status = "warning";
2922 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2923 		return (err);
2924 	}
2925 
2926 	threshold = picldiag_get_float_propval(voltageh,
2927 	    PICL_PROP_HIGH_SHUTDOWN, &err);
2928 	if (err == PICL_SUCCESS) {
2929 		if (got_voltage && voltage > threshold)
2930 			status = "failed";
2931 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2932 		return (err);
2933 	}
2934 
2935 	err = picldiag_get_string_propval(voltageh,
2936 	    PICL_PROP_CONDITION, &status);
2937 	if (err == PICL_SUCCESS) {
2938 		log_printf("%s", status);
2939 		set_exit_code(status);
2940 		free(status);
2941 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
2942 		return (err);
2943 	} else {
2944 		log_printf("%s ", status);
2945 		set_exit_code(status);
2946 		if (strcmp(status, "warning") == 0 ||
2947 		    strcmp(status, "failed") == 0)
2948 			log_printf("(%.2fV)", voltage);
2949 	}
2950 
2951 	log_printf("\n");
2952 	return (PICL_SUCCESS);
2953 }
2954 
2955 static int
2956 voltage_callback(picl_nodehdl_t voltageh, void *arg)
2957 {
2958 	int	*countp = arg;
2959 	int		err;
2960 
2961 	if (*countp == 0) {
2962 		log_printf("------------------------------------\n");
2963 		log_printf(dgettext(TEXT_DOMAIN, "Voltage sensors:\n"));
2964 		log_printf("-----------------------------------\n");
2965 		log_printf("Location       Sensor        Status\n");
2966 		log_printf("-----------------------------------\n");
2967 	}
2968 	*countp += 1;
2969 	err = logprintf_voltage_info(voltageh);
2970 	if (err == PICL_SUCCESS)
2971 		return (PICL_WALK_CONTINUE);
2972 	return (err);
2973 }
2974 
2975 /*
2976  * callback function search children to find voltage sensors and print voltage
2977  */
2978 /* ARGSUSED */
2979 static int
2980 display_voltage(picl_nodehdl_t plafh)
2981 {
2982 	int		err;
2983 	int		print_header;
2984 
2985 	print_header = 0;
2986 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_SENSOR,
2987 	    &print_header, voltage_callback);
2988 	if (err != PICL_SUCCESS)
2989 		return (err);
2990 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_INDICATOR,
2991 	    &print_header, voltage_callback);
2992 	return (err);
2993 }
2994 
2995 /*
2996  * print led device information
2997  */
2998 static int
2999 logprintf_led_info(picl_nodehdl_t ledh)
3000 {
3001 	int		err;
3002 	char		*label;
3003 	char		*state;
3004 	char		*color;
3005 	picl_nodehdl_t  fruph;
3006 
3007 	err = picldiag_get_fru_parent(ledh, &fruph);
3008 	if (err != PICL_SUCCESS)
3009 		return (err);
3010 
3011 	err = picldiag_get_combined_label(fruph, &label, 22);
3012 	if (err != PICL_SUCCESS) {
3013 		log_printf("           -         ", label);
3014 	} else {
3015 		log_printf("%-22s ", label);
3016 		free(label);
3017 	}
3018 
3019 	err = picldiag_get_label(ledh, &label);
3020 	if (err != PICL_SUCCESS)
3021 		return (err);
3022 	log_printf("%-20s  ", label);
3023 	free(label);
3024 
3025 	err = picldiag_get_string_propval(ledh, PICL_PROP_STATE, &state);
3026 	if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
3027 		log_printf("     -     ");
3028 	} else if (err != PICL_SUCCESS) {
3029 		return (err);
3030 	} else {
3031 		log_printf("%-10s  ", state);
3032 		free(state);
3033 	}
3034 
3035 	err = picldiag_get_string_propval(ledh, PICL_PROP_COLOR, &color);
3036 	if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
3037 		log_printf("\n");
3038 	} else if (err != PICL_SUCCESS) {
3039 		return (err);
3040 	} else {
3041 		log_printf("%-16s\n", color);
3042 		free(color);
3043 	}
3044 
3045 	return (PICL_SUCCESS);
3046 }
3047 
3048 static int
3049 led_callback(picl_nodehdl_t ledh, void *arg)
3050 {
3051 	int		*countp = arg;
3052 	int		err;
3053 
3054 	if (*countp == 0) {
3055 
3056 		log_printf("--------------------------------------"
3057 		    "------------\n");
3058 		log_printf(dgettext(TEXT_DOMAIN, "Led State:\n"));
3059 		log_printf("----------------------------------------"
3060 		    "----------------------\n");
3061 		log_printf("Location               Led                   State"
3062 		    "       Color\n");
3063 		log_printf("----------------------------------------"
3064 		    "----------------------\n");
3065 	}
3066 	*countp += 1;
3067 	err = logprintf_led_info(ledh);
3068 	if (err == PICL_SUCCESS)
3069 		return (PICL_WALK_CONTINUE);
3070 	return (err);
3071 }
3072 
3073 /*
3074  * callback function search children to find led devices and print status
3075  */
3076 /* ARGSUSED */
3077 static int
3078 display_led_status(picl_nodehdl_t plafh)
3079 {
3080 	int		print_header;
3081 
3082 	print_header = 0;
3083 	picl_walk_tree_by_class(plafh, PICL_CLASS_LED,
3084 	    &print_header, led_callback);
3085 	return (PICL_SUCCESS);
3086 }
3087 
3088 /*
3089  * print keyswitch device information
3090  */
3091 static int
3092 logprintf_keyswitch_info(picl_nodehdl_t keyswitchh, picl_nodehdl_t fruph)
3093 {
3094 	int		err;
3095 	char		*label;
3096 	char		*state;
3097 
3098 	err = picldiag_get_combined_label(fruph, &label, 10);
3099 	if (err != PICL_SUCCESS) {
3100 		log_printf("%-14s", "     -");
3101 	} else {
3102 		log_printf("%-14s ", label);
3103 		free(label);
3104 	}
3105 
3106 	err = picldiag_get_label(keyswitchh, &label);
3107 	if (err != PICL_SUCCESS)
3108 		return (err);
3109 	log_printf("%-11s ", label);
3110 	free(label);
3111 
3112 	err = picldiag_get_string_propval(keyswitchh, PICL_PROP_STATE, &state);
3113 	if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
3114 		log_printf("     -\n");
3115 	} else if (err != PICL_SUCCESS) {
3116 		return (err);
3117 	} else {
3118 		log_printf("%s\n", state);
3119 		free(state);
3120 	}
3121 
3122 	return (PICL_SUCCESS);
3123 }
3124 
3125 static int
3126 keyswitch_callback(picl_nodehdl_t keyswitchh, void *arg)
3127 {
3128 	int		*countp = arg;
3129 	int		err;
3130 	picl_nodehdl_t	fruph;
3131 
3132 	/*
3133 	 * Tamale simulates a key-switch on ENxS. So the presence of a
3134 	 * node of class keyswitch is not sufficient. If it has a fru parent
3135 	 * or location parent, then believe it.
3136 	 */
3137 	err = picl_get_propval_by_name(keyswitchh, PICL_REFPROP_FRU_PARENT,
3138 	    &fruph, sizeof (fruph));
3139 	if (err == PICL_PROPNOTFOUND) {
3140 		err = picl_get_propval_by_name(keyswitchh,
3141 		    PICL_REFPROP_LOC_PARENT, &fruph, sizeof (fruph));
3142 	}
3143 	if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE)
3144 		return (PICL_WALK_CONTINUE);
3145 	if (err != PICL_SUCCESS)
3146 		return (err);
3147 
3148 	if (*countp == 0) {
3149 		log_printf("-----------------------------------------\n");
3150 		log_printf(dgettext(TEXT_DOMAIN, "Keyswitch:\n"));
3151 		log_printf("-----------------------------------------\n");
3152 		log_printf(dgettext(TEXT_DOMAIN,
3153 		    "Location       Keyswitch   State\n"));
3154 		log_printf("-----------------------------------------\n");
3155 	}
3156 	*countp += 1;
3157 	err = logprintf_keyswitch_info(keyswitchh, fruph);
3158 	if (err == PICL_SUCCESS)
3159 		return (PICL_WALK_CONTINUE);
3160 	return (err);
3161 }
3162 
3163 /*
3164  * search children to find keyswitch device(s) and print status
3165  */
3166 /* ARGSUSED */
3167 static int
3168 display_keyswitch(picl_nodehdl_t plafh)
3169 {
3170 	int		print_header = 0;
3171 
3172 	picl_walk_tree_by_class(plafh, PICL_CLASS_KEYSWITCH,
3173 	    &print_header, keyswitch_callback);
3174 	return (PICL_SUCCESS);
3175 }
3176 
3177 /*
3178  * display environment status
3179  */
3180 static int
3181 display_envctrl_status(picl_nodehdl_t plafh)
3182 {
3183 	logprintf_header(dgettext(TEXT_DOMAIN, "Environmental Status"),
3184 	    DEFAULT_LINE_WIDTH);
3185 
3186 	display_fan_speed(plafh);
3187 	display_temp(plafh);
3188 	display_current(plafh);
3189 	display_voltage(plafh);
3190 	display_keyswitch(plafh);
3191 	display_led_status(plafh);
3192 
3193 	return (PICL_SUCCESS);
3194 }
3195 
3196 /*
3197  * print fru operational status
3198  */
3199 static int
3200 logprintf_fru_oper_status(picl_nodehdl_t fruh, int *countp)
3201 {
3202 	int		err;
3203 	char		*label;
3204 	char		*status;
3205 
3206 	err = picldiag_get_combined_label(fruh, &label, 23);
3207 	if (err != PICL_SUCCESS)
3208 		return (PICL_WALK_CONTINUE);
3209 
3210 	err = picldiag_get_string_propval(fruh,
3211 	    PICL_PROP_OPERATIONAL_STATUS, &status);
3212 	if (err == PICL_SUCCESS) {
3213 		if (*countp == 0) {
3214 			logprintf_header(dgettext(TEXT_DOMAIN,
3215 			    "FRU Operational Status"),
3216 			    DEFAULT_LINE_WIDTH);
3217 			log_printf("---------------------------------\n");
3218 			log_printf(dgettext(TEXT_DOMAIN,
3219 			    "Fru Operational Status:\n"));
3220 			log_printf("---------------------------------\n");
3221 			log_printf("Location                Status\n");
3222 			log_printf("---------------------------------\n");
3223 		}
3224 		*countp += 1;
3225 		log_printf("%-23s ", label);
3226 		free(label);
3227 		log_printf("%s\n", status);
3228 		set_exit_code(status);
3229 		free(status);
3230 	} else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
3231 		free(label);
3232 		return (err);
3233 	} else {
3234 		free(label);
3235 	}
3236 	return (PICL_WALK_CONTINUE);
3237 }
3238 
3239 static int
3240 fru_oper_status_callback(picl_nodehdl_t fruh, void *arg)
3241 {
3242 	int err;
3243 
3244 	err = logprintf_fru_oper_status(fruh, (int *)arg);
3245 	return (err);
3246 }
3247 
3248 /*
3249  * display fru operational status
3250  */
3251 static int
3252 display_fru_oper_status(picl_nodehdl_t frutreeh)
3253 {
3254 	int		print_header;
3255 
3256 	print_header = 0;
3257 	picl_walk_tree_by_class(frutreeh, PICL_CLASS_FRU,
3258 	    &print_header, fru_oper_status_callback);
3259 	return (PICL_SUCCESS);
3260 }
3261 
3262 /*
3263  * check if the node having the version prop
3264  * If yes, print its nodename and version
3265  */
3266 /* ARGSUSED */
3267 static int
3268 asicrev_callback(picl_nodehdl_t nodeh, void *arg)
3269 {
3270 	uint32_t	version;
3271 	char		*name;
3272 	char		*model;
3273 	char		*status;
3274 	int		err;
3275 
3276 	/*
3277 	 * Fire based platforms use "module-revision#" in place of "version#",
3278 	 * so we need to look for this property if we don't find "version#"
3279 	 */
3280 	version = picldiag_get_uint_propval(nodeh, OBP_PROP_VERSION_NUM, &err);
3281 	if (err == PICL_PROPNOTFOUND) {
3282 		version = picldiag_get_uint_propval(nodeh, OBP_PROP_MODREV_NUM,
3283 		    &err);
3284 		if (err == PICL_PROPNOTFOUND)
3285 			return (PICL_WALK_CONTINUE);
3286 	}
3287 	if (err != PICL_SUCCESS)
3288 		return (err);
3289 
3290 	/* devfs-path */
3291 	err =  picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH, &name);
3292 	if (err == PICL_PROPNOTFOUND)
3293 		name = NULL;
3294 	else if (err != PICL_SUCCESS)
3295 		return (err);
3296 
3297 	/* model */
3298 	err =  picldiag_get_string_propval(nodeh, PICL_PROP_BINDING_NAME,
3299 	    &model);
3300 	if (err == PICL_PROPNOTFOUND)
3301 		model = NULL;
3302 	else if (err != PICL_SUCCESS)
3303 		return (err);
3304 
3305 	/* status */
3306 	err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
3307 	if (err == PICL_PROPNOTFOUND)
3308 		status = NULL;
3309 	else if (err != PICL_SUCCESS)
3310 		return (err);
3311 
3312 	/*
3313 	 * Display the data
3314 	 */
3315 
3316 	/* name */
3317 	if (name != NULL) {
3318 		log_printf("%-22s ", name);
3319 		free(name);
3320 	} else
3321 		log_printf("%-22s ", "unknown");
3322 	/* model */
3323 	if (model != NULL) {
3324 		log_printf("%-15s  ", model);
3325 		free(model);
3326 	} else
3327 		log_printf("%-15s  ", "unknown");
3328 	/* status */
3329 	if (status == NULL)
3330 		log_printf("%-15s  ", "okay");
3331 	else {
3332 		log_printf("%-15s  ", status);
3333 		set_exit_code(status);
3334 		free(status);
3335 	}
3336 	/* revision */
3337 	log_printf("  %-4d\n",	version);
3338 
3339 	return (PICL_WALK_CONTINUE);
3340 }
3341 
3342 /*
3343  * traverse the tree to display asic revision id for ebus
3344  */
3345 /* ARGSUSED */
3346 static int
3347 ebus_callback(picl_nodehdl_t ebush, void *arg)
3348 {
3349 	uint32_t	id;
3350 	char		*name;
3351 	int		err;
3352 	char		*model;
3353 	char		*status;
3354 
3355 	id = picldiag_get_uint_propval(ebush, OBP_PROP_REVISION_ID, &err);
3356 	if (err == PICL_PROPNOTFOUND)
3357 		return (PICL_WALK_CONTINUE);
3358 	else if (err != PICL_SUCCESS)
3359 		return (err);
3360 
3361 	/* devfs-path */
3362 	err =  picldiag_get_string_propval(ebush, PICL_PROP_DEVFS_PATH, &name);
3363 	if (err == PICL_PROPNOTFOUND)
3364 		name = NULL;
3365 	else if (err != PICL_SUCCESS)
3366 		return (err);
3367 
3368 	/* model */
3369 	err =  picldiag_get_string_propval(ebush, PICL_PROP_BINDING_NAME,
3370 	    &model);
3371 	if (err == PICL_PROPNOTFOUND)
3372 		model = NULL;
3373 	else if (err != PICL_SUCCESS)
3374 		return (err);
3375 
3376 	/* status */
3377 	err = picldiag_get_string_propval(ebush, PICL_PROP_STATUS, &status);
3378 	if (err == PICL_PROPNOTFOUND)
3379 		status = NULL;
3380 	else if (err != PICL_SUCCESS)
3381 		return (err);
3382 
3383 	/*
3384 	 * Display the data
3385 	 */
3386 
3387 	/* name */
3388 	if (name != NULL) {
3389 		log_printf("%-22s ", name);
3390 		free(name);
3391 	} else
3392 		log_printf("%-22s ", "unknown");
3393 	/* model */
3394 	if (model != NULL) {
3395 		log_printf("%-15s  ", model);
3396 		free(model);
3397 	} else
3398 		log_printf("%-15s  ", "unknown");
3399 	/* status */
3400 	if (status == NULL)
3401 		log_printf("%-15s  ", "okay");
3402 	else {
3403 		log_printf("%-15s  ", status);
3404 		set_exit_code(status);
3405 		free(status);
3406 	}
3407 	/* revision */
3408 	log_printf("  %-4d\n",	id);
3409 
3410 	return (PICL_WALK_CONTINUE);
3411 }
3412 
3413 /*
3414  * display asic revision id
3415  */
3416 static int
3417 display_hw_revisions(picl_nodehdl_t plafh)
3418 {
3419 	int	err;
3420 
3421 	/* Print the header */
3422 	logprintf_header(dgettext(TEXT_DOMAIN, "HW Revisions"),
3423 	    DEFAULT_LINE_WIDTH);
3424 
3425 	log_printf("ASIC Revisions:\n");
3426 	log_printf("-----------------------------");
3427 	log_printf("--------------------------------------\n");
3428 	log_printf("Path                   Device");
3429 	log_printf("           Status             Revision\n");
3430 	log_printf("-----------------------------");
3431 	log_printf("--------------------------------------\n");
3432 
3433 	err = picl_walk_tree_by_class(plafh, NULL, NULL, asicrev_callback);
3434 	if (err != PICL_SUCCESS)
3435 		return (err);
3436 
3437 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_EBUS,
3438 	    NULL, ebus_callback);
3439 	if (err != PICL_SUCCESS)
3440 		return (err);
3441 
3442 	log_printf("\n");
3443 
3444 	err = picl_walk_tree_by_class(plafh, PICL_CLASS_DISPLAY,
3445 	    NULL, ffbconfig_callback);
3446 	return (err);
3447 }
3448 
3449 /*
3450  * find the options node and its powerfail_time prop
3451  * If found, display the list of latest powerfail.
3452  */
3453 /* ARGSUSED */
3454 static int
3455 options_callback(picl_nodehdl_t nodeh, void *arg)
3456 {
3457 	time_t		value;
3458 	char		*failtime;
3459 	int		err;
3460 
3461 	err = picldiag_get_string_propval(nodeh, PROP_POWERFAIL_TIME,
3462 	    &failtime);
3463 	if (err == PICL_PROPNOTFOUND)
3464 		return (PICL_WALK_TERMINATE);
3465 	else if (err != PICL_SUCCESS)
3466 		return (err);
3467 
3468 	value = (time_t)atoi(failtime);
3469 	free(failtime);
3470 	if (value == 0)
3471 		return (PICL_WALK_TERMINATE);
3472 
3473 	log_printf(dgettext(TEXT_DOMAIN, "Most recent AC Power Failure:\n"));
3474 	log_printf("=============================\n");
3475 	log_printf("%s", ctime(&value));
3476 	log_printf("\n");
3477 	return (PICL_WALK_TERMINATE);
3478 }
3479 
3480 /*
3481  * display the OBP and POST prom revisions
3482  */
3483 /* ARGSUSED */
3484 static int
3485 flashprom_callback(picl_nodehdl_t flashpromh, void *arg)
3486 {
3487 	picl_prophdl_t	proph;
3488 	picl_prophdl_t	tblh;
3489 	picl_prophdl_t	rowproph;
3490 	picl_propinfo_t	pinfo;
3491 	char		*prom_version = NULL;
3492 	char		*obp_version = NULL;
3493 	int		err;
3494 
3495 	err = picl_get_propinfo_by_name(flashpromh, OBP_PROP_VERSION,
3496 	    &pinfo, &proph);
3497 	if (err == PICL_PROPNOTFOUND)
3498 		return (PICL_WALK_TERMINATE);
3499 	else if (err != PICL_SUCCESS)
3500 		return (err);
3501 
3502 	log_printf(dgettext(TEXT_DOMAIN, "System PROM revisions:\n"));
3503 	log_printf("----------------------\n");
3504 
3505 	/*
3506 	 * If it's a table prop, the first element is OBP revision
3507 	 * The second one is POST revision.
3508 	 * If it's a charstring prop, the value will be only OBP revision
3509 	 */
3510 	if (pinfo.type == PICL_PTYPE_CHARSTRING) {
3511 		prom_version = alloca(pinfo.size);
3512 		if (prom_version == NULL)
3513 			return (PICL_FAILURE);
3514 		err = picl_get_propval(proph, prom_version, pinfo.size);
3515 		if (err != PICL_SUCCESS)
3516 			return (err);
3517 		log_printf("%s\n", prom_version);
3518 	}
3519 
3520 	if (pinfo.type != PICL_PTYPE_TABLE)	/* not supported type */
3521 		return (PICL_WALK_TERMINATE);
3522 
3523 	err = picl_get_propval(proph, &tblh, pinfo.size);
3524 	if (err != PICL_SUCCESS)
3525 		return (err);
3526 
3527 	err = picl_get_next_by_row(tblh, &rowproph);
3528 	if (err == PICL_SUCCESS) {
3529 		/* get first row */
3530 		err = picl_get_propinfo(rowproph, &pinfo);
3531 		if (err != PICL_SUCCESS)
3532 		    return (err);
3533 
3534 		prom_version = alloca(pinfo.size);
3535 		if (prom_version == NULL)
3536 			return (PICL_FAILURE);
3537 
3538 		err = picl_get_propval(rowproph, prom_version, pinfo.size);
3539 		if (err != PICL_SUCCESS)
3540 			return (err);
3541 		log_printf("%s\n", prom_version);
3542 
3543 		/* get second row */
3544 		err = picl_get_next_by_col(rowproph, &rowproph);
3545 		if (err == PICL_SUCCESS) {
3546 			err = picl_get_propinfo(rowproph, &pinfo);
3547 			if (err != PICL_SUCCESS)
3548 				return (err);
3549 
3550 			obp_version = alloca(pinfo.size);
3551 			if (obp_version == NULL)
3552 				return (PICL_FAILURE);
3553 			err = picl_get_propval(rowproph, obp_version,
3554 			    pinfo.size);
3555 			if (err != PICL_SUCCESS)
3556 				return (err);
3557 			log_printf("%s\n", obp_version);
3558 		}
3559 	}
3560 
3561 	return (PICL_WALK_TERMINATE);
3562 }
3563 
3564 static int
3565 display_system_info(int serrlog, int log_flag, picl_nodehdl_t rooth)
3566 {
3567 	int		err;
3568 	picl_nodehdl_t plafh;
3569 	picl_nodehdl_t frutreeh;
3570 
3571 	err = picldiag_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
3572 	if (err != PICL_SUCCESS)
3573 		return (err);
3574 
3575 	if (!log_flag) {
3576 		err = display_platform_banner(plafh);
3577 		if (err != PICL_SUCCESS)
3578 			return (err);
3579 
3580 		err = display_system_clock(plafh);
3581 		if (err != PICL_SUCCESS)
3582 			return (err);
3583 
3584 		err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY,
3585 		    PICL_CLASS_MEMORY, memory_callback);
3586 		if (err != PICL_SUCCESS)
3587 			return (err);
3588 
3589 		err = display_cpu_info(plafh);
3590 		if (err != PICL_SUCCESS)
3591 			return (err);
3592 
3593 		err = display_io_device_info(plafh);
3594 		if (err != PICL_SUCCESS)
3595 			return (err);
3596 
3597 		err = display_memory_config(plafh);
3598 		if (err != PICL_SUCCESS)
3599 			return (err);
3600 
3601 		err = display_usb_devices(plafh);
3602 		if (err != PICL_SUCCESS)
3603 			return (err);
3604 	}
3605 
3606 	if (serrlog) {
3607 		err = picl_walk_tree_by_class(rooth, PICL_CLASS_OPTIONS,
3608 		    NULL, options_callback);
3609 		if (err != PICL_SUCCESS)
3610 			return (err);
3611 
3612 		err = display_envctrl_status(plafh);
3613 		if (err != PICL_SUCCESS)
3614 			return (err);
3615 
3616 		err = picldiag_get_node_by_name(rooth, PICL_NODE_FRUTREE,
3617 		    &frutreeh);
3618 		if (err != PICL_SUCCESS)
3619 			return (err);
3620 
3621 		err = display_fru_oper_status(frutreeh);
3622 		if (err != PICL_SUCCESS)
3623 			return (err);
3624 
3625 		err = display_hw_revisions(plafh);
3626 		if (err != PICL_SUCCESS)
3627 			return (err);
3628 
3629 		err = picl_walk_tree_by_class(plafh, PICL_CLASS_FLASHPROM,
3630 		    NULL, flashprom_callback);
3631 		if (err != PICL_SUCCESS)
3632 			return (err);
3633 
3634 		err = display_serial_number(plafh);
3635 		if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
3636 			return (err);
3637 	}
3638 
3639 	return (PICL_SUCCESS);
3640 }
3641 
3642 /*
3643  * do_prominfo is called from main in prtdiag. It returns PD_SYSTEM_FAILURE if
3644  * any system failure is detected, PD_INTERNAL_FAILURE for internal errors and
3645  * PD_SUCCESS otherwise. main uses the return value as the exit code.
3646  */
3647 /* ARGSUSED */
3648 int
3649 do_prominfo(int serrlog, char *pgname, int log_flag, int prt_flag)
3650 {
3651 	int		err;
3652 	char		*errstr;
3653 	int		done;
3654 	picl_nodehdl_t	rooth;
3655 
3656 	err = picl_initialize();
3657 	if (err != PICL_SUCCESS) {
3658 		fprintf(stderr, EM_INIT_FAIL, picl_strerror(err));
3659 		return (PD_INTERNAL_FAILURE);
3660 	}
3661 
3662 	do {
3663 		done = 1;
3664 		err = picl_get_root(&rooth);
3665 		if (err != PICL_SUCCESS) {
3666 			fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err));
3667 			return (PD_INTERNAL_FAILURE);
3668 		}
3669 
3670 		err = display_system_info(serrlog, log_flag, rooth);
3671 
3672 		if ((err == PICL_STALEHANDLE) || (err == PICL_INVALIDHANDLE))
3673 			done = 0;
3674 	} while (!done);
3675 
3676 	if (err != PICL_SUCCESS) {
3677 		errstr = picl_strerror(err);
3678 		fprintf(stderr, EM_PRTDIAG_FAIL);
3679 		fprintf(stderr, "%s\n", errstr? errstr : " ");
3680 		exit_code = PD_INTERNAL_FAILURE;
3681 	}
3682 
3683 	(void) picl_shutdown();
3684 
3685 	return (exit_code);
3686 }
3687