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