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