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