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