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