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