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