summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorstevel <none@none>2006-03-29 15:44:11 -0800
committerstevel <none@none>2006-03-29 15:44:11 -0800
commit03831d35f7499c87d51205817c93e9a8d42c4bae (patch)
treebffe92ec7d68bd67b0cd216c9186bf7a01118b8a /usr/src/lib
parent1b01eaa0e4d0703606fba8c845845b4a7f0c0583 (diff)
downloadillumos-joyent-03831d35f7499c87d51205817c93e9a8d42c4bae.tar.gz
6392837 move sram to usr/src
6393316 move fcgp2 to usr/src 6393416 move gptwo_pci to usr/src 6393420 move gptwo_wci to usr/src 6393421 move sc_gptwocfg to usr/src 6393424 move axq to usr/src 6393425 move dman to usr/src 6393426 move iosram to usr/src 6393427 move mboxsc to usr/src 6393428 move sbdp to usr/src 6393429 move schpc to usr/src 6393432 move sckmdrv to usr/src 6393435 move scosmb to usr/src 6393437 move driver sgcn to usr/src 6393438 move sgenv to usr/src 6393439 move sgfru to usr/src 6393440 move driver sghsc to usr/src 6393441 move driver sgsbbc to usr/src 6393442 move driver ssm to usr/src 6393452 move pcf8574_nct to usr/src 6393453 move pcf8591_nct to usr/src 6393454 move acebus to usr/src 6393455 move scsb to usr/src 6393462 move lw8 to usr/src 6393463 move driver rmc_comm to usr/src 6393464 move driver rmcadm to usr/src 6393475 move todsg to usr/src 6393889 move libprtdiag to usr/src 6393890 move libprtdiag_psr to usr/src 6393896 move librsc to usr/src 6393898 move scadm to usr/src 6399766 move serengeti platform to usr/src 6399770 move starcat platform to usr/src 6400949 daktari platmod Makefile references incorrect platmod directory
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile18
-rw-r--r--usr/src/lib/libprtdiag/Makefile49
-rw-r--r--usr/src/lib/libprtdiag/Makefile.com71
-rw-r--r--usr/src/lib/libprtdiag/common/cpu.c246
-rw-r--r--usr/src/lib/libprtdiag/common/display_funcs.c184
-rw-r--r--usr/src/lib/libprtdiag/common/display_sun4u.c217
-rw-r--r--usr/src/lib/libprtdiag/common/display_sun4v.c330
-rw-r--r--usr/src/lib/libprtdiag/common/io.c1067
-rw-r--r--usr/src/lib/libprtdiag/common/kstat.c428
-rw-r--r--usr/src/lib/libprtdiag/common/libdevinfo_sun4u.c479
-rw-r--r--usr/src/lib/libprtdiag/common/llib-lprtdiag33
-rw-r--r--usr/src/lib/libprtdiag/common/memory.c541
-rw-r--r--usr/src/lib/libprtdiag/common/pdevinfo_funcs.c833
-rw-r--r--usr/src/lib/libprtdiag/common/pdevinfo_sun4u.c275
-rw-r--r--usr/src/lib/libprtdiag/common/pdevinfo_sun4v.c288
-rw-r--r--usr/src/lib/libprtdiag/common/prom.c134
-rw-r--r--usr/src/lib/libprtdiag/inc/display.h62
-rw-r--r--usr/src/lib/libprtdiag/inc/display_sun4u.h96
-rw-r--r--usr/src/lib/libprtdiag/inc/display_sun4v.h60
-rw-r--r--usr/src/lib/libprtdiag/inc/libprtdiag.h202
-rw-r--r--usr/src/lib/libprtdiag/inc/pdevinfo.h192
-rw-r--r--usr/src/lib/libprtdiag/inc/pdevinfo_sun4u.h233
-rw-r--r--usr/src/lib/libprtdiag/inc/reset_info.h108
-rw-r--r--usr/src/lib/libprtdiag/sparc/Makefile46
-rw-r--r--usr/src/lib/libprtdiag/sparc/sun4u/Makefile80
-rw-r--r--usr/src/lib/libprtdiag/sparc/sun4v/Makefile79
-rw-r--r--usr/src/lib/libprtdiag_psr/Makefile50
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/Makefile49
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/Makefile.com71
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/cherrystone/Makefile107
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/cherrystone.c919
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/workfile.c832
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/daktari/Makefile101
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/daktari/common/daktari.c1346
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/daktari/common/workfile.c939
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/desktop/Makefile47
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/desktop/common/desktop.c622
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/desktop/common/picldiag.c3687
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/desktop/nonpicl/Makefile107
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/desktop/picl/Makefile120
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/javelin/Makefile77
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/javelin/common/javelin.c1375
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/littleneck/Makefile84
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/littleneck/common/littleneck.c1072
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/littleneck/common/workfile.c955
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/lw8/Makefile47
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/lw8/common/lw8.c3607
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/lw8/picl/Makefile87
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/montecarlo/Makefile104
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/montecarlo/common/montecarlo.c2454
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/ontario/Makefile92
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.c546
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.h115
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.c649
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.h97
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.c496
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.h101
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/schumacher/Makefile47
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/schumacher/common/schumacher.c3257
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/schumacher/picl/Makefile89
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/serengeti/Makefile78
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/serengeti/common/serengeti.c2113
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/snowbird/Makefile95
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/snowbird/common/snowbird.c1120
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/starcat/Makefile74
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/starcat/common/starcat.c1169
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/starfire/Makefile70
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/starfire/common/starfire.c224
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/sunfire/Makefile68
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/sunfire/common/sunfire.c2284
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/tazmo/Makefile76
-rw-r--r--usr/src/lib/libprtdiag_psr/sparc/tazmo/common/tazmo.c1577
-rw-r--r--usr/src/lib/librsc/Makefile45
-rw-r--r--usr/src/lib/librsc/Makefile.com97
-rw-r--r--usr/src/lib/librsc/sparc/Makefile44
-rw-r--r--usr/src/lib/librsc/sparc/Makefile.com33
-rw-r--r--usr/src/lib/librsc/sparc/mpxu/Makefile45
-rw-r--r--usr/src/lib/librsc/sparc/mpxu/common/librsc.c711
-rw-r--r--usr/src/lib/librsc/sparc/mpxu/common/librsc.h118
79 files changed, 40729 insertions, 11 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index cfcba443d5..d17ca46109 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -218,12 +218,10 @@ SUBDIRS += \
sparc_SUBDIRS= .WAIT \
efcode \
- libc_psr .WAIT
-$(CLOSED_BUILD)sparc_SUBDIRS += \
- $(CLOSED)/lib/libprtdiag .WAIT \
- $(CLOSED)/lib/libprtdiag_psr \
- $(CLOSED)/lib/librsc
-sparc_SUBDIRS += \
+ libc_psr .WAIT \
+ libprtdiag .WAIT \
+ libprtdiag_psr \
+ librsc \
libfruutils .WAIT \
libfru \
libwrsmconf \
@@ -285,11 +283,9 @@ $(CLOSED_BUILD)MSGSUBDIRS += \
MSGSUBDIRS += \
$($(MACH)_MSGSUBDIRS)
-sparc_MSGSUBDIRS=
-
-$(CLOSED_BUILD)sparc_MSGSUBDIRS += \
- $(CLOSED)/lib/libprtdiag \
- $(CLOSED)/lib/libprtdiag_psr
+sparc_MSGSUBDIRS= \
+ libprtdiag \
+ libprtdiag_psr
HDRSUBDIRS= libaio \
auditd_plugins \
diff --git a/usr/src/lib/libprtdiag/Makefile b/usr/src/lib/libprtdiag/Makefile
new file mode 100644
index 0000000000..6a1f2a7e69
--- /dev/null
+++ b/usr/src/lib/libprtdiag/Makefile
@@ -0,0 +1,49 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag/Makefile
+#
+
+include $(SRC)/lib/Makefile.lib
+
+SUBDIRS= $(MACH)
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all install clean clobber lint _msg : $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libprtdiag/Makefile.com b/usr/src/lib/libprtdiag/Makefile.com
new file mode 100644
index 0000000000..0997c2f910
--- /dev/null
+++ b/usr/src/lib/libprtdiag/Makefile.com
@@ -0,0 +1,71 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Create default so empty rules don't
+# confuse make
+#
+CLASS = 32
+UTSBASE = $(SRC)/uts
+
+LIBRARY = libprtdiag.a
+VERS = .1
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/Makefile.psm
+
+LIBS = $(DYNLIB) $(LINTLIB)
+IFLAGS = -I ../../inc -I $(USR_PSM_INCL_DIR)
+IFLAGS += -I $(UTSBASE)/sun4u
+IFLAGS += -I $(UTSBASE)/sun4u/sunfire
+IFLAGS += -I $(UTSBASE)/sun4u/serengeti
+CPPFLAGS = $(IFLAGS) $(CPPFLAGS.master)
+CFLAGS += $(CCVERBOSE)
+LDLIBS += -lc -lkstat
+DYNFLAGS += -Wl,-f/usr/platform/\$$PLATFORM/lib/$(DYNLIBPSR)
+
+SRCDIR = ../../common
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+USR_PSMLINT= $(LINTSRC:%=$(USR_PSM_LIB_DIR)/%)
+
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file) ;\
+ $(RM) -r $(USR_PSM_LIB_DIR)/libprtdiag.so ;\
+ $(SYMLINK) ./libprtdiag.so$(VERS) $(USR_PSM_LIB_DIR)/libprtdiag.so
+
+$(USR_PSM_LIB_DIR)/%: $(SRCDIR)/%
+ $(INS.file)
+
+#
+# build rules
+#
+objs/%.o pics/%.o: ../../common/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/libprtdiag/common/cpu.c b/usr/src/lib/libprtdiag/common/cpu.c
new file mode 100644
index 0000000000..4248f3415c
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/cpu.c
@@ -0,0 +1,246 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <sys/spitregs.h>
+#include <sys/cheetahregs.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+/*
+ * Return the operating frequency of a processor in Hertz. This function
+ * requires as input a legal prom node pointer. If a NULL
+ * is passed in or the clock-frequency property does not exist, the
+ * function returns 0.
+ */
+int
+get_cpu_freq(Prom_node *pnode)
+{
+ Prop *prop;
+ int *value;
+
+ /* find the property */
+ if ((prop = find_prop(pnode, "clock-frequency")) == NULL) {
+ return (0);
+ }
+
+ if ((value = (int *)get_prop_val(prop)) == NULL) {
+ return (0);
+ }
+
+ return (*value);
+}
+
+/*
+ * returns the size of the given processors external cache in
+ * bytes. If the properties required to determine this are not
+ * present, then the function returns 0.
+ */
+int
+get_ecache_size(Prom_node *node)
+{
+ int *cache_size_p; /* pointer to number of cache lines */
+
+ /* find the properties */
+ if (cache_size_p = (int *)get_prop_val(find_prop(node,
+ "ecache-size"))) {
+ return (*cache_size_p);
+ }
+ if (cache_size_p = (int *)get_prop_val(find_prop(node,
+ "l3-cache-size"))) {
+ return (*cache_size_p);
+ }
+ if (cache_size_p = (int *)get_prop_val(find_prop(node,
+ "l2-cache-size"))) {
+ return (*cache_size_p);
+ }
+
+ return (0);
+}
+
+
+/*
+ * This routine is the generic link into displaying CPU and memory info.
+ * It displays the table header, then calls the CPU and memory display
+ * routine for all boards.
+ */
+void
+display_cpu_devices(Sys_tree *tree)
+{
+ Board_node *bnode;
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision of all cpus.
+ */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(" CPUs ", 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+ log_printf(" Run Ecache "
+ " CPU CPU\n", 0);
+ log_printf("Brd CPU Module MHz MB "
+ "Impl. Mask\n", 0);
+ log_printf("--- --- ------- ----- ------ "
+ "------ ----\n", 0);
+
+ /* Now display all of the cpus on each board */
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ display_cpus(bnode);
+ bnode = bnode->next;
+ }
+
+ log_printf("\n", 0);
+}
+
+/*
+ * Display the CPUs present on this board.
+ */
+void
+display_cpus(Board_node *board)
+{
+ Prom_node *cpu;
+
+ /*
+ * display the CPUs' operating frequency, cache size, impl. field
+ * and mask revision.
+ */
+ for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
+ cpu = dev_next_type(cpu, "cpu")) {
+ int freq; /* CPU clock frequency */
+ int ecache_size; /* External cache size */
+ int *mid;
+ int *impl;
+ int *mask, decoded_mask;
+
+ mid = (int *)get_prop_val(find_prop(cpu, "upa-portid"));
+ if (mid == NULL) {
+ mid = (int *)get_prop_val(find_prop(cpu, "portid"));
+ }
+
+ freq = (get_cpu_freq(cpu) + 500000) / 1000000;
+ ecache_size = get_ecache_size(cpu);
+ impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
+ mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
+
+ /* Do not display a failed CPU node */
+ if ((freq != 0) && (node_failed(cpu) == 0)) {
+ /* Board number */
+ display_boardnum(board->board_num);
+
+ /* CPU MID */
+ log_printf(" %2d ", *mid, 0);
+
+ /* Module number */
+ display_mid(*mid);
+
+ /* Running frequency */
+ log_printf(" %3d ", freq, 0);
+
+ /* Ecache size */
+ if (ecache_size == 0)
+ log_printf(" %3s ", "N/A", 0);
+ else
+ log_printf(" %4.1f ",
+ (float)ecache_size / (float)(1<<20),
+ 0);
+
+ /* Implementation */
+ if (impl == NULL) {
+ log_printf("%6s ", "N/A", 0);
+ } else {
+ switch (*impl) {
+ case SPITFIRE_IMPL:
+ log_printf("%-6s ", "US-I", 0);
+ break;
+ case BLACKBIRD_IMPL:
+ log_printf("%-6s ", "US-II", 0);
+ break;
+ case CHEETAH_IMPL:
+ log_printf("%-6s ", "US-III", 0);
+ break;
+ case CHEETAH_PLUS_IMPL:
+ log_printf("%-7s ", "US-III+", 0);
+ break;
+ case JAGUAR_IMPL:
+ log_printf("%-6s ", "US-IV", 0);
+ break;
+ default:
+ log_printf("%-6x ", *impl, 0);
+ break;
+ }
+ }
+
+ /* CPU Mask */
+ if (mask == NULL) {
+ log_printf(" %3s", "N/A", 0);
+ } else {
+ if ((impl) && IS_CHEETAH(*impl))
+ decoded_mask =
+ REMAP_CHEETAH_MASK(*mask);
+ else
+ decoded_mask = *mask;
+
+ log_printf(" %d.%d", (decoded_mask >> 4) & 0xf,
+ decoded_mask & 0xf, 0);
+ }
+
+ log_printf("\n", 0);
+ }
+ }
+}
+
+void
+display_mid(int mid)
+{
+ log_printf(" %2d ", mid, 0);
+}
diff --git a/usr/src/lib/libprtdiag/common/display_funcs.c b/usr/src/lib/libprtdiag/common/display_funcs.c
new file mode 100644
index 0000000000..80a9b8af1e
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/display_funcs.c
@@ -0,0 +1,184 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <sys/openpromio.h>
+#include <libintl.h>
+#include "pdevinfo.h"
+#include "display.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*
+ * external data
+ */
+extern int print_flag;
+extern int logging;
+
+/*
+ * The following macros for dealing with raw output from the Mostek 48T02
+ * were borrowed from the kernel. Openboot passes the raw Mostek data
+ * thru the device tree, and there are no library routines to deal with
+ * this data.
+ */
+
+/*
+ * Tables to convert a single byte from binary-coded decimal (BCD).
+ */
+static uchar_t bcd_to_byte[256] = { /* CSTYLED */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0, 0, 0, 0, 0, 0,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0, 0, 0, 0, 0, 0,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0, 0, 0, 0, 0, 0,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0, 0, 0, 0, 0, 0,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+};
+
+#define BCD_TO_BYTE(x) bcd_to_byte[(x) & 0xff]
+#define YRBASE 68
+
+static int days_thru_month[64] = {
+ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0, 0,
+ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
+ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
+ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0,
+};
+
+/*
+ * This function takes the raw Mostek data from the device tree translates
+ * it into UNIXC time (secs since Jan 1, 1970) and returns a string from
+ * ctime(3c).
+ */
+char *
+get_time(uchar_t *mostek)
+{
+ time_t utc;
+ int sec, min, hour, day, month, year;
+
+ year = BCD_TO_BYTE(mostek[6]) + YRBASE;
+ month = BCD_TO_BYTE(mostek[5] & 0x1f) + ((year & 3) << 4);
+ day = BCD_TO_BYTE(mostek[4] & 0x3f);
+ hour = BCD_TO_BYTE(mostek[2] & 0x3f);
+ min = BCD_TO_BYTE(mostek[1] & 0x7f);
+ sec = BCD_TO_BYTE(mostek[0] & 0x7f);
+
+ utc = (year - 70); /* next 3 lines: utc = 365y + y/4 */
+ utc += (utc << 3) + (utc << 6);
+ utc += (utc << 2) + ((year - 69) >> 2);
+ utc += days_thru_month[month] + day - 1;
+ utc = (utc << 3) + (utc << 4) + hour; /* 24 * day + hour */
+ utc = (utc << 6) - (utc << 2) + min; /* 60 * hour + min */
+ utc = (utc << 6) - (utc << 2) + sec; /* 60 * min + sec */
+
+ return (ctime((time_t *)&utc));
+}
+
+void
+disp_powerfail(Prom_node *root)
+{
+ Prom_node *pnode;
+ char *option_str = "options";
+ char *pf_str = "powerfail-time";
+ char *value_str;
+ time_t value;
+
+ pnode = dev_find_node(root, option_str);
+ if (pnode == NULL) {
+ return;
+ }
+
+ value_str = get_prop_val(find_prop(pnode, pf_str));
+ if (value_str == NULL) {
+ return;
+ }
+
+ value = (time_t)atoi(value_str);
+ if (value == 0)
+ return;
+
+ (void) log_printf(
+ dgettext(TEXT_DOMAIN,
+ "Most recent AC Power Failure:\n"));
+ (void) log_printf("=============================\n");
+ (void) log_printf("%s", ctime(&value));
+ (void) log_printf("\n");
+}
+
+
+/*VARARGS1*/
+void
+log_printf(char *fmt, ...)
+{
+ va_list ap;
+ int len;
+ static char bigbuf[4096];
+ char buffer[1024];
+
+ if (print_flag == 0) {
+ return;
+ }
+
+ va_start(ap, fmt);
+ if (logging != 0) {
+ len = vsprintf(buffer, fmt, ap);
+ (void) strcat(bigbuf, buffer);
+
+ /* we only call to syslog when we get the entire line. */
+ if (buffer[len-1] == '\n') {
+ syslog(LOG_DAEMON|LOG_NOTICE, bigbuf);
+ bigbuf[0] = 0;
+ }
+
+ } else {
+ (void) vprintf(fmt, ap);
+ }
+ va_end(ap);
+}
+
+void
+print_header(int board)
+{
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Analysis for Board %d\n"), board, 0);
+ log_printf("--------------------\n", 0);
+}
diff --git a/usr/src/lib/libprtdiag/common/display_sun4u.c b/usr/src/lib/libprtdiag/common/display_sun4u.c
new file mode 100644
index 0000000000..60638aa05d
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/display_sun4u.c
@@ -0,0 +1,217 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+extern int sys_clk;
+
+int
+display(Sys_tree *tree,
+ Prom_node *root,
+ struct system_kstat_data *kstats,
+ int syserrlog)
+{
+ int exit_code = 0; /* init to all OK */
+ void *value; /* used for opaque PROM data */
+ struct mem_total memory_total; /* Total memory in system */
+ struct grp_info grps; /* Info on all groups in system */
+
+ sys_clk = -1; /* System clock freq. (in MHz) */
+
+ /*
+ * silently check for any types of machine errors
+ */
+ exit_code = error_check(tree, kstats);
+
+ /*
+ * Now display the machine's configuration. We do this if we
+ * are not logging or exit_code is set (machine is broke).
+ */
+ if (!logging || exit_code) {
+ struct utsname uts_buf;
+
+ /*
+ * Display system banner
+ */
+ (void) uname(&uts_buf);
+
+ log_printf(
+ dgettext(TEXT_DOMAIN, "System Configuration: "
+ "Sun Microsystems %s %s\n"), uts_buf.machine,
+ get_prop_val(find_prop(root,
+ "banner-name")), 0);
+
+ /* display system clock frequency */
+ value = get_prop_val(find_prop(root, "clock-frequency"));
+ if (value != NULL) {
+ sys_clk = ((*((int *)value)) + 500000) / 1000000;
+ log_printf(dgettext(TEXT_DOMAIN, "System clock "
+ "frequency: %d MHz\n"), sys_clk, 0);
+ }
+
+ /* Display the Memory Size */
+ display_memorysize(tree, kstats, &grps, &memory_total);
+
+ /* Display platform specific configuration info */
+ display_platform_specific_header();
+
+ /* Display the CPU devices */
+ display_cpu_devices(tree);
+
+ /* Display the Memory configuration */
+ display_memoryconf(tree, &grps);
+
+ /* Display all the IO cards. */
+ (void) display_io_devices(tree);
+
+
+ /*
+ * Display any Hot plugged, disabled and failed board(s)
+ * where appropriate.
+ */
+ display_hp_fail_fault(tree, kstats);
+
+ display_diaginfo((syserrlog || (logging && exit_code)),
+ root, tree, kstats);
+ }
+
+ return (exit_code);
+}
+
+
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+#ifdef lint
+ tree = tree;
+ kstats = kstats;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+ return (0);
+}
+
+int
+disp_fail_parts(Sys_tree *tree)
+{
+#ifdef lint
+ tree = tree;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+ return (0);
+}
+
+
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+#ifdef lint
+ tree = tree;
+ kstats = kstats;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+}
+
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+#ifdef lint
+ flag = flag;
+ root = root;
+ tree = tree;
+ kstats = kstats;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+}
+
+
+void
+resolve_board_types(Sys_tree *tree)
+{
+#ifdef lint
+ tree = tree;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+}
+
+void
+display_boardnum(int num)
+{
+ log_printf("%2d ", num, 0);
+}
+
+
+/*
+ * The various platforms can over-ride this function to
+ * return any platform specific configuration information
+ * they may wish to return in addition to the generic output.
+ */
+void
+display_platform_specific_header(void)
+{
+ /*
+ * This function is intentionally empty
+ */
+}
diff --git a/usr/src/lib/libprtdiag/common/display_sun4v.c b/usr/src/lib/libprtdiag/common/display_sun4v.c
new file mode 100644
index 0000000000..42d998a12c
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/display_sun4v.c
@@ -0,0 +1,330 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "display_sun4v.h"
+#include "libprtdiag.h"
+
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+extern int sys_clk;
+
+int
+sun4v_display(Sys_tree *tree, Prom_node *root, int syserrlog,
+ picl_nodehdl_t plafh)
+{
+ int exit_code = 0; /* init to all OK */
+ void *value; /* used for opaque PROM data */
+ struct mem_total memory_total; /* Total memory in system */
+ struct grp_info grps; /* Info on all groups in system */
+
+ sys_clk = -1; /* System clock freq. (in MHz) */
+
+ /*
+ * Now display the machine's configuration. We do this if we
+ * are not logging.
+ */
+ if (!logging) {
+ struct utsname uts_buf;
+
+ /*
+ * Display system banner
+ */
+ (void) uname(&uts_buf);
+
+ log_printf(
+ dgettext(TEXT_DOMAIN, "System Configuration: "
+ "Sun Microsystems %s %s\n"), uts_buf.machine,
+ get_prop_val(find_prop(root,
+ "banner-name")), 0);
+
+ /* display system clock frequency */
+ value = get_prop_val(find_prop(root, "clock-frequency"));
+ if (value != NULL) {
+ sys_clk = ((*((int *)value)) + 500000) / 1000000;
+ log_printf(dgettext(TEXT_DOMAIN, "System clock "
+ "frequency: %d MHz\n"), sys_clk, 0);
+ }
+
+ /* Display the Memory Size */
+ display_memorysize(tree, NULL, &grps, &memory_total);
+
+ /* Display the CPU devices */
+ sun4v_display_cpu_devices(plafh);
+
+ /* Display the Memory configuration */
+ sun4v_display_memoryconf(plafh);
+
+ /* Display all the IO cards. */
+ (void) sun4v_display_pci(plafh);
+
+ sun4v_display_diaginfo((syserrlog || (logging)), root, plafh);
+ }
+
+ return (exit_code);
+}
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+void
+sun4v_display_pci(picl_nodehdl_t plafh)
+{
+#ifdef lint
+ plafh = plafh;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+}
+
+void
+sun4v_display_memoryconf(picl_nodehdl_t plafh)
+{
+#ifdef lint
+ plafh = plafh;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+}
+
+void
+sun4v_display_cpu_devices(picl_nodehdl_t plafh)
+{
+ char *fmt = "%-12s %-5s %-8s %-19s %-5s";
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision of all cpus.
+ */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "========================="
+ " CPUs "
+ "==============================================="
+ "\n"
+ "\n"));
+ log_printf(fmt, "", "", "", "CPU", "CPU", 0);
+ log_printf("\n");
+ log_printf(fmt, "Location", "CPU", "Freq",
+ "Implementation", "Mask", 0);
+ log_printf("\n");
+ log_printf(fmt, "------------", "-----", "--------",
+ "-------------------", "-----", 0);
+ log_printf("\n");
+
+ (void) picl_walk_tree_by_class(plafh, "cpu", "cpu", sun4v_display_cpus);
+
+ log_printf("\n");
+}
+
+/*
+ * Display the CPUs present on this board.
+ */
+/*ARGSUSED*/
+int
+sun4v_display_cpus(picl_nodehdl_t cpuh, void* args)
+{
+ int status;
+ picl_prophdl_t proph;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ picl_propinfo_t propinfo;
+ int *int_value;
+ uint64_t cpuid, mask_no;
+ char *comp_value;
+ char *no_prop_value = " ";
+ char freq_str[MAXSTRLEN];
+ char fru_name[MAXSTRLEN];
+
+ /*
+ * Get cpuid property and print it and the NAC name
+ */
+ status = picl_get_propinfo_by_name(cpuh, "cpuid", &propinfo, &proph);
+ if (status == PICL_SUCCESS) {
+ status = picl_get_propval(proph, &cpuid, sizeof (cpuid));
+ if (status != PICL_SUCCESS) {
+ log_printf("%-12s", no_prop_value);
+ log_printf("%6s", no_prop_value);
+ } else {
+ (void) snprintf(fru_name, sizeof (fru_name), "%s%d",
+ CPU_STRAND_NAC, (int)cpuid);
+ log_printf("%-12s", fru_name);
+ log_printf("%6d", (int)cpuid);
+ }
+ } else {
+ log_printf("%-12s", no_prop_value);
+ log_printf("%6s", no_prop_value);
+ }
+
+clock_freq:
+ status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo,
+ &proph);
+ if (status == PICL_SUCCESS) {
+ int_value = malloc(propinfo.size);
+ if (int_value == NULL) {
+ log_printf("%9s", no_prop_value);
+ goto compatible;
+ }
+ status = picl_get_propval(proph, int_value, propinfo.size);
+ if (status != PICL_SUCCESS) {
+ log_printf("%9s", no_prop_value);
+ } else {
+ /* Running frequency */
+ (void) snprintf(freq_str, sizeof (freq_str), "%d MHz",
+ CLK_FREQ_TO_MHZ(*int_value));
+ log_printf("%9s", freq_str);
+ }
+ free(int_value);
+ } else
+ log_printf("%9s", no_prop_value);
+
+compatible:
+ status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo,
+ &proph);
+ if (status == PICL_SUCCESS) {
+ if (propinfo.type == PICL_PTYPE_CHARSTRING) {
+ /*
+ * Compatible Property only has 1 value
+ */
+ comp_value = malloc(propinfo.size);
+ if (comp_value == NULL) {
+ log_printf("%20s", no_prop_value, 0);
+ goto mask;
+ }
+ status = picl_get_propval(proph, comp_value,
+ propinfo.size);
+ if (status == PICL_SUCCESS) {
+ log_printf("%20s", no_prop_value, 0);
+ free(comp_value);
+ }
+ } else if (propinfo.type == PICL_PTYPE_TABLE) {
+ /*
+ * Compatible Property has multiple values
+ */
+ status = picl_get_propval(proph, &tblh, propinfo.size);
+ if (status != PICL_SUCCESS) {
+ printf("Failed getting tblh\n");
+ log_printf("%20s", no_prop_value, 0);
+ goto mask;
+ }
+ status = picl_get_next_by_row(tblh, &rowproph);
+ if (status != PICL_SUCCESS) {
+ printf("Failed getting next by row\n");
+ log_printf("%20s", no_prop_value, 0);
+ goto mask;
+ }
+
+ status = picl_get_propinfo(rowproph, &propinfo);
+ if (status != PICL_SUCCESS) {
+ printf("Failed getting prop for rowproph\n");
+ log_printf("%20s", no_prop_value, 0);
+ goto mask;
+ }
+
+ comp_value = malloc(propinfo.size);
+ if (comp_value == NULL) {
+ printf("Failed to get malloc value?\n");
+ log_printf("%20s", no_prop_value, 0);
+ goto mask;
+ }
+
+ status = picl_get_propval(rowproph, comp_value,
+ propinfo.size);
+ if (status != PICL_SUCCESS) {
+ printf("Failed geting rowproph\n");
+ log_printf("%20s", no_prop_value, 0);
+ free(comp_value);
+ goto mask;
+ } else
+ log_printf("%20s", comp_value, 0);
+ free(comp_value);
+ }
+ } else
+ log_printf("%20s", no_prop_value, 0);
+
+mask:
+ status = picl_get_propinfo_by_name(cpuh, "mask#", &propinfo, &proph);
+ if (status == PICL_SUCCESS) {
+ status = picl_get_propval(proph, &mask_no, sizeof (mask_no));
+ if (status != PICL_SUCCESS) {
+ log_printf("%9s", no_prop_value);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN, " %2d.%d"),
+ (mask_no>> 4) & 0xf, mask_no & 0xf);
+ }
+ } else
+ log_printf("%9s", no_prop_value);
+
+done:
+ log_printf("\n");
+ return (PICL_WALK_CONTINUE);
+}
+
+void
+sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
+{
+#ifdef lint
+ flag = flag;
+ root = root;
+ plafh = plafh;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+}
+
+void
+display_boardnum(int num)
+{
+ log_printf("%2d ", num, 0);
+}
diff --git a/usr/src/lib/libprtdiag/common/io.c b/usr/src/lib/libprtdiag/common/io.c
new file mode 100644
index 0000000000..f1bdb447cc
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/io.c
@@ -0,0 +1,1067 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <sys/systeminfo.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+Prom_node *
+find_pci_bus(Prom_node *node, int id, int bus)
+{
+ Prom_node *pnode;
+
+ /* find the first pci node */
+ pnode = dev_find_node(node, "pci");
+
+ while (pnode != NULL) {
+ int tmp_id;
+ int tmp_bus;
+
+ tmp_id = get_id(pnode);
+ tmp_bus = get_pci_bus(pnode);
+
+ if ((tmp_id == id) &&
+ (tmp_bus == bus)) {
+ break;
+ }
+
+ pnode = dev_next_node(pnode, "pci");
+ }
+ return (pnode);
+}
+
+/*
+ * get_pci_bus
+ *
+ * Determines the PCI bus, either A (0) or B (1). If the function cannot
+ * find the bus-ranges property, it returns -1.
+ */
+int
+get_pci_bus(Prom_node *pnode)
+{
+ int *value;
+
+ /* look up the bus-range property */
+ if ((value = (int *)get_prop_val(find_prop(pnode, "bus-range"))) ==
+ NULL) {
+ return (-1);
+ }
+
+ if (*value == 0) {
+ return (1); /* B bus has a bus-range value = 0 */
+ } else {
+ return (0);
+ }
+}
+
+
+
+/*
+ * Find the PCI device number of this PCI device. If no device number can
+ * be determined, then return -1.
+ */
+int
+get_pci_device(Prom_node *pnode)
+{
+ void *value;
+
+ if ((value = get_prop_val(find_prop(pnode, "assigned-addresses"))) !=
+ NULL) {
+ return (PCI_DEVICE(*(int *)value));
+ } else {
+ return (-1);
+ }
+}
+
+/*
+ * Find the PCI device number of this PCI device. If no device number can
+ * be determined, then return -1.
+ */
+int
+get_pci_to_pci_device(Prom_node *pnode)
+{
+ void *value;
+
+ if ((value = get_prop_val(find_prop(pnode, "reg"))) !=
+ NULL) {
+ return (PCI_DEVICE(*(int *)value));
+ } else {
+ return (-1);
+ }
+}
+
+/*
+ * free_io_cards
+ * Frees the memory allocated for an io card list.
+ */
+void
+free_io_cards(struct io_card *card_list)
+{
+ /* Free the list */
+ if (card_list != NULL) {
+ struct io_card *p, *q;
+
+ for (p = card_list, q = NULL; p != NULL; p = q) {
+ q = p->next;
+ free(p);
+ }
+ }
+}
+
+
+/*
+ * insert_io_card
+ * Inserts an io_card structure into the list. The list is maintained
+ * in order based on board number and slot number. Also, the storage
+ * for the "card" argument is assumed to be handled by the caller,
+ * so we won't touch it.
+ */
+struct io_card *
+insert_io_card(struct io_card *list, struct io_card *card)
+{
+ struct io_card *newcard;
+ struct io_card *p, *q;
+
+ if (card == NULL)
+ return (list);
+
+ /* Copy the card to be added into new storage */
+ newcard = (struct io_card *)malloc(sizeof (struct io_card));
+ if (newcard == NULL) {
+ perror("malloc");
+ exit(2);
+ }
+ (void) memcpy(newcard, card, sizeof (struct io_card));
+ newcard->next = NULL;
+
+ if (list == NULL)
+ return (newcard);
+
+ /* Find the proper place in the list for the new card */
+ for (p = list, q = NULL; p != NULL; q = p, p = p->next) {
+ if (newcard->board < p->board)
+ break;
+ if ((newcard->board == p->board) && (newcard->slot < p->slot))
+ break;
+ }
+
+ /* Insert the new card into the list */
+ if (q == NULL) {
+ newcard->next = p;
+ return (newcard);
+ } else {
+ newcard->next = p;
+ q->next = newcard;
+ return (list);
+ }
+}
+
+
+char *
+fmt_manf_id(unsigned int encoded_id, char *outbuf)
+{
+ union manuf manuf;
+
+ /*
+ * Format the manufacturer's info. Note a small inconsistency we
+ * have to work around - Brooktree has it's part number in decimal,
+ * while Mitsubishi has it's part number in hex.
+ */
+ manuf.encoded_id = encoded_id;
+ switch (manuf.fld.manf) {
+ case MANF_BROOKTREE:
+ (void) sprintf(outbuf, "%s %d, version %d", "Brooktree",
+ manuf.fld.partno, manuf.fld.version);
+ break;
+
+ case MANF_MITSUBISHI:
+ (void) sprintf(outbuf, "%s %x, version %d", "Mitsubishi",
+ manuf.fld.partno, manuf.fld.version);
+ break;
+
+ default:
+ (void) sprintf(outbuf, "JED code %d, Part num 0x%x, version %d",
+ manuf.fld.manf, manuf.fld.partno, manuf.fld.version);
+ }
+ return (outbuf);
+}
+
+
+/*
+ * Find the sbus slot number of this Sbus device. If no slot number can
+ * be determined, then return -1.
+ */
+int
+get_sbus_slot(Prom_node *pnode)
+{
+ void *value;
+
+ if ((value = get_prop_val(find_prop(pnode, "reg"))) != NULL) {
+ return (*(int *)value);
+ } else {
+ return (-1);
+ }
+}
+
+
+/*
+ * This routine is the generic link into displaying system IO
+ * configuration. It displays the table header, then displays
+ * all the SBus cards, then displays all fo the PCI IO cards.
+ */
+void
+display_io_devices(Sys_tree *tree)
+{
+ Board_node *bnode;
+
+ /*
+ * TRANSLATION_NOTE
+ * Following string is used as a table header.
+ * Please maintain the current alignment in
+ * translation.
+ */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " IO Cards "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ display_sbus(bnode);
+ display_pci(bnode);
+ display_ffb(bnode, 1);
+ bnode = bnode->next;
+ }
+}
+
+void
+display_pci(Board_node *bnode)
+{
+#ifdef lint
+ bnode = bnode;
+#endif
+ /*
+ * This function is intentionally empty
+ */
+}
+
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == 0) {
+ log_printf(" Bus Freq\n", 0);
+ log_printf("Brd Type MHz Slot "
+ "Name "
+ "Model", 0);
+ log_printf("\n", 0);
+ log_printf("--- ---- ---- ---------- "
+ "---------------------------- "
+ "--------------------", 0);
+ log_printf("\n", 0);
+ banner = 1;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf("%2d ", p->board, 0);
+ log_printf("%-4s ", p->bus_type, 0);
+ log_printf("%3d ", p->freq, 0);
+ /*
+ * We check to see if it's an int or
+ * a char string to display for slot.
+ */
+ if (p->slot == PCI_SLOT_IS_STRING)
+ log_printf("%10s ", p->slot_str, 0);
+ else
+ log_printf("%10d ", p->slot, 0);
+
+ log_printf("%-28.28s", p->name, 0);
+ if (strlen(p->name) > 28)
+ log_printf("+ ", 0);
+ else
+ log_printf(" ", 0);
+ log_printf("%-19.19s", p->model, 0);
+ if (strlen(p->model) > 19)
+ log_printf("+", 0);
+ log_printf("\n", 0);
+ }
+}
+
+/*
+ * Display all FFBs on this board. It can either be in tabular format,
+ * or a more verbose format.
+ */
+void
+display_ffb(Board_node *board, int table)
+{
+ Prom_node *fb;
+ void *value;
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ char *type;
+ char *label;
+
+ if (board == NULL)
+ return;
+
+ /* Fill in common information */
+ card.display = 1;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, BUS_TYPE);
+ card.freq = sys_clk;
+
+ for (fb = dev_find_node_by_type(board->nodes, "device_type", "display");
+ fb != NULL;
+ fb = dev_next_node_by_type(fb, "device_type", "display")) {
+ value = get_prop_val(find_prop(fb, "name"));
+ if (value != NULL) {
+ if ((strcmp(FFB_NAME, value)) == 0) {
+ type = FFB_NAME;
+ label = "FFB";
+ } else if ((strcmp(AFB_NAME, value)) == 0) {
+ type = AFB_NAME;
+ label = "AFB";
+ } else
+ continue;
+ } else
+ continue;
+ if (table == 1) {
+ /* Print out in table format */
+
+ /* XXX - Get the slot number (hack) */
+ card.slot = get_id(fb);
+
+ /* Find out if it's single or double buffered */
+ (void) sprintf(card.name, "%s", label);
+ value = get_prop_val(find_prop(fb, "board_type"));
+ if (value != NULL)
+ if ((*(int *)value) & FFB_B_BUFF)
+ (void) sprintf(card.name,
+ "%s, Double Buffered", label);
+ else
+ (void) sprintf(card.name,
+ "%s, Single Buffered", label);
+
+ /*
+ * Print model number only if board_type bit 2
+ * is not set and it is not SUNW,XXX-XXXX.
+ */
+ card.model[0] = '\0';
+
+ if (strcmp(type, AFB_NAME) == 0) {
+ if (((*(int *)value) & 0x4) != 0x4) {
+ value = get_prop_val(find_prop(fb,
+ "model"));
+ if ((value != NULL) &&
+ (strcmp(value,
+ "SUNW,XXX-XXXX") != 0)) {
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+ }
+ }
+ } else {
+ value = get_prop_val(find_prop(fb, "model"));
+ if (value != NULL)
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+ }
+
+ card_list = insert_io_card(card_list, &card);
+ } else {
+ /* print in long format */
+ char device[MAXSTRLEN];
+ int fd = -1;
+ struct dirent *direntp;
+ DIR *dirp;
+ union strap_un strap;
+ struct ffb_sys_info fsi;
+
+ /* Find the device node using upa-portid/portid */
+ value = get_prop_val(find_prop(fb, "upa-portid"));
+ if (value == NULL)
+ value = get_prop_val(find_prop(fb, "portid"));
+
+ if (value == NULL)
+ continue;
+
+ (void) sprintf(device, "%s@%x", type,
+ *(int *)value);
+ if ((dirp = opendir("/devices")) == NULL)
+ continue;
+
+ while ((direntp = readdir(dirp)) != NULL) {
+ if (strstr(direntp->d_name, device) != NULL) {
+ (void) sprintf(device, "/devices/%s",
+ direntp->d_name);
+ fd = open(device, O_RDWR, 0666);
+ break;
+ }
+ }
+ (void) closedir(dirp);
+
+ if (fd == -1)
+ continue;
+
+ if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
+ continue;
+
+ log_printf("%s Hardware Configuration:\n", label, 0);
+ log_printf("-----------------------------------\n", 0);
+
+ strap.ffb_strap_bits = fsi.ffb_strap_bits;
+ log_printf("\tBoard rev: %d\n",
+ (int)strap.fld.board_rev, 0);
+ log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
+ log_printf("\tDAC: %s\n",
+ fmt_manf_id(fsi.dac_version, device), 0);
+ log_printf("\t3DRAM: %s\n",
+ fmt_manf_id(fsi.fbram_version, device), 0);
+ log_printf("\n", 0);
+ }
+
+ }
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+
+/*
+ * Display all the SBus IO cards on this board.
+ */
+void
+display_sbus(Board_node *board)
+{
+ struct io_card card;
+ struct io_card *card_list = NULL;
+ int freq;
+ int card_num;
+ void *value;
+ Prom_node *sbus;
+ Prom_node *card_node;
+
+ if (board == NULL)
+ return;
+
+ for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL;
+ sbus = dev_next_node(sbus, SBUS_NAME)) {
+
+ /* Skip failed nodes for now */
+ if (node_failed(sbus))
+ continue;
+
+ /* Calculate SBus frequency in MHz */
+ value = get_prop_val(find_prop(sbus, "clock-frequency"));
+ if (value != NULL)
+ freq = ((*(int *)value) + 500000) / 1000000;
+ else
+ freq = -1;
+
+ for (card_node = sbus->child; card_node != NULL;
+ card_node = card_node->sibling) {
+ char *model;
+ char *name;
+ char *child_name;
+
+ card_num = get_sbus_slot(card_node);
+ if (card_num == -1)
+ continue;
+
+ /* Fill in card information */
+ card.display = 1;
+ card.freq = freq;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "SBus");
+ card.slot = card_num;
+ card.status[0] = '\0';
+
+ /* Try and get card status */
+ value = get_prop_val(find_prop(card_node, "status"));
+ if (value != NULL)
+ (void) strncpy(card.status, (char *)value,
+ MAXSTRLEN);
+
+ /* XXX - For now, don't display failed cards */
+ if (strstr(card.status, "fail") != NULL)
+ continue;
+
+ /* Now gather all of the node names for that card */
+ model = (char *)get_prop_val(find_prop(card_node,
+ "model"));
+ name = get_node_name(card_node);
+
+ if (name == NULL)
+ continue;
+
+ card.name[0] = '\0';
+ card.model[0] = '\0';
+
+ /* Figure out how we want to display the name */
+ child_name = get_node_name(card_node->child);
+ if ((card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(card_node->child,
+ "device_type"));
+ if (value != NULL)
+ (void) sprintf(card.name, "%s/%s (%s)",
+ name, child_name,
+ (char *)value);
+ else
+ (void) sprintf(card.name, "%s/%s", name,
+ child_name);
+ } else {
+ (void) strncpy(card.name, name, MAXSTRLEN);
+ }
+
+ if (model != NULL)
+ (void) strncpy(card.model, model, MAXSTRLEN);
+
+ card_list = insert_io_card(card_list, &card);
+ }
+ }
+
+ /* We're all done gathering card info, now print it out */
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+
+/*
+ * Get slot-names properties from parent node and
+ * store them in an array.
+ */
+int
+populate_slot_name_arr(Prom_node *pci, int *slot_name_bits,
+ char **slot_name_arr, int num_slots)
+{
+ int i, j, bit_mask;
+ char *value;
+
+ value = (char *)get_prop_val(find_prop(pci, "slot-names"));
+ D_PRINTF("\n populate_slot_name_arr: value = [0x%x]\n", value);
+
+ if (value != NULL) {
+ char *strings_arr[MAX_SLOTS_PER_IO_BD];
+ bit_mask = *slot_name_bits = *(int *)value;
+ D_PRINTF("\nslot_names 1st integer = [0x%x]", *slot_name_bits);
+
+ /* array starts after first int */
+ strings_arr[0] = value + sizeof (int);
+
+ /*
+ * break the array out into num_slots number of strings
+ */
+ for (i = 1; i < num_slots; i++) {
+ strings_arr[i] = (char *)strings_arr[i - 1]
+ + strlen(strings_arr[i - 1]) + 1;
+ }
+
+ /*
+ * process array of slot_names to remove blanks
+ */
+ j = 0;
+ for (i = 0; i < num_slots; i++) {
+ if ((bit_mask >> i) & 0x1)
+ slot_name_arr[i] = strings_arr[j++];
+ else
+ slot_name_arr[i] = "";
+
+ D_PRINTF("\nslot_name_arr[%d] = [%s]", i,
+ slot_name_arr[i]);
+ }
+ return (0);
+ } else {
+ D_PRINTF("\n populate_slot_name_arr: - psycho with no "
+ "slot-names\n");
+ return (0);
+ }
+}
+
+int
+get_card_frequency(Prom_node *pci)
+{
+ char *value = get_prop_val(find_prop(pci, "clock-frequency"));
+
+ if (value == NULL)
+ return (-1);
+ else
+ return (int)(((*(int *)value) + 500000) / 1000000);
+
+}
+
+void
+get_dev_func_num(Prom_node *card_node, int *dev_no, int *func_no)
+{
+
+ void *value = get_prop_val(find_prop(card_node, "reg"));
+
+ if (value != NULL) {
+ int int_val = *(int *)value;
+ *dev_no = PCI_REG_TO_DEV(int_val);
+ *func_no = PCI_REG_TO_FUNC(int_val);
+ } else {
+ *dev_no = -1;
+ *func_no = -1;
+ }
+}
+
+void
+get_pci_class_codes(Prom_node *card_node, int *class_code, int *subclass_code)
+{
+ int class_code_reg = get_pci_class_code_reg(card_node);
+
+ *class_code = CLASS_REG_TO_CLASS(class_code_reg);
+ *subclass_code = CLASS_REG_TO_SUBCLASS(class_code_reg);
+}
+
+int
+is_pci_bridge(Prom_node *card_node, char *name)
+{
+ int class_code, subclass_code;
+
+ if (card_node == NULL)
+ return (FALSE);
+
+ get_pci_class_codes(card_node, &class_code, &subclass_code);
+
+ if ((strncmp(name, "pci", 3) == 0) &&
+ (class_code == PCI_BRIDGE_CLASS) &&
+ (subclass_code == PCI_PCI_BRIDGE_SUBCLASS))
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+int
+is_pci_bridge_other(Prom_node *card_node, char *name)
+{
+ int class_code, subclass_code;
+
+ if (card_node == NULL)
+ return (FALSE);
+
+ get_pci_class_codes(card_node, &class_code, &subclass_code);
+
+ if ((strncmp(name, "pci", 3) == 0) &&
+ (class_code == PCI_BRIDGE_CLASS) &&
+ (subclass_code == PCI_SUBCLASS_OTHER))
+ return (TRUE);
+ else
+ return (FALSE);
+}
+void
+get_pci_card_model(Prom_node *card_node, char *model)
+{
+ char *name = get_prop_val(find_prop(card_node, "name"));
+ char *value = get_prop_val(find_prop(card_node, "model"));
+ int pci_bridge = is_pci_bridge(card_node, name);
+
+ if (value == NULL)
+ model[0] = '\0';
+ else
+ (void) sprintf(model, "%s",
+ (char *)value);
+
+ if (pci_bridge) {
+ if (strlen(model) == 0)
+ (void) sprintf(model,
+ "%s", "pci-bridge");
+ else
+ (void) sprintf(model,
+ "%s/pci-bridge", model);
+ }
+}
+
+void
+create_io_card_name(Prom_node *card_node, char *name, char *card_name)
+{
+ char *value = get_prop_val(find_prop(card_node, "compatible"));
+ char *child_name;
+ char buf[MAXSTRLEN];
+
+ if (value != NULL) {
+ (void) sprintf(buf, "%s-%s", name,
+ (char *)value);
+ } else
+ (void) sprintf(buf, "%s", name);
+
+ name = buf;
+
+ child_name = (char *)get_node_name(card_node->child);
+
+ if ((card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(card_node->child,
+ "device_type"));
+ if (value != NULL)
+ (void) sprintf(card_name, "%s/%s (%s)",
+ name, child_name,
+ (char *)value);
+ else
+ (void) sprintf(card_name, "%s/%s", name,
+ child_name);
+ } else {
+ (void) sprintf(card_name, "%s", (char *)name);
+ }
+}
+
+
+/*
+ * Desktop display_psycho_pci
+ * Display all the psycho based PCI IO cards on this board.
+ */
+
+/* ARGSUSED */
+void
+display_psycho_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+
+ Prom_node *pci, *card_node, *pci_bridge_node = NULL;
+ char *name;
+ int slot_name_bits, pci_bridge_dev_no,
+ class_code, subclass_code,
+ pci_pci_bridge;
+ char *slot_name_arr[MAX_SLOTS_PER_IO_BD];
+
+ if (board == NULL)
+ return;
+
+ /* Initialize all the common information */
+ card.display = 1;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "PCI");
+
+ for (pci = dev_find_node_by_type(board->nodes, "model", "SUNW,psycho");
+ pci != NULL;
+ pci = dev_next_node_by_type(pci, "model", "SUNW,psycho")) {
+
+ /*
+ * If we have reached a pci-to-pci bridge node,
+ * we are one level below the 'pci' nodes level
+ * in the device tree. To get back to that level,
+ * the search should continue with the sibling of
+ * the parent or else the remaining 'pci' cards
+ * will not show up in the output.
+ */
+ if (find_prop(pci, "upa-portid") == NULL) {
+ if ((pci->parent->sibling != NULL) &&
+ (strcmp(get_prop_val(
+ find_prop(pci->parent->sibling,
+ "name")), PCI_NAME) == 0))
+ pci = pci->parent->sibling;
+ else {
+ pci = pci->parent->sibling;
+ continue;
+ }
+ }
+
+ D_PRINTF("\n\n------->Looking at device [%s][%d] - [%s]\n",
+ PCI_NAME, *((int *)get_prop_val(find_prop(
+ pci, "upa-portid"))),
+ get_prop_val(find_prop(pci, "model")));
+
+ /* Skip all failed nodes for now */
+ if (node_failed(pci))
+ continue;
+
+ /* Fill in frequency */
+ card.freq = get_card_frequency(pci);
+
+ /*
+ * Each PSYCHO device has a slot-names property that can be
+ * used to determine the slot-name string for each IO
+ * device under this node. We get this array now and use
+ * it later when looking at the children of this PSYCHO.
+ */
+ if ((populate_slot_name_arr(pci, &slot_name_bits,
+ (char **)&slot_name_arr, MAX_SLOTS_PER_IO_BD)) != 0)
+ goto next_card;
+
+ /* Walk through the PSYCHO children */
+ card_node = pci->child;
+ while (card_node != NULL) {
+
+ pci_pci_bridge = FALSE;
+
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(card_node, "name"));
+ if (name == NULL)
+ goto next_card;
+
+ /* get dev# and func# for this card. */
+ get_dev_func_num(card_node, &card.dev_no,
+ &card.func_no);
+
+ /* get class/subclass code for this card. */
+ get_pci_class_codes(card_node, &class_code,
+ &subclass_code);
+
+ D_PRINTF("\nName [%s] - ", name);
+ D_PRINTF("device no [%d] - ", card.dev_no);
+ D_PRINTF("class_code [%d] subclass_code [%d] - ",
+ class_code, subclass_code);
+
+ /*
+ * Weed out PCI Bridge, subclass 'other' and
+ * ebus nodes.
+ */
+ if (((class_code == PCI_BRIDGE_CLASS) &&
+ (subclass_code == PCI_SUBCLASS_OTHER)) ||
+ (strstr(name, "ebus"))) {
+ D_PRINTF("\nSkip ebus/class-other nodes [%s]",
+ name);
+ goto next_card;
+ }
+
+ /*
+ * If this is a PCI bridge, then we store it's dev_no
+ * so that it's children can use it for getting at
+ * the slot_name.
+ */
+ if (is_pci_bridge(card_node, name)) {
+ pci_bridge_dev_no = card.dev_no;
+ pci_bridge_node = card_node;
+ pci_pci_bridge = TRUE;
+ D_PRINTF("\nPCI Bridge detected\n");
+ }
+
+ /*
+ * If we are the child of a pci_bridge we use the
+ * dev# of the pci_bridge as an index to get
+ * the slot number. We know that we are a child of
+ * a pci-bridge if our parent is the same as the last
+ * pci_bridge node found above.
+ */
+ if (card_node->parent == pci_bridge_node)
+ card.dev_no = pci_bridge_dev_no;
+
+ /* Get slot-names property from slot_names_arr. */
+ get_slot_number_str(&card, (char **)slot_name_arr,
+ slot_name_bits);
+
+ if (slot_name_bits)
+ D_PRINTF("\nIO Card [%s] dev_no [%d] SlotStr "
+ "[%s] slot [%s]", name, card.dev_no,
+ slot_name_arr[card.dev_no],
+ card.slot_str);
+
+ /* XXX - Don't know how to get status for PCI cards */
+ card.status[0] = '\0';
+
+ /* Get the model of this card */
+ get_pci_card_model(card_node, (char *)&card.model);
+
+ /*
+ * If we haven't figured out the frequency yet,
+ * try and get it from the card.
+ */
+ value = get_prop_val(find_prop(pci, "clock-frequency"));
+ if (value != NULL && card.freq == -1)
+ card.freq = ((*(int *)value) + 500000)
+ / 1000000;
+
+
+ /* Figure out how we want to display the name */
+ create_io_card_name(card_node, name,
+ (char *)&card.name);
+
+ if (card.freq != -1)
+ card_list = insert_io_card(card_list, &card);
+
+next_card:
+ /*
+ * If we are done with the children of the pci bridge,
+ * we must continue with the remaining siblings of
+ * the pci-to-pci bridge - otherwise we move onto our
+ * own sibling.
+ */
+ if (pci_pci_bridge) {
+ if (card_node->child != NULL)
+ card_node = card_node->child;
+ else
+ card_node = card_node->sibling;
+ } else {
+ if ((card_node->parent == pci_bridge_node) &&
+ (card_node->sibling == NULL))
+ card_node = pci_bridge_node->sibling;
+ else
+ card_node = card_node->sibling;
+ }
+ } /* end-while */
+ } /* end-for */
+
+ D_PRINTF("\n\n");
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+void
+get_slot_number_str(struct io_card *card, char **slot_name_arr,
+ int slot_name_bits)
+{
+ if (card->dev_no != -1) {
+ char *slot;
+ /*
+ * slot_name_bits is a mask of the plug-in slots so if our
+ * dev_no does not appear in this mask we must be an
+ * on_board device so set the slot to 'On-Board'
+ */
+ if (slot_name_bits & (1 << card->dev_no)) {
+ /* we are a plug-in card */
+ slot = slot_name_arr[card->dev_no];
+ if (strlen(slot) != 0) {
+ (void) sprintf(card->slot_str, "%s",
+ slot);
+ } else
+ (void) sprintf(card->slot_str, "-");
+ } else {
+ /* this is an on-board dev. */
+ sprintf(card->slot_str, "On-Board");
+ }
+
+ } else {
+ (void) sprintf(card->slot_str, "%c", '-');
+ }
+
+ /* Informs display_io_cards to print slot_str instead of slot */
+ card->slot = PCI_SLOT_IS_STRING;
+}
+
+
+/*
+ * The output of a number of I/O cards are identical so we need to
+ * differentiate between them.
+ *
+ * This function is called by the platform specific code and it decides
+ * if the card needs further processing.
+ *
+ * It can be extended in the future if card types other than QLC have
+ * the same problems.
+ */
+void
+distinguish_identical_io_cards(char *name, Prom_node *node,
+ struct io_card *card)
+{
+ if ((name == NULL) || (node == NULL))
+ return;
+
+ if (strcmp(name, "SUNW,qlc") == 0)
+ decode_qlc_card_model_prop(node, card);
+}
+
+
+/*
+ * The name/model properties for a number of the QLC FCAL PCI cards are
+ * identical (*), so we need to distinguish them using the subsystem-id
+ * and modify the model string to be more informative.
+ *
+ * (*) Currently the problem cards are:
+ * Amber
+ * Crystal+
+ */
+void
+decode_qlc_card_model_prop(Prom_node *card_node, struct io_card *card)
+{
+ void *value = NULL;
+
+ if (card_node == NULL)
+ return;
+
+ value = get_prop_val(find_prop(card_node, "subsystem-id"));
+ if (value != NULL) {
+ int id = *(int *)value;
+
+ switch (id) {
+ case AMBER_SUBSYSTEM_ID:
+ (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
+ AMBER_CARD_NAME);
+ break;
+
+ case CRYSTAL_SUBSYSTEM_ID:
+ (void) snprintf(card->model, MAX_QLC_MODEL_LEN, "%s",
+ CRYSTAL_CARD_NAME);
+ break;
+
+ default:
+ /*
+ * If information has been saved into the model field
+ * before this function was called we will keep it as
+ * it probably will be more meaningful that the
+ * subsystem-id, otherwise we save the subsystem-id in
+ * the hope that it will distinguish the cards.
+ */
+ if (strcmp(card->model, "") == 0) {
+ (void) snprintf(card->model, MAX_QLC_MODEL_LEN,
+ "0x%x", id);
+ }
+ break;
+ }
+ }
+}
diff --git a/usr/src/lib/libprtdiag/common/kstat.c b/usr/src/lib/libprtdiag/common/kstat.c
new file mode 100644
index 0000000000..1c29e96642
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/kstat.c
@@ -0,0 +1,428 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+/*
+ * This module does the reading and interpreting of sun4u system
+ * kstats. These kstats are created by the following drivers:
+ * fhc, environ, sysctrl. Each board in the tree should have
+ * kstats created for it. There are also system wide kstats that
+ * are created.
+ */
+void
+read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep)
+{
+ Board_node *bnode;
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ int i;
+ struct hp_info *hp;
+
+#ifdef lint
+ ep = ep;
+#endif
+ if ((kc = kstat_open()) == NULL) {
+ return;
+ }
+
+ /* For each board in the system, read the kstats for it. */
+ for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) {
+ int board;
+
+ /*
+ * Kstat instances numbers are set by fhc, ac, simmstat,
+ * and environ drivers based on their board# property.
+ */
+ board = bnode->board_num;
+ bdp = &sys_kstat->bd_ksp_list[board];
+
+ /* Try to find an FHC instance for this board number */
+ ksp = kstat_lookup(kc, UNIX, board, FHC_KSTAT_NAME);
+
+ /* Atempt to read the FHC kstat */
+ if ((ksp != NULL) && (kstat_read(kc, ksp, NULL) == -1)) {
+ ksp = NULL;
+ }
+
+ /* Now read out the data if the kstat read OK */
+ if (ksp != NULL) {
+ /*
+ * We set the kstats_ok flag to good here. If we
+ * fail one of the data reads, we set it to bad.
+ */
+ bdp->fhc_kstats_ok = 1;
+
+ /*
+ * For each data value, If the Kstat named struct
+ * is found, then get the data out.
+ */
+ knp = kstat_data_lookup(ksp, CSR_KSTAT_NAMED);
+ if (knp != NULL) {
+ bdp->fhc_csr = knp->value.ul;
+ } else {
+ bdp->fhc_kstats_ok = 0;
+ }
+ knp = kstat_data_lookup(ksp, BSR_KSTAT_NAMED);
+ if (knp != NULL) {
+ bdp->fhc_bsr = knp->value.ul;
+ } else {
+ bdp->fhc_kstats_ok = 0;
+ }
+ }
+
+ /* Try to find an AC instance for this board number */
+ ksp = kstat_lookup(kc, UNIX, board, AC_KSTAT_NAME);
+
+ /* Attempt to read the AC kstat. */
+ if ((ksp != NULL) && (kstat_read(kc, ksp, NULL) == -1)) {
+ ksp = NULL;
+ }
+
+ /* If the AC kstat exists, try to read the data from it. */
+ if (ksp != NULL) {
+ /*
+ * We set the kstats_ok flag to good here. If we
+ * fail one of the data reads, we set it to bad.
+ */
+ bdp->ac_kstats_ok = 1;
+ bdp->ac_memstat_ok = 1;
+
+ /*
+ * For each data value, If the Kstat named struct
+ * is found, then get the data out.
+ */
+
+ knp = kstat_data_lookup(ksp, MEMCTL_KSTAT_NAMED);
+ if (knp != NULL) {
+ bdp->ac_memctl = knp->value.ull;
+ } else {
+ bdp->ac_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, MEMDECODE0_KSTAT_NAMED);
+ if (knp != NULL) {
+ bdp->ac_memdecode[0] = knp->value.ull;
+ } else {
+ bdp->ac_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, MEMDECODE1_KSTAT_NAMED);
+ if (knp != NULL) {
+ bdp->ac_memdecode[1] = knp->value.ull;
+ } else {
+ bdp->ac_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, BANK_0_KSTAT_NAMED);
+ if (knp != NULL) {
+ bdp->mem_stat[0].status = knp->value.c[0];
+ bdp->mem_stat[0].condition = knp->value.c[1];
+ } else {
+ bdp->ac_memstat_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, BANK_1_KSTAT_NAMED);
+ if (knp != NULL) {
+ bdp->mem_stat[1].status = knp->value.c[0];
+ bdp->mem_stat[1].condition = knp->value.c[1];
+ } else {
+ bdp->ac_memstat_ok = 0;
+ }
+
+ }
+
+ /* Try to find an simmstat instance for this board number */
+ ksp = kstat_lookup(kc, UNIX, board, SIMMSTAT_KSTAT_NAME);
+
+ if (ksp != NULL) {
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ bdp->simmstat_kstats_ok = 0;
+ } else {
+ bdp->simmstat_kstats_ok = 1;
+ (void) memcpy(&bdp->simm_status, ksp->ks_data,
+ sizeof (bdp->simm_status));
+ }
+ }
+
+ /* Try to find an overtemp kstat instance for this board */
+ ksp = kstat_lookup(kc, UNIX, board, OVERTEMP_KSTAT_NAME);
+
+ if (ksp != NULL) {
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ bdp->temp_kstat_ok = 0;
+ } else {
+ bdp->temp_kstat_ok = 1;
+ (void) memcpy(&bdp->tempstat, ksp->ks_data,
+ sizeof (bdp->tempstat));
+ /* XXX - this is for 2.5.1 testing. remove */
+ if (sizeof (bdp->tempstat) > ksp->ks_data_size)
+ bdp->tempstat.trend = TREND_UNKNOWN;
+ }
+ }
+ }
+
+ /* Read the kstats for the system control board */
+ ksp = kstat_lookup(kc, UNIX, 0, SYSCTRL_KSTAT_NAME);
+
+ if ((ksp != NULL) && (kstat_read(kc, ksp, NULL) == -1)) {
+ sys_kstat->sys_kstats_ok = 0;
+ ksp = NULL;
+ }
+
+ if (ksp != NULL) {
+ sys_kstat->sys_kstats_ok = 1;
+
+ knp = kstat_data_lookup(ksp, CSR_KSTAT_NAMED);
+ if (knp != NULL) {
+ sys_kstat->sysctrl = knp->value.c[0];
+ } else {
+ sys_kstat->sys_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, STAT1_KSTAT_NAMED);
+ if (knp != NULL) {
+ sys_kstat->sysstat1 = knp->value.c[0];
+ } else {
+ sys_kstat->sys_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, STAT2_KSTAT_NAMED);
+ if (knp != NULL) {
+ sys_kstat->sysstat2 = knp->value.c[0];
+ } else {
+ sys_kstat->sys_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, CLK_FREQ2_KSTAT_NAMED);
+ if (knp != NULL) {
+ sys_kstat->clk_freq2 = knp->value.c[0];
+ } else {
+ sys_kstat->sys_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, FAN_KSTAT_NAMED);
+ if (knp != NULL) {
+ sys_kstat->fan_status = knp->value.c[0];
+ } else {
+ sys_kstat->sys_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, KEY_KSTAT_NAMED);
+ if (knp != NULL) {
+ sys_kstat->keysw_status = knp->value.c[0];
+ } else {
+ sys_kstat->sys_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, POWER_KSTAT_NAMED);
+ if (knp != NULL) {
+ sys_kstat->power_state =
+ (enum power_state)knp->value.l;
+ } else {
+ sys_kstat->sys_kstats_ok = 0;
+ }
+
+ knp = kstat_data_lookup(ksp, CLK_VER_KSTAT_NAME);
+ if (knp != NULL) {
+ sys_kstat->clk_ver = knp->value.c[0];
+ } else {
+ /*
+ * the clock version register only appears
+ * on new clock boards
+ */
+ sys_kstat->clk_ver = 0;
+ }
+
+ }
+
+ /* Read the kstats for the power supply stats */
+ ksp = kstat_lookup(kc, UNIX, 0, PSSHAD_KSTAT_NAME);
+
+ if ((ksp != NULL) && (kstat_read(kc, ksp, NULL) != -1)) {
+ sys_kstat->psstat_kstat_ok = 1;
+ (void) memcpy(&sys_kstat->ps_shadow[0], ksp->ks_data,
+ sizeof (sys_kstat->ps_shadow));
+ } else {
+ sys_kstat->psstat_kstat_ok = 0;
+ }
+
+ /* read the overtemp kstat for the system control board */
+ /* Try to find an overtemp kstat instance for this board */
+ ksp = kstat_lookup(kc, UNIX, CLOCK_BOARD_INDEX, OVERTEMP_KSTAT_NAME);
+
+ if (ksp != NULL) {
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ sys_kstat->temp_kstat_ok = 0;
+ } else {
+ sys_kstat->temp_kstat_ok = 1;
+ (void) memcpy(&sys_kstat->tempstat, ksp->ks_data,
+ sizeof (sys_kstat->tempstat));
+ /* XXX - this is for 2.5.1 testing. remove */
+ if (sizeof (sys_kstat->tempstat) > ksp->ks_data_size)
+ sys_kstat->tempstat.trend = TREND_UNKNOWN;
+ }
+ }
+
+ /* Read the reset-info kstat from one of the boards. */
+ ksp = kstat_lookup(kc, UNIX, 0, RESETINFO_KSTAT_NAME);
+
+ if (ksp == NULL) {
+ sys_kstat->reset_kstats_ok = 0;
+ } else if (kstat_read(kc, ksp, NULL) == -1) {
+ sys_kstat->reset_kstats_ok = 0;
+ } else {
+ sys_kstat->reset_kstats_ok = 1;
+ (void) memcpy(&sys_kstat->reset_info, ksp->ks_data,
+ sizeof (sys_kstat->reset_info));
+ }
+
+ /* read kstats for hotplugged boards */
+ for (i = 0, hp = &sys_kstat->hp_info[0]; i < MAX_BOARDS; i++, hp++) {
+ ksp = kstat_lookup(kc, UNIX, i, BDLIST_KSTAT_NAME);
+
+ if (ksp == NULL) {
+ continue;
+ }
+
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ hp->kstat_ok = 0;
+ } else {
+ hp->kstat_ok = 1;
+ (void) memcpy(&hp->bd_info, ksp->ks_data,
+ sizeof (hp->bd_info));
+ }
+ }
+
+ /* read in the kstat for the fault list. */
+ ksp = kstat_lookup(kc, UNIX, 0, FT_LIST_KSTAT_NAME);
+
+ if (ksp == NULL) {
+ sys_kstat->ft_kstat_ok = 0;
+ } else {
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ perror("kstat read");
+ sys_kstat->ft_kstat_ok = 0;
+ return;
+ }
+
+ sys_kstat->nfaults = ksp->ks_data_size /
+ sizeof (struct ft_list);
+
+ sys_kstat->ft_array =
+ (struct ft_list *)malloc(ksp->ks_data_size);
+
+ if (sys_kstat->ft_array == NULL) {
+ perror("Malloc");
+ exit(2);
+ }
+ sys_kstat->ft_kstat_ok = 1;
+ (void) memcpy(sys_kstat->ft_array, ksp->ks_data,
+ ksp->ks_data_size);
+ }
+}
+
+/*
+ * This function does the reading and interpreting of sun4u system
+ * kstats. These kstats are created by the following drivers:
+ * fhc, environ, sysctrl. Each board in the tree should have
+ * kstats created for it. There are also system wide kstats that
+ * are created.
+ */
+void
+read_sun4u_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat)
+{
+#if 0
+ Board_node *bnode;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ struct hp_info *hp;
+ struct envctrltwo_kstat_data *ecp;
+#endif
+ kstat_ctl_t *kc;
+ int i;
+ struct bd_kstat_data *bdp;
+ struct envctrl_kstat_data *ep;
+
+ if ((kc = kstat_open()) == NULL) {
+ return;
+ }
+#ifdef lint
+ kc = kc;
+#endif
+
+ /* Initialize the kstats structure */
+ sys_kstat->sys_kstats_ok = 0;
+ sys_kstat->temp_kstat_ok = 0;
+ sys_kstat->reset_kstats_ok = 0;
+ sys_kstat->ft_kstat_ok = 0;
+ sys_kstat->envctrl_kstat_ok = 0;
+ for (i = 0; i < MAX_BOARDS; i++) {
+ bdp = &sys_kstat->bd_ksp_list[i];
+ bdp->ac_kstats_ok = 0;
+ bdp->fhc_kstats_ok = 0;
+ bdp->simmstat_kstats_ok = 0;
+ bdp->temp_kstat_ok = 0;
+
+ sys_kstat->hp_info[i].kstat_ok = 0;
+ }
+ for (i = 0; i < MAX_DEVS; i++) {
+ ep = &sys_kstat->env_data;
+ ep->ps_kstats[i].instance = I2C_NODEV;
+ ep->fan_kstats[i].instance = I2C_NODEV;
+ ep->encl_kstats[i].instance = I2C_NODEV;
+ }
+
+ read_platform_kstats(tree, sys_kstat, bdp, ep);
+}
diff --git a/usr/src/lib/libprtdiag/common/libdevinfo_sun4u.c b/usr/src/lib/libprtdiag/common/libdevinfo_sun4u.c
new file mode 100644
index 0000000000..c7d73f5445
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/libdevinfo_sun4u.c
@@ -0,0 +1,479 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <libdevinfo.h>
+
+#include "pdevinfo.h"
+#include "pdevinfo_sun4u.h"
+#include "display.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+/*
+ * This file contains the functions that are to be called when
+ * a platform wants to use libdevinfo for it's device information
+ * instead of OBP. This will allow prtdiag to support hot-plug
+ * events on platforms whose OBP doesn't get updated to reflect
+ * the hot-plug changes to the system.
+ */
+
+int do_devinfo(int syserrlog, char *pgname, int log_flag,
+ int prt_flag);
+static void dump_di_node(Prom_node *pnode, di_node_t di_node);
+static Prom_node *walk_di_tree(Sys_tree *tree, Prom_node *root,
+ di_node_t di_node);
+static int match_compatible_name(char *, int, char *);
+
+/*
+ * Global variables
+ */
+di_prom_handle_t ph; /* Handle for using di_prom interface */
+extern char *progname;
+
+
+
+/*
+ * Used instead of the walk() function when a platform wants to
+ * walk libdevinfo's device tree instead of walking OBP's
+ * device tree.
+ */
+static Prom_node*
+walk_di_tree(Sys_tree *tree, Prom_node *root, di_node_t di_node)
+{
+ di_node_t curnode;
+ Prom_node *pnode;
+ char *name, *type, *model, *compatible_array;
+ int board_node = 0;
+ int *int_val;
+ int portid;
+ int is_schizo = 0, n_names;
+
+ /* allocate a node for this level */
+ if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
+ NULL) {
+ perror("malloc");
+ exit(2);
+ }
+
+ /* assign parent Prom_node */
+ pnode->parent = root;
+ pnode->sibling = NULL;
+ pnode->child = NULL;
+
+ /* read properties for this node */
+ dump_di_node(pnode, di_node);
+
+ name = get_node_name(pnode);
+ type = get_node_type(pnode);
+ if (type == NULL)
+ type = "";
+ model = (char *)get_prop_val(find_prop(pnode, "model"));
+ if (model == NULL)
+ model = "";
+
+ /*
+ * For identifying Schizo nodes we need to check if the
+ * compatible property contains the string 'pci108e,8001'.
+ * This property contains an array of strings so we need
+ * search all strings.
+ */
+ if ((n_names = di_compatible_names(di_node, &compatible_array)) > 0) {
+ if (match_compatible_name(compatible_array, n_names,
+ "pci108e,8001"))
+ is_schizo = 1;
+ }
+
+ if (int_val = (int *)get_prop_val(find_prop(pnode, "portid")))
+ portid = *int_val;
+ else if ((strcmp(type, "cpu") == 0) &&
+ (int_val = (int *)get_prop_val(find_prop(pnode->parent, "portid"))))
+ portid = *int_val;
+ else
+ portid = -1;
+
+#ifdef DEBUG
+ if (name != NULL)
+ printf("name=%s\n", name);
+ if (type != NULL)
+ printf("type=%s\n", type);
+ if (model != NULL)
+ printf("model=%s\n", model);
+ printf("portid=%d\n", portid);
+#endif
+
+ if (name != NULL) {
+ if (has_board_num(pnode)) {
+ add_node(tree, pnode);
+ board_node = 1;
+ D_PRINTF("\n---\nnodename = %s [ %s ] \n",
+ di_node_name(di_node), di_devfs_path(di_node));
+ D_PRINTF("ADDED BOARD name=%s type=%s model=%s "
+ "portid =%d\n", name, type, model, portid);
+ } else if ((strcmp(name, FFB_NAME) == 0) ||
+ (strcmp(type, "cpu") == 0) ||
+
+ ((strcmp(type, "memory-controller") == 0) &&
+ (strcmp(name, "ac") != 0)) ||
+
+ ((strcmp(name, "pci") == 0) &&
+ (strcmp(model, "SUNW,psycho") == 0)) ||
+
+ ((strcmp(name, "pci") == 0) &&
+ (strcmp(model, "SUNW,sabre") == 0)) ||
+
+ ((strcmp(name, "pci") == 0) && (is_schizo)) ||
+
+ (strcmp(name, "counter-timer") == 0) ||
+ (strcmp(name, "sbus") == 0)) {
+ add_node(tree, pnode);
+ board_node = 1;
+ D_PRINTF("\n---\nnodename = %s [ %s ] \n",
+ di_node_name(di_node), di_devfs_path(di_node));
+ D_PRINTF("ADDED BOARD name=%s type=%s model=%s\n",
+ name, type, model);
+ }
+ } else {
+ D_PRINTF("node not added: type=%s portid =%d\n", type, portid);
+ }
+
+ if (curnode = di_child_node(di_node)) {
+ pnode->child = walk_di_tree(tree, pnode, curnode);
+ }
+
+ if (curnode = di_sibling_node(di_node)) {
+ if (board_node) {
+ return (walk_di_tree(tree, root, curnode));
+ } else {
+ pnode->sibling = walk_di_tree(tree, root, curnode);
+ }
+ }
+
+ /*
+ * This check is needed in case the "board node" occurs at the
+ * end of the sibling chain as opposed to the middle or front.
+ */
+ if (board_node)
+ return (NULL);
+
+ return (pnode);
+}
+
+/*
+ * Dump all the devinfo properties and then the obp properties for
+ * the specified devinfo node into the Prom_node structure.
+ */
+static void
+dump_di_node(Prom_node *pnode, di_node_t di_node)
+{
+ Prop *prop = NULL; /* tail of properties list */
+
+ Prop *temp; /* newly allocated property */
+ di_prop_t di_prop;
+ di_prom_prop_t p_prop;
+ int retval = 0;
+ int i;
+
+ /* clear out pointers in pnode */
+ pnode->props = NULL;
+
+ D_PRINTF("\n\n ------- Dumping devinfo properties for node ------\n");
+
+ /*
+ * get all the devinfo properties first
+ */
+ for (di_prop = di_prop_next(di_node, DI_PROP_NIL);
+ di_prop != DI_PROP_NIL;
+ di_prop = di_prop_next(di_node, di_prop)) {
+
+ char *di_name;
+ void *di_data;
+ int di_ptype;
+
+ di_name = di_prop_name(di_prop);
+ if (di_name == (char *)NULL)
+ continue;
+
+ di_ptype = di_prop_type(di_prop);
+ D_PRINTF("DEVINFO Properties %s: ", di_name);
+
+ switch (di_ptype) {
+ int *int_val;
+ char *char_val;
+ case DI_PROP_TYPE_INT:
+ retval = di_prop_lookup_ints(DDI_DEV_T_ANY,
+ di_node, di_name, (int **)&di_data);
+ if (retval > 0) {
+ int_val = (int *)di_data;
+ D_PRINTF("0x%x\n", *int_val);
+ }
+ break;
+ case DI_PROP_TYPE_STRING:
+ retval = di_prop_lookup_strings(DDI_DEV_T_ANY,
+ di_node, di_name, (char **)&di_data);
+ if (retval > 0) {
+ char_val = (char *)di_data;
+ D_PRINTF("%s\n", char_val);
+ }
+ break;
+ case DI_PROP_TYPE_BYTE:
+ retval = di_prop_lookup_bytes(DDI_DEV_T_ANY,
+ di_node, di_name, (uchar_t **)&di_data);
+ if (retval > 0) {
+ char_val = (char *)di_data;
+ D_PRINTF("%s\n", char_val);
+ }
+ break;
+ case DI_PROP_TYPE_UNKNOWN:
+ retval = di_prop_lookup_bytes(DDI_DEV_T_ANY,
+ di_node, di_name, (uchar_t **)&di_data);
+ if (retval > 0) {
+ char_val = (char *)di_data;
+ D_PRINTF("%s\n", char_val);
+ }
+ break;
+ case DI_PROP_TYPE_BOOLEAN:
+ di_data = NULL;
+ retval = 1;
+ break;
+ default:
+ D_PRINTF(" Skipping property\n");
+ retval = -1;
+ }
+
+ if (retval <= 0)
+ continue;
+
+ /* allocate space for the property */
+ if ((temp = (Prop *) malloc(sizeof (Prop))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ /*
+ * Given that we're using libdevinfo rather than OBP,
+ * the chances are that future accesses to di_name and
+ * di_data will be via temp->name.val_ptr and
+ * temp->value.val_ptr respectively. However, this may
+ * not be the case, so we have to suitably fill in
+ * temp->name.opp and temp->value.opp.
+ *
+ * di_name is char * and non-NULL if we've made it to
+ * here, so we can simply point
+ * temp->name.opp.oprom_array to temp->name.val_ptr.
+ *
+ * di_data could be NULL, char * or int * at this point.
+ * If it's non-NULL, a 1st char of '\0' indicates int *.
+ * We thus set temp->value.opp.oprom_node[] (although
+ * interest in any element other than 0 is rare, all
+ * elements must be set to ensure compatibility with
+ * OBP), and holds_array is set to 0.
+ *
+ * If di_data is NULL, or the 1st char is not '\0', we set
+ * temp->value.opp.oprom_array. If di_ptype is
+ * DI_PROP_TYPE_BOOLEAN, holds_array is set to 0, else it
+ * is set to 1.
+ */
+ temp->name.val_ptr = (void *)di_name;
+ temp->name.opp.oprom_array = temp->name.val_ptr;
+ temp->name.opp.holds_array = 1;
+
+ temp->value.val_ptr = (void *)di_data;
+ if ((di_data != NULL) && (*((char *)di_data) == '\0')) {
+ for (i = 0; i < OPROM_NODE_SIZE; i++)
+ temp->value.opp.oprom_node[i] = *((int *)di_data+i);
+
+ temp->value.opp.holds_array = 0;
+ } else {
+ temp->value.opp.oprom_array = temp->value.val_ptr;
+ if (di_ptype == DI_PROP_TYPE_BOOLEAN)
+ temp->value.opp.holds_array = 0;
+ else
+ temp->value.opp.holds_array = 1;
+ }
+
+ temp->size = retval;
+
+ /* everything worked so link the property list */
+ if (pnode->props == NULL)
+ pnode->props = temp;
+ else if (prop != NULL)
+ prop->next = temp;
+ prop = temp;
+ prop->next = NULL;
+ }
+
+ /*
+ * Then get all the OBP properties.
+ */
+ for (p_prop = di_prom_prop_next(ph, di_node, DI_PROM_PROP_NIL);
+ p_prop != DI_PROM_PROP_NIL;
+ p_prop = di_prom_prop_next(ph, di_node, p_prop)) {
+
+ char *p_name;
+ unsigned char *p_data;
+
+ p_name = di_prom_prop_name(p_prop);
+ if (p_name == (char *)NULL)
+ retval = -1;
+ else
+ retval = di_prom_prop_data(p_prop, &p_data);
+
+ if (retval <= 0)
+ continue;
+
+ /* allocate space for the property */
+ if ((temp = (Prop *) malloc(sizeof (Prop))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ /*
+ * As above, p_name is char * and non-NULL if we've made
+ * it to here, so we can simply point
+ * temp->name.opp.oprom_array to temp->name.val_ptr.
+ *
+ * p_data could be NULL, a character or a number at this
+ * point. If it's non-NULL, a 1st char of '\0' indicates a
+ * number, so we set temp->value.opp.oprom_node[] (again
+ * setting every element to ensure OBP compatibility).
+ * These assignments create a lint error, hence the LINTED
+ * comment.
+ *
+ * If p_data is NULL, or the 1st char is not '\0', we set
+ * temp->value.opp.oprom_array.
+ */
+ temp->name.val_ptr = (void *)p_name;
+ temp->name.opp.oprom_array = temp->name.val_ptr;
+ temp->name.opp.holds_array = 1;
+
+ temp->value.val_ptr = (void *)p_data;
+ if ((p_data != NULL) && (*p_data == '\0')) {
+ for (i = 0; i < OPROM_NODE_SIZE; i++)
+ /* LINTED */
+ temp->value.opp.oprom_node[i] = *((int *)p_data+i);
+
+ temp->value.opp.holds_array = 0;
+ } else {
+ temp->value.opp.oprom_array = temp->value.val_ptr;
+ temp->value.opp.holds_array = 1;
+ }
+
+ temp->size = retval;
+
+ /* everything worked so link the property list */
+ if (pnode->props == NULL) {
+ pnode->props = temp;
+ } else if (prop != NULL) {
+ prop->next = temp;
+ }
+ prop = temp;
+ prop->next = NULL;
+ }
+}
+
+/*
+ * Used in place of do_prominfo() when a platform wants to use
+ * libdevinfo for getting the device tree instead of OBP.
+ */
+int
+do_devinfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+ Sys_tree sys_tree; /* system information */
+ Prom_node *root_node; /* root node of OBP device tree */
+ di_node_t di_root_node; /* root of the devinfo tree */
+ struct system_kstat_data sys_kstat; /* kstats for non-OBP data */
+ int retval = -1;
+
+ /* set the global flags */
+ progname = pgname;
+ logging = log_flag;
+ print_flag = prt_flag;
+
+ /* set the the system tree fields */
+ sys_tree.sys_mem = NULL;
+ sys_tree.boards = NULL;
+ sys_tree.bd_list = NULL;
+ sys_tree.board_cnt = 0;
+
+ /*
+ * create a snapshot of the kernel device tree
+ * and return a handle to it.
+ */
+ if ((di_root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
+ exit(_error("di_init() failed"));
+ }
+
+ /*
+ * create a handle to the PROM device tree.
+ */
+ if ((ph = di_prom_init()) == NULL) {
+ exit(_error("di_prom_init() failed"));
+ }
+
+ /*
+ * walk the devinfo tree and build up a list of all
+ * nodes and properties.
+ */
+ root_node = walk_di_tree(&sys_tree, NULL, di_root_node);
+
+ /* resolve the board types now */
+ resolve_board_types(&sys_tree);
+
+ read_sun4u_kstats(&sys_tree, &sys_kstat);
+ retval = display(&sys_tree, root_node, &sys_kstat, syserrlog);
+
+ di_fini(di_root_node);
+ di_prom_fini(ph);
+ return (retval);
+}
+
+/*
+ * check to see if the name shows up in the compatible array
+ */
+static int
+match_compatible_name(char *compatible_array, int n_names, char *name)
+{
+ int i, ret = 0;
+
+ /* parse the compatible list */
+ for (i = 0; i < n_names; i++) {
+ if (strcmp(compatible_array, name) == 0) {
+ ret = 1;
+ break;
+ }
+ compatible_array += strlen(compatible_array) + 1;
+ }
+ return (ret);
+}
diff --git a/usr/src/lib/libprtdiag/common/llib-lprtdiag b/usr/src/lib/libprtdiag/common/llib-lprtdiag
new file mode 100644
index 0000000000..5c7ac4ce3b
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/llib-lprtdiag
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <sys/types.h>
+#include "libprtdiag.h"
diff --git a/usr/src/lib/libprtdiag/common/memory.c b/usr/src/lib/libprtdiag/common/memory.c
new file mode 100644
index 0000000000..1e1aaff425
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/memory.c
@@ -0,0 +1,541 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include <sys/sbd_ioctl.h>
+#include <sys/sbdp_mem.h>
+#include <sys/serengeti.h>
+#include <sys/mc.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+#define KBYTE 1024
+#define MBYTE (KBYTE * KBYTE)
+
+#define MEM_UK_SIZE_MASK 0x3FF
+
+/*
+ * Global variables.
+ */
+static memory_bank_t *bank_head;
+static memory_bank_t *bank_tail;
+static memory_seg_t *seg_head;
+
+/*
+ * Local functions.
+ */
+static void add_bank_node(uint64_t mc_decode, int portid, char *bank_status);
+static void add_seg_node(void);
+static memory_seg_t *match_seg(uint64_t);
+
+
+/*
+ * Used for US-I and US-II systems
+ */
+/*ARGSUSED0*/
+void
+display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats,
+ struct grp_info *grps, struct mem_total *memory_total)
+{
+ log_printf(dgettext(TEXT_DOMAIN, "Memory size: "), 0);
+
+ if (sysconf(_SC_PAGESIZE) == -1 || sysconf(_SC_PHYS_PAGES) == -1)
+ log_printf(dgettext(TEXT_DOMAIN, "unable to determine\n"), 0);
+ else {
+ uint64_t mem_size;
+
+ mem_size =
+ (uint64_t)sysconf(_SC_PAGESIZE) * \
+ (uint64_t)sysconf(_SC_PHYS_PAGES);
+
+ if (mem_size >= MBYTE)
+ log_printf(dgettext(TEXT_DOMAIN, "%d Megabytes\n"),
+ (int)((mem_size+MBYTE-1) / MBYTE), 0);
+ else
+ log_printf(dgettext(TEXT_DOMAIN, "%d Kilobytes\n"),
+ (int)((mem_size+KBYTE-1) / KBYTE), 0);
+ }
+}
+
+/*ARGSUSED0*/
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ /*
+ * This function is intentionally blank
+ */
+}
+
+/*
+ * The following functions are for use by any US-III based systems.
+ * All they need to do is to call get_us3_mem_regs()
+ * and then display_us3_banks(). Each platform then needs to decide how
+ * to format this data by over-riding the generic function
+ * print_us3_memory_line().
+ */
+int
+get_us3_mem_regs(Board_node *bnode)
+{
+ Prom_node *pnode;
+ int portid;
+ uint64_t *ma_reg_arr;
+ uint64_t madr[NUM_MBANKS_PER_MC];
+ void *bank_status_array;
+ char *bank_status;
+ int i, status_offset;
+
+ for (pnode = dev_find_node(bnode->nodes, "memory-controller");
+ pnode != NULL;
+ pnode = dev_next_node(pnode, "memory-controller")) {
+
+ /* Get portid of this mc from libdevinfo. */
+ portid = (*(int *)get_prop_val(find_prop(pnode, "portid")));
+
+ /* read the logical_bank_ma_regs property for this mc node. */
+ ma_reg_arr = (uint64_t *)get_prop_val(
+ find_prop(pnode, MEM_CFG_PROP_NAME));
+
+ /*
+ * There are situations where a memory-controller node
+ * will not have the logical_bank_ma_regs property and
+ * we need to allow for these cases. They include:
+ * - Excalibur/Littleneck systems that only
+ * support memory on one of their CPUs.
+ * - Systems that support DR where a cpu board
+ * can be unconfigured but still connected.
+ * It is up to the caller of this function to ensure
+ * that the bank_head and seg_head pointers are not
+ * NULL after processing all memory-controllers in the
+ * system. This would indicate a situation where no
+ * memory-controllers in the system have a logical_bank_ma_regs
+ * property which should never happen.
+ */
+ if (ma_reg_arr == NULL)
+ continue;
+
+ /*
+ * The first NUM_MBANKS_PER_MC of uint64_t's in the
+ * logical_bank_ma_regs property are the madr values.
+ */
+ for (i = 0; i < NUM_MBANKS_PER_MC; i++) {
+ madr[i] = *ma_reg_arr++;
+ }
+
+ /*
+ * Get the bank_status property for this mem controller from
+ * OBP. This contains the bank-status for each logical bank.
+ */
+ bank_status_array = (void *)get_prop_val(
+ find_prop(pnode, "bank-status"));
+ status_offset = 0;
+
+ /*
+ * process each logical bank
+ */
+ for (i = 0; i < NUM_MBANKS_PER_MC; i++) {
+ /*
+ * Get the bank-status string for this bank
+ * from the bank_status_array we just retrieved
+ * from OBP. If the prop was not found, we
+ * malloc a bank_status and set it to "no_status".
+ */
+ if (bank_status_array) {
+ bank_status = ((char *)bank_status_array +
+ status_offset);
+
+ /* Move offset to next bank_status string */
+ status_offset += (strlen(bank_status) + 1);
+ } else {
+ bank_status = malloc(strlen("no_status"));
+ strcpy(bank_status, "no_status");
+ }
+
+ /*
+ * create a bank_node for this bank
+ * and add it to the list.
+ */
+ add_bank_node(madr[i], portid, bank_status);
+
+ /*
+ * find the segment to which this bank
+ * belongs. If it doesn't already exist
+ * then create it. If it exists, add to it.
+ */
+ add_seg_node();
+ }
+ }
+ return (0);
+}
+
+static void
+add_bank_node(uint64_t mc_decode, int portid, char *bank_status)
+{
+ static int id = 0;
+ memory_bank_t *new, *bank;
+ uint32_t ifactor = MC_INTLV(mc_decode);
+ uint64_t seg_size;
+
+ if ((new = malloc(sizeof (memory_bank_t))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ new->portid = portid;
+ new->id = id++;
+ new->valid = (mc_decode >> 63);
+ new->uk = MC_UK(mc_decode);
+ new->um = MC_UM(mc_decode);
+ new->lk = MC_LK(mc_decode);
+ new->lm = MC_LM(mc_decode);
+
+ seg_size = ((((uint64_t)new->uk & MEM_UK_SIZE_MASK) + 1) << 26);
+ new->bank_size = seg_size / ifactor;
+ new->bank_status = bank_status;
+
+ new->next = NULL;
+ new->seg_next = NULL;
+
+ /* Handle the first bank found */
+ if (bank_head == NULL) {
+ bank_head = new;
+ bank_tail = new;
+ return;
+ }
+
+ /* find last bank in list */
+ bank = bank_head;
+ while (bank->next)
+ bank = bank->next;
+
+ /* insert this bank into the list */
+ bank->next = new;
+ bank_tail = new;
+}
+
+void
+display_us3_banks(void)
+{
+ uint64_t base, bank_size;
+ uint32_t intlv;
+ memory_bank_t *bank, *tmp_bank;
+ memory_seg_t *seg;
+ int mcid;
+ uint64_t dimm_size;
+ uint64_t total_bank_size = 0;
+ uint64_t total_sys_mem;
+ static uint64_t bank0_size, bank1_size, bank2_size, bank3_size;
+
+ if ((bank_head == NULL) || (seg_head == NULL)) {
+ log_printf("\nCannot find any memory bank/segment info.\n");
+ return;
+ }
+
+ for (bank = bank_head; bank; bank = bank->next) {
+ /*
+ * Interleave factor is determined from the
+ * lk bits in the Mem Addr Decode register.
+ *
+ * The Base Address of the memory segment in which this
+ * bank belongs is determined from the um abd uk bits
+ * of the Mem Addr Decode register.
+ *
+ * See section 9.1.5 of Cheetah Programmer's reference
+ * manual.
+ */
+ intlv = ((bank->lk ^ 0xF) + 1);
+ base = bank->um & ~(bank->uk);
+
+ mcid = SG_PORTID_TO_SAFARI_ID(bank->portid);
+
+ /* If bank is not valid, set size to zero incase it's garbage */
+ if (bank->valid)
+ bank_size = ((bank->bank_size) / MBYTE);
+ else
+ bank_size = 0;
+
+ /*
+ * Keep track of all banks found so we can check later
+ * that this value matches the total memory in the
+ * system using the pagesize and number of pages.
+ */
+ total_bank_size += bank_size;
+
+ /* Find the matching segment for this bank. */
+ seg = match_seg(base);
+
+ /*
+ * Find the Dimm size by adding banks 0 + 2 and divide by 4
+ * and then adding banks 1 + 3 and divide by 4. We divide
+ * by 2 if one of the logical banks size is zero.
+ */
+ switch ((bank->id) % 4) {
+ case 0:
+ /* have bank0_size, need bank2_size */
+ bank0_size = bank_size;
+ bank2_size = 0;
+
+ tmp_bank = bank->next;
+ while (tmp_bank) {
+ if (tmp_bank->valid == 0) {
+ tmp_bank = tmp_bank->next;
+ continue;
+ }
+ /* Is next bank on the same mc ? */
+ if (mcid != SG_PORTID_TO_SAFARI_ID(
+ tmp_bank->portid)) {
+ break;
+ }
+ if ((tmp_bank->id) % 4 == 2) {
+ bank2_size =
+ (tmp_bank->bank_size / MBYTE);
+ break;
+ }
+ tmp_bank = tmp_bank->next;
+ }
+ if (bank2_size)
+ dimm_size = (bank0_size + bank2_size) / 4;
+ else
+ dimm_size = bank0_size / 2;
+ break;
+ case 1:
+ /* have bank1_size, need bank3_size */
+ bank1_size = bank_size;
+ bank3_size = 0;
+
+ tmp_bank = bank->next;
+ while (tmp_bank) {
+ if (tmp_bank->valid == 0) {
+ tmp_bank = tmp_bank->next;
+ continue;
+ }
+ /* Is next bank on the same mc ? */
+ if (mcid != SG_PORTID_TO_SAFARI_ID(
+ tmp_bank->portid)) {
+ break;
+ }
+ if ((tmp_bank->id) % 4 == 3) {
+ bank3_size =
+ (tmp_bank->bank_size / MBYTE);
+ break;
+ }
+ tmp_bank = tmp_bank->next;
+ }
+ if (bank3_size)
+ dimm_size = (bank1_size + bank3_size) / 4;
+ else
+ dimm_size = bank1_size / 2;
+ break;
+ case 2:
+ /* have bank0_size and bank2_size */
+ bank2_size = bank_size;
+ if (bank0_size)
+ dimm_size = (bank0_size + bank2_size) / 4;
+ else
+ dimm_size = bank2_size / 2;
+ break;
+ case 3:
+ /* have bank1_size and bank3_size */
+ bank3_size = bank_size;
+ if (bank1_size)
+ dimm_size = (bank1_size + bank3_size) / 4;
+ else
+ dimm_size = bank3_size / 4;
+ break;
+ }
+
+ if (bank->valid == 0)
+ continue;
+
+ /*
+ * Call platform specific code for formatting memory
+ * information.
+ */
+ print_us3_memory_line(bank->portid, bank->id, bank_size,
+ bank->bank_status, dimm_size, intlv, seg->id);
+ }
+
+ printf("\n");
+
+ /*
+ * Sanity check to ensure that the total amount of system
+ * memory matches the total number of memory banks that
+ * we find here. Scream if there is a mis-match.
+ */
+ total_sys_mem = (((uint64_t)sysconf(_SC_PAGESIZE) * \
+ (uint64_t)sysconf(_SC_PHYS_PAGES)) / MBYTE);
+
+ if (total_bank_size != total_sys_mem) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nError: total bank size [%lldMB] does not match total "
+ "system memory [%lldMB]\n"), total_bank_size,
+ total_sys_mem, 0);
+ }
+
+}
+
+static void
+add_seg_node(void)
+{
+ uint64_t base;
+ memory_seg_t *new;
+ static int id = 0;
+ memory_bank_t *bank = bank_tail;
+
+ if (bank->valid != 1)
+ return;
+
+ base = bank->um & ~(bank->uk);
+
+ if ((new = match_seg(base)) == NULL) {
+ /*
+ * This bank is part of a new segment, so create
+ * a struct for it and added to the list of segments
+ */
+ if ((new = malloc(sizeof (memory_seg_t))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ new->id = id++;
+ new->base = base;
+ new->size = (((uint64_t)bank->uk +1) << 26);
+ new->intlv = ((bank->lk ^ 0xF) + 1);
+
+ /*
+ * add to the seg list
+ */
+ new->next = seg_head;
+ seg_head = new;
+ }
+
+ new->nbanks++;
+ /*
+ * add bank into segs bank list. Note we add at the head
+ */
+ bank->seg_next = new->banks;
+ new->banks = bank;
+}
+
+static memory_seg_t *
+match_seg(uint64_t base)
+{
+ memory_seg_t *cur_seg;
+
+ for (cur_seg = seg_head; cur_seg; cur_seg = cur_seg->next) {
+ if (cur_seg-> base == base)
+ break;
+ }
+ return (cur_seg);
+}
+
+/*ARGSUSED0*/
+void
+print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
+{
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n No print_us3_memory_line() function specified for"
+ " this platform\n"), 0);
+}
+
+int
+display_us3_failed_banks(int system_failed)
+{
+ memory_bank_t *bank;
+ int found_failed_bank = 0;
+
+ if ((bank_head == NULL) || (seg_head == NULL)) {
+ log_printf("\nCannot find any memory bank/segment info.\n");
+ return (1);
+ }
+
+ for (bank = bank_head; bank; bank = bank->next) {
+ /*
+ * check to see if the bank is invalid and also
+ * check if the bank_status is unpopulated. Unpopulated
+ * means the bank is empty.
+ */
+
+ if ((bank->valid == 0) &&
+ (strcmp(bank->bank_status, "unpopulated"))) {
+ if (!system_failed && !found_failed_bank) {
+ found_failed_bank = TRUE;
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed Field Replaceable Units (FRU) in "
+ "System:\n"), 0);
+ log_printf("=========================="
+ "====================\n", 0);
+ }
+ /*
+ * Call platform specific code for formatting memory
+ * information.
+ */
+ print_us3_failed_memory_line(bank->portid, bank->id,
+ bank->bank_status);
+ }
+ }
+ if (found_failed_bank)
+ return (1);
+ else
+ return (0);
+}
+
+/*ARGSUSED0*/
+void
+print_us3_failed_memory_line(int portid, int bank_id, char *bank_status)
+{
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n No print_us3_failed_memory_line() function specified for"
+ " this platform\n"), 0);
+}
diff --git a/usr/src/lib/libprtdiag/common/pdevinfo_funcs.c b/usr/src/lib/libprtdiag/common/pdevinfo_funcs.c
new file mode 100644
index 0000000000..ce52634405
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/pdevinfo_funcs.c
@@ -0,0 +1,833 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <libintl.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+
+/*
+ * For machines that support the openprom, fetch and print the list
+ * of devices that the kernel has fetched from the prom or conjured up.
+ *
+ */
+
+
+static int prom_fd;
+extern char *progname;
+extern char *promdev;
+extern void getppdata();
+extern void printppdata();
+
+/*
+ * Define DPRINT for run-time debugging printf's...
+ * #define DPRINT 1
+ */
+
+#ifdef DPRINT
+static char vdebug_flag = 1;
+#define dprintf if (vdebug_flag) printf
+static void dprint_dev_info(caddr_t, dev_info_t *);
+#endif /* DPRINT */
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*VARARGS1*/
+int
+_error(char *fmt, ...)
+{
+ int saved_errno;
+ va_list ap;
+ extern int errno;
+ saved_errno = errno;
+
+ if (progname)
+ (void) fprintf(stderr, "%s: ", progname);
+
+ va_start(ap, fmt);
+
+ (void) vfprintf(stderr, fmt, ap);
+
+ va_end(ap);
+
+ (void) fprintf(stderr, ": ");
+ errno = saved_errno;
+ perror("");
+
+ return (2);
+}
+
+int
+is_openprom(void)
+{
+ Oppbuf oppbuf;
+ register struct openpromio *opp = &(oppbuf.opp);
+ register unsigned int i;
+
+ opp->oprom_size = MAXVALSIZE;
+ if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
+ exit(_error("OPROMGETCONS"));
+
+ i = (unsigned int)((unsigned char)opp->oprom_array[0]);
+ return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
+}
+
+/*
+ * Read all properties and values from nodes.
+ * Copy the properties read into the prom_node passsed in.
+ */
+void
+dump_node(Prom_node *node)
+{
+ Oppbuf oppbuf;
+ register struct openpromio *opp = &oppbuf.opp;
+ Prop *prop = NULL; /* tail of properties list */
+ StaticProp *temp;
+
+ /* clear out pointers in pnode */
+ node->props = NULL;
+
+ /* get first prop by asking for null string */
+ (void) memset((void *) oppbuf.buf, 0, BUFSIZE);
+
+ /* allocate space for the property */
+ if ((temp = malloc(sizeof (StaticProp))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ opp->oprom_size = MAXPROPSIZE;
+ while (opp->oprom_size != 0) {
+ Prop *new;
+ int i;
+ char *tempp, *newp;
+
+ /*
+ * get property
+ */
+ opp->oprom_size = MAXPROPSIZE;
+
+ if (ioctl(prom_fd, OPROMNXTPROP, opp) < 0)
+ exit(_error("OPROMNXTPROP"));
+
+ if (opp->oprom_size != 0) {
+ temp->name.opp.oprom_size = opp->oprom_size;
+ (void) strcpy(temp->name.opp.oprom_array,
+ opp->oprom_array);
+
+ (void) strcpy(temp->value.opp.oprom_array,
+ temp->name.opp.oprom_array);
+ getpropval(&temp->value.opp);
+ temp->size = temp->value.opp.oprom_size;
+
+ /* Now copy over temp's data to new. */
+ if ((new = malloc(sizeof (Prop))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ /*
+ * First copy over temp->name's data. The
+ * temp->name.opp.opio_u union always contains char[]
+ * (as opposed to an int or int []).
+ */
+ new->name.opp.oprom_size = temp->name.opp.oprom_size;
+
+ if ((new->name.opp.oprom_array =
+ malloc(new->name.opp.oprom_size)) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ (void) strcpy(new->name.opp.oprom_array,
+ temp->name.opp.oprom_array);
+
+ new->name.opp.holds_array = 1;
+
+ /*
+ * Then copy over temp->value's data.
+ * temp->value.opp.opio_u could contain char[], int or
+ * int []. If *(temp->value.opp.oprom_array) is '\0',
+ * this indicates int or int []. int is the norm, but
+ * to be safe we assume int [] and copy over
+ * OPROM_NODE_SIZE int elements.
+ */
+ new->value.opp.oprom_size = temp->value.opp.oprom_size;
+
+ if (*(temp->value.opp.oprom_array) == '\0') {
+ for (i = 0; i < OPROM_NODE_SIZE; i++)
+ new->value.opp.oprom_node[i] =
+ *(&temp->value.opp.oprom_node+i);
+
+ new->value.opp.holds_array = 0;
+ } else {
+ if ((new->value.opp.oprom_array =
+ malloc(new->value.opp.oprom_size))
+ == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ /*
+ * temp->value.opp.oprom_array can contain one
+ * or more embedded NULLs. These trip-up the
+ * standard string copying functions, so we do
+ * the copy by hand. temp->value.opp.oprom_array
+ * will be NULL-terminated. oprom_size includes
+ * this terminating NULL.
+ */
+ newp = new->value.opp.oprom_array;
+ tempp = temp->value.opp.oprom_array;
+ for (i = new->value.opp.oprom_size; i > 0; i--)
+ *newp++ = *tempp++;
+
+ new->value.opp.holds_array = 1;
+ }
+
+ new->size = temp->size;
+
+ /* everything worked so link the property list */
+ if (node->props == NULL)
+ node->props = new;
+ else if (prop != NULL)
+ prop->next = new;
+ prop = new;
+ prop->next = NULL;
+ }
+ }
+ free(temp);
+}
+
+int
+promopen(int oflag)
+{
+ /*CONSTCOND*/
+ while (1) {
+ if ((prom_fd = open(promdev, oflag)) < 0) {
+ if (errno == EAGAIN) {
+ (void) sleep(5);
+ continue;
+ }
+ if (errno == ENXIO)
+ return (-1);
+ exit(_error(dgettext(TEXT_DOMAIN, "cannot open %s"),
+ promdev));
+ } else
+ return (0);
+ }
+ /*NOTREACHED*/
+}
+
+void
+promclose(void)
+{
+ if (close(prom_fd) < 0)
+ exit(_error(dgettext(TEXT_DOMAIN, "close error on %s"),
+ promdev));
+}
+
+/*
+ * Read the value of the property from the PROM device tree
+ */
+void
+getpropval(struct openpromio *opp)
+{
+ opp->oprom_size = MAXVALSIZE;
+
+ if (ioctl(prom_fd, OPROMGETPROP, opp) < 0)
+ exit(_error("OPROMGETPROP"));
+}
+
+int
+next(int id)
+{
+ Oppbuf oppbuf;
+ register struct openpromio *opp = &(oppbuf.opp);
+ /* LINTED */
+ int *ip = (int *)(opp->oprom_array);
+
+ (void) memset((void *) oppbuf.buf, 0, BUFSIZE);
+
+ opp->oprom_size = MAXVALSIZE;
+ *ip = id;
+ if (ioctl(prom_fd, OPROMNEXT, opp) < 0)
+ return (_error("OPROMNEXT"));
+ /* LINTED */
+ return (*(int *)opp->oprom_array);
+}
+
+int
+child(int id)
+{
+ Oppbuf oppbuf;
+ register struct openpromio *opp = &(oppbuf.opp);
+ /* LINTED */
+ int *ip = (int *)(opp->oprom_array);
+
+ (void) memset((void *) oppbuf.buf, 0, BUFSIZE);
+ opp->oprom_size = MAXVALSIZE;
+ *ip = id;
+ if (ioctl(prom_fd, OPROMCHILD, opp) < 0)
+ return (_error("OPROMCHILD"));
+ /* LINTED */
+ return (*(int *)opp->oprom_array);
+}
+
+/*
+ * Check if the Prom node passed in contains a property called
+ * "board#".
+ */
+int
+has_board_num(Prom_node *node)
+{
+ Prop *prop = node->props;
+
+ /*
+ * walk thru all properties in this PROM node and look for
+ * board# prop
+ */
+ while (prop != NULL) {
+ if (strcmp(prop->name.opp.oprom_array, "board#") == 0)
+ return (1);
+
+ prop = prop->next;
+ }
+
+ return (0);
+} /* end of has_board_num() */
+
+/*
+ * Retrieve the value of the board number property from this Prom
+ * node. It has the type of int.
+ */
+int
+get_board_num(Prom_node *node)
+{
+ Prop *prop = node->props;
+
+ /*
+ * walk thru all properties in this PROM node and look for
+ * board# prop
+ */
+ while (prop != NULL) {
+ if (strcmp(prop->name.opp.oprom_array, "board#") == 0)
+ return (prop->value.opp.oprom_node[0]);
+
+ prop = prop->next;
+ }
+
+ return (-1);
+} /* end of get_board_num() */
+
+/*
+ * Find the requested board struct in the system device tree.
+ */
+Board_node *
+find_board(Sys_tree *root, int board)
+{
+ Board_node *bnode = root->bd_list;
+
+ while ((bnode != NULL) && (board != bnode->board_num))
+ bnode = bnode->next;
+
+ return (bnode);
+} /* end of find_board() */
+
+/*
+ * Add a board to the system list in order. Initialize all pointer
+ * fields to NULL.
+ */
+Board_node *
+insert_board(Sys_tree *root, int board)
+{
+ Board_node *bnode;
+ Board_node *temp = root->bd_list;
+
+ if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+ bnode->nodes = NULL;
+ bnode->next = NULL;
+ bnode->board_num = board;
+
+ if (temp == NULL)
+ root->bd_list = bnode;
+ else if (temp->board_num > board) {
+ bnode->next = temp;
+ root->bd_list = bnode;
+ } else {
+ while ((temp->next != NULL) && (board > temp->next->board_num))
+ temp = temp->next;
+ bnode->next = temp->next;
+ temp->next = bnode;
+ }
+ root->board_cnt++;
+
+ return (bnode);
+} /* end of insert_board() */
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property.
+ */
+char *
+get_node_name(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("name", prop->name.opp.oprom_array) == 0)
+ return (prop->value.opp.oprom_array);
+ prop = prop->next;
+ }
+ return (NULL);
+} /* end of get_node_name() */
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property.
+ */
+char *
+get_node_type(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("device_type", prop->name.opp.oprom_array) == 0)
+ return (prop->value.opp.oprom_array);
+ prop = prop->next;
+ }
+ return (NULL);
+} /* end of get_node_type() */
+
+/*
+ * Do a depth-first walk of a device tree and
+ * return the first node with the name matching.
+ */
+
+Prom_node *
+dev_find_node(Prom_node *root, char *name)
+{
+ Prom_node *node;
+
+ node = dev_find_node_by_type(root, "name", name);
+
+ return (node);
+}
+
+Prom_node *
+dev_next_node(Prom_node *root, char *name)
+{
+ Prom_node *node;
+
+ node = dev_next_node_by_type(root, "name", name);
+
+ return (node);
+}
+
+/*
+ * Search for and return a node of the required type. If no node is found,
+ * then return NULL.
+ */
+Prom_node *
+dev_find_type(Prom_node *root, char *type)
+{
+ Prom_node *node;
+
+ node = dev_find_node_by_type(root, "device_type", type);
+
+ return (node); /* not found */
+}
+
+/*
+ * Start from the current node and return the next node besides the
+ * current one which has the requested type property.
+ */
+Prom_node *
+dev_next_type(Prom_node *root, char *type)
+{
+ Prom_node *node;
+
+ node = dev_next_node_by_type(root, "device_type", type);
+
+ return (node); /* not found */
+}
+
+/*
+ * Search a device tree and return the first failed node that is found.
+ * (has a 'status' property)
+ */
+Prom_node *
+find_failed_node(Prom_node * root)
+{
+ Prom_node *pnode;
+
+ if (root == NULL)
+ return (NULL);
+
+ if (node_failed(root)) {
+ return (root);
+ }
+
+ /* search the child */
+ if ((pnode = find_failed_node(root->child)) != NULL)
+ return (pnode);
+
+ /* search the siblings */
+ if ((pnode = find_failed_node(root->sibling)) != NULL)
+ return (pnode);
+
+ return (NULL);
+} /* end of find_failed_node() */
+
+/*
+ * Start from the current node and return the next node besides
+ * the current one which is failed. (has a 'status' property)
+ */
+Prom_node *
+next_failed_node(Prom_node * root)
+{
+ Prom_node *pnode;
+ Prom_node *parent;
+
+ if (root == NULL)
+ return (NULL);
+
+ /* search the child */
+ if ((pnode = find_failed_node(root->child)) != NULL) {
+ return (pnode);
+ }
+
+ /* search the siblings */
+ if ((pnode = find_failed_node(root->sibling)) != NULL) {
+ return (pnode);
+ }
+
+ /* backtracking the search up through parents' siblings */
+ parent = root->parent;
+ while (parent != NULL) {
+ if ((pnode = find_failed_node(parent->sibling)) != NULL)
+ return (pnode);
+ else
+ parent = parent->parent;
+ }
+
+ return (NULL);
+} /* end of find_failed_node() */
+
+/*
+ * node_failed
+ *
+ * This function determines if the current Prom node is failed. This
+ * is defined by having a status property containing the token 'fail'.
+ */
+int
+node_failed(Prom_node *node)
+{
+ return (node_status(node, "fail"));
+}
+
+int
+node_status(Prom_node *node, char *status)
+{
+ void *value;
+
+ if (status == NULL)
+ return (0);
+
+ /* search the local node */
+ if ((value = get_prop_val(find_prop(node, "status"))) != NULL) {
+ if ((value != NULL) && strstr((char *)value, status))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Get a property's value. Must be void * since the property can
+ * be any data type. Caller must know the *PROPER* way to use this
+ * data.
+ */
+void *
+get_prop_val(Prop *prop)
+{
+ if (prop == NULL)
+ return (NULL);
+
+ if (prop->value.opp.holds_array)
+ return ((void *)(prop->value.opp.oprom_array));
+ else
+ return ((void *)(&prop->value.opp.oprom_node[0]));
+} /* end of get_prop_val() */
+
+/*
+ * Search a Prom node and retrieve the property with the correct
+ * name.
+ */
+Prop *
+find_prop(Prom_node *pnode, char *name)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ if (pnode->props == NULL) {
+ (void) printf("%s", dgettext(TEXT_DOMAIN, "Prom node has "
+ "no properties\n"));
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while ((prop != NULL) && (strcmp(prop->name.opp.oprom_array, name)))
+ prop = prop->next;
+
+ return (prop);
+}
+
+/*
+ * This function adds a board node to the board structure where that
+ * that node's physical component lives.
+ */
+void
+add_node(Sys_tree *root, Prom_node *pnode)
+{
+ int board;
+ Board_node *bnode;
+ Prom_node *p;
+
+ /* add this node to the Board list of the appropriate board */
+ if ((board = get_board_num(pnode)) == -1) {
+ /* board is 0 if not on Sunfire */
+ board = 0;
+ }
+
+ /* find the node with the same board number */
+ if ((bnode = find_board(root, board)) == NULL) {
+ bnode = insert_board(root, board);
+ bnode->board_type = UNKNOWN_BOARD;
+ }
+
+ /* now attach this prom node to the board list */
+ /* Insert this node at the end of the list */
+ pnode->sibling = NULL;
+ if (bnode->nodes == NULL)
+ bnode->nodes = pnode;
+ else {
+ p = bnode->nodes;
+ while (p->sibling != NULL)
+ p = p->sibling;
+ p->sibling = pnode;
+ }
+
+}
+
+/*
+ * Find the device on the current board with the requested device ID
+ * and name. If this rountine is passed a NULL pointer, it simply returns
+ * NULL.
+ */
+Prom_node *
+find_device(Board_node *board, int id, char *name)
+{
+ Prom_node *pnode;
+ int mask;
+
+ /* find the first cpu node */
+ pnode = dev_find_node(board->nodes, name);
+
+ mask = 0x1F;
+ while (pnode != NULL) {
+ if ((get_id(pnode) & mask) == id)
+ return (pnode);
+
+ pnode = dev_next_node(pnode, name);
+ }
+ return (NULL);
+}
+
+Prom_node *
+dev_find_node_by_type(Prom_node *root, char *type, char *property)
+{
+ Prom_node *node;
+ char *type_prop;
+
+ if (root == NULL || property == NULL)
+ return (NULL);
+
+ type_prop = (char *)get_prop_val(find_prop(root, type));
+
+ if (type_prop != NULL) {
+ if (strcmp(type_prop, property) == 0) {
+ return (root);
+ }
+ }
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_type(root->child, type,
+ property)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_type(root->sibling, type,
+ property)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+Prom_node *
+dev_next_node_by_type(Prom_node *root, char *type, char *property)
+{
+ Prom_node *node;
+
+ if (root == NULL || property == NULL)
+ return (NULL);
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_type(root->child, type,
+ property)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_type(root->sibling, type,
+ property)) != NULL)
+ return (node);
+
+ /* now look at papa's siblings */
+ if ((node = dev_find_node_by_type(root->parent->sibling,
+ type, property)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+/*
+ * Do a depth-first walk of a device tree and
+ * return the first node with the matching compatible.
+ */
+Prom_node *
+dev_find_node_by_compatible(Prom_node *root, char *compatible)
+{
+ Prom_node *node;
+ Prop *prop;
+ char *compatible_array;
+ int size, nbytes;
+
+ if (root == NULL || compatible == NULL)
+ return (NULL);
+
+ if ((prop = find_prop(root, "compatible")) != NULL &&
+ (compatible_array = (char *)get_prop_val(prop)) != NULL) {
+ /*
+ * The Prop structure returned by find_prop() is supposed
+ * to contain an indication of how big the value of the
+ * compatible property is. Since it is an array of strings
+ * this is our only means of determining just how many
+ * strings might be in this property. However, this size
+ * is often left as zero even though there is at least one
+ * string present. When this is the case, all we can do
+ * is examine the first string in the compatible property.
+ */
+
+ for (size = prop->size; size >= 0; size -= nbytes) {
+ if (strcmp(compatible_array, compatible) == 0)
+ return (root); /* found a match */
+
+ nbytes = strlen(compatible_array) + 1;
+ compatible_array += nbytes;
+ }
+ }
+
+ node = dev_find_node_by_compatible(root->child, compatible);
+ if (node != NULL)
+ return (node);
+
+ /*
+ * Note the very deliberate use of tail recursion here. A good
+ * compiler (such as Sun's) will recognize this and generate code
+ * that does not allocate another stack frame. Instead, it will
+ * overlay the existing stack frame with the new one, the only change
+ * having been to replace the original root with its sibling.
+ * This has the potential to create some confusion for anyone
+ * trying to debug this code from a core dump, since the stack
+ * trace will not reveal recursion on siblings, only on children.
+ */
+
+ return (dev_find_node_by_compatible(root->sibling, compatible));
+}
+
+/*
+ * Start from the current node and return the next node besides
+ * the current one which has the requested compatible property.
+ */
+Prom_node *
+dev_next_node_by_compatible(Prom_node *root, char *compatible)
+{
+ Prom_node *node;
+
+ if (root == NULL || compatible == NULL)
+ return (NULL);
+
+ node = dev_find_node_by_compatible(root->child, compatible);
+ if (node != NULL)
+ return (node);
+
+ /*
+ * More tail recursion. Even though it is a different function,
+ * this will overlay the current stack frame. Caveat exterminator.
+ */
+
+ node = dev_find_node_by_compatible(root->sibling, compatible);
+ if (node != NULL)
+ return (node);
+
+ return (dev_find_node_by_compatible(root->parent->sibling, compatible));
+}
diff --git a/usr/src/lib/libprtdiag/common/pdevinfo_sun4u.c b/usr/src/lib/libprtdiag/common/pdevinfo_sun4u.c
new file mode 100644
index 0000000000..6a464321a5
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/pdevinfo_sun4u.c
@@ -0,0 +1,275 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <varargs.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include "pdevinfo.h"
+#include "pdevinfo_sun4u.h"
+#include "display.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*
+ * Global variables
+ */
+char *progname;
+char *promdev = "/dev/openprom";
+int print_flag = 1;
+int logging = 0;
+
+/*
+ * This file represents the splitting out of some functionality
+ * of prtdiag due to the port to the sun4u platform. The PROM
+ * tree-walking functions which contain sun4u specifics were moved
+ * into this module.
+ */
+
+extern int get_id(Prom_node *);
+
+/* Function prototypes */
+Prom_node *walk(Sys_tree *, Prom_node *, int);
+
+/*
+ * do_prominfo() is called from main() in usr/src/cmd/prtdiag/main.c
+ *
+ * This is the starting point for all platforms. However, this function
+ * can be overlayed by writing a do_prominfo() function
+ * in the libprtdiag_psr for a particular platform.
+ *
+ */
+int
+do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+ Sys_tree sys_tree; /* system information */
+ Prom_node *root_node; /* root node of OBP device tree */
+ struct system_kstat_data sys_kstat; /* kstats for non-OBP data */
+
+
+ /* set the global flags */
+ progname = pgname;
+ logging = log_flag;
+ print_flag = prt_flag;
+
+ /* set the the system tree fields */
+ sys_tree.sys_mem = NULL;
+ sys_tree.boards = NULL;
+ sys_tree.bd_list = NULL;
+ sys_tree.board_cnt = 0;
+
+ if (promopen(O_RDONLY)) {
+ exit(_error(dgettext(TEXT_DOMAIN, "openeepr device "
+ "open failed")));
+ }
+
+ if (is_openprom() == 0) {
+ (void) fprintf(stderr, "%s",
+ dgettext(TEXT_DOMAIN, "System architecture "
+ "does not support this option of this "
+ "command.\n"));
+ return (2);
+ }
+
+ if (next(0) == 0) {
+ return (2);
+ }
+
+ root_node = walk(&sys_tree, NULL, next(0));
+ promclose();
+
+ /* resolve the board types now */
+ resolve_board_types(&sys_tree);
+
+ read_sun4u_kstats(&sys_tree, &sys_kstat);
+
+ return (display(&sys_tree, root_node, &sys_kstat, syserrlog));
+
+}
+
+int
+get_id(Prom_node *node)
+{
+ int *value;
+
+ /*
+ * check for upa-portid on UI and UII systems
+ */
+ if ((value = (int *)get_prop_val(find_prop(node, "upa-portid")))
+ == NULL) {
+ /*
+ * check for portid on UIII systems
+ */
+ if ((value = (int *)get_prop_val(find_prop(node, "portid")))
+ == NULL) {
+ return (-1);
+ }
+ }
+ return (*value);
+}
+
+
+
+/*
+ * Walk the PROM device tree and build the system tree and root tree.
+ * Nodes that have a board number property are placed in the board
+ * structures for easier processing later. Child nodes are placed
+ * under their parents. ffb (Fusion Frame Buffer) nodes are handled
+ * specially, because they do not contain board number properties.
+ * This was requested from OBP, but was not granted. So this code
+ * must parse the MID of the FFB to find the board#.
+ *
+ */
+Prom_node *
+walk(Sys_tree *tree, Prom_node *root, int id)
+{
+ register int curnode;
+ Prom_node *pnode;
+ char *name;
+ char *type;
+ char *model;
+ int board_node = 0;
+
+ /* allocate a node for this level */
+ if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
+ NULL) {
+ perror("malloc");
+ exit(2); /* program errors cause exit 2 */
+ }
+
+ /* assign parent Prom_node */
+ pnode->parent = root;
+ pnode->sibling = NULL;
+ pnode->child = NULL;
+
+ /* read properties for this node */
+ dump_node(pnode);
+
+ /*
+ * Place a node in a 'board' if it has 'board'-ness. The definition
+ * is that all nodes that are children of root should have a
+ * board# property. But the PROM tree does not exactly follow
+ * this. This is where we start hacking. The name 'ffb' can
+ * change, so watch out for this.
+ *
+ * The UltraSPARC, sbus, pci and ffb nodes will exit in
+ * the desktops and will not have board# properties. These
+ * cases must be handled here.
+ *
+ * PCI to PCI bridges also have the name "pci", but with different
+ * model property values. They should not be put under 'board'.
+ */
+ name = get_node_name(pnode);
+ type = get_node_type(pnode);
+ model = (char *)get_prop_val(find_prop(pnode, "model"));
+#ifdef DEBUG
+ if (name != NULL)
+ printf("name=%s ", name);
+ if (type != NULL)
+ printf("type=%s ", type);
+ if (model != NULL)
+ printf("model=%s", model);
+ printf("\n");
+#endif
+ if (model == NULL)
+ model = "";
+ if (type == NULL)
+ type = "";
+ if (name != NULL) {
+ if (has_board_num(pnode)) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s model=%s\n",
+ name, type, model);
+#endif
+ } else if ((strcmp(name, FFB_NAME) == 0) ||
+ (strcmp(name, AFB_NAME) == 0) ||
+ (strcmp(type, "cpu") == 0) ||
+
+ ((strcmp(type, "memory-controller") == 0) &&
+ (strcmp(name, "ac") != 0)) ||
+
+ ((strcmp(name, "pci") == 0) &&
+ (strcmp(model, "SUNW,psycho") == 0)) ||
+
+ ((strcmp(name, "pci") == 0) &&
+ (strcmp(model, "SUNW,sabre") == 0)) ||
+
+ ((strcmp(name, "pci") == 0) &&
+ (strcmp(model, "SUNW,schizo") == 0)) ||
+
+ ((strcmp(name, "pci") == 0) &&
+ (strcmp(model, "SUNW,xmits") == 0)) ||
+
+ (strcmp(name, "counter-timer") == 0) ||
+ (strcmp(name, "sbus") == 0)) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s model=%s\n",
+ name, type, model);
+#endif
+ }
+#ifdef DEBUG
+ else
+ printf("node not added: name=%s type=%s\n", name, type);
+#endif
+ }
+
+ if (curnode = child(id)) {
+ pnode->child = walk(tree, pnode, curnode);
+ }
+
+ if (curnode = next(id)) {
+ if (board_node) {
+ return (walk(tree, root, curnode));
+ } else {
+ pnode->sibling = walk(tree, root, curnode);
+ }
+ }
+
+ if (board_node) {
+ return (NULL);
+ } else {
+ return (pnode);
+ }
+}
diff --git a/usr/src/lib/libprtdiag/common/pdevinfo_sun4v.c b/usr/src/lib/libprtdiag/common/pdevinfo_sun4v.c
new file mode 100644
index 0000000000..8b1f1914d2
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/pdevinfo_sun4v.c
@@ -0,0 +1,288 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <varargs.h>
+#include <errno.h>
+#include <unistd.h>
+#include <alloca.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "display_sun4v.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*
+ * Global variables
+ */
+char *progname;
+char *promdev = "/dev/openprom";
+int print_flag = 1;
+int logging = 0;
+
+/*
+ * This file represents the splitting out of some functionality
+ * of prtdiag due to the port to the sun4v platform. The PROM
+ * tree-walking functions which contain sun4v specifics were moved
+ * into this module.
+ */
+
+extern int get_id(Prom_node *);
+
+/* Function prototypes */
+Prom_node *sun4v_walk(Sys_tree *, Prom_node *, int);
+int sun4v_get_node_by_name(picl_nodehdl_t rooth, char *name,
+ picl_nodehdl_t *nodeh);
+/*
+ * do_prominfo() is called from main() in usr/src/cmd/prtdiag/main.c
+ *
+ * This is the starting point for all platforms. However, this function
+ * can be overlayed by writing a do_prominfo() function
+ * in the libprtdiag_psr for a particular platform.
+ *
+ */
+int
+do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+ Sys_tree sys_tree; /* system information */
+ Prom_node *root_node; /* root node of OBP device tree */
+ picl_nodehdl_t rooth; /* root PICL node for IO display */
+ picl_nodehdl_t plafh; /* Platform PICL node for IO display */
+
+ int err;
+
+ err = picl_initialize();
+ if (err != PICL_SUCCESS) {
+ (void) fprintf(stderr, EM_INIT_FAIL, picl_strerror(err));
+ exit(1);
+ }
+
+ /* set the global flags */
+ progname = pgname;
+ logging = log_flag;
+ print_flag = prt_flag;
+
+ /* set the the system tree fields */
+ sys_tree.sys_mem = NULL;
+ sys_tree.boards = NULL;
+ sys_tree.bd_list = NULL;
+ sys_tree.board_cnt = 0;
+
+ if (promopen(O_RDONLY)) {
+ exit(_error(dgettext(TEXT_DOMAIN, "openeepr device "
+ "open failed")));
+ }
+
+ if (is_openprom() == 0) {
+ (void) fprintf(stderr, "%s",
+ dgettext(TEXT_DOMAIN, "System architecture "
+ "does not support this option of this "
+ "command.\n"));
+ return (2);
+ }
+
+ if (next(0) == 0) {
+ return (2);
+ }
+
+ root_node = sun4v_walk(&sys_tree, NULL, next(0));
+ promclose();
+
+ err = picl_get_root(&rooth);
+ if (err != PICL_SUCCESS) {
+ (void) fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err));
+ exit(1);
+ }
+
+ err = sun4v_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ return (sun4v_display(&sys_tree, root_node, syserrlog, plafh));
+
+}
+
+/*
+ * sun4v_Walk the PROM device tree and build the system tree and root tree.
+ * Nodes that have a board number property are placed in the board
+ * structures for easier processing later. Child nodes are placed
+ * under their parents.
+ */
+Prom_node *
+sun4v_walk(Sys_tree *tree, Prom_node *root, int id)
+{
+ register int curnode;
+ Prom_node *pnode;
+ char *name;
+ char *type;
+ char *compatible;
+ int board_node = 0;
+
+ /* allocate a node for this level */
+ if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
+ NULL) {
+ perror("malloc");
+ exit(2); /* program errors cause exit 2 */
+ }
+
+ /* assign parent Prom_node */
+ pnode->parent = root;
+ pnode->sibling = NULL;
+ pnode->child = NULL;
+
+ /* read properties for this node */
+ dump_node(pnode);
+
+ /*
+ * Place a node in a 'board' if it has 'board'-ness. The definition
+ * is that all nodes that are children of root should have a
+ * board# property. But the PROM tree does not exactly follow
+ * this. This is where we start hacking.
+ *
+ * PCI to PCI bridges also have the name "pci", but with different
+ * model property values. They should not be put under 'board'.
+ */
+ name = get_node_name(pnode);
+ type = get_node_type(pnode);
+ compatible = (char *)get_prop_val(find_prop(pnode, "compatible"));
+
+#ifdef DEBUG
+ if (name != NULL)
+ printf("name=%s ", name);
+ if (type != NULL)
+ printf("type=%s ", type);
+ printf("\n");
+#endif
+ if (compatible == NULL)
+ compatible = "";
+ if (type == NULL)
+ type = "";
+ if (name != NULL) {
+ if (has_board_num(pnode)) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s compatible=%s\n",
+ name, type, compatible);
+#endif
+ } else if (strcmp(type, "cpu") == 0) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s compatible=%s\n",
+ name, type, compatible);
+#endif
+ }
+#ifdef DEBUG
+ else
+ printf("node not added: name=%s type=%s\n", name, type);
+#endif
+ }
+
+ if (curnode = child(id)) {
+ pnode->child = sun4v_walk(tree, pnode, curnode);
+ }
+
+ if (curnode = next(id)) {
+ if (board_node) {
+ return (sun4v_walk(tree, root, curnode));
+ } else {
+ pnode->sibling = sun4v_walk(tree, root, curnode);
+ }
+ }
+
+ if (board_node) {
+ return (NULL);
+ } else {
+ return (pnode);
+ }
+}
+
+/*
+ * search children to get the node by the nodename
+ */
+int
+sun4v_get_node_by_name(picl_nodehdl_t rooth, char *name,
+ picl_nodehdl_t *nodeh)
+{
+ picl_nodehdl_t childh;
+ int err;
+ char *nodename;
+
+ nodename = alloca(strlen(name) + 1);
+ if (nodename == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
+ nodename, (strlen(name) + 1));
+ if (err != PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ if (strcmp(nodename, name) == 0) {
+ *nodeh = childh;
+ return (PICL_SUCCESS);
+ }
+
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ return (err);
+}
+
+int
+get_id(Prom_node *node)
+{
+#ifdef lint
+ node = node;
+#endif
+
+ /*
+ * This function is intentionally empty
+ */
+ return (0);
+}
diff --git a/usr/src/lib/libprtdiag/common/prom.c b/usr/src/lib/libprtdiag/common/prom.c
new file mode 100644
index 0000000000..bd0e711ca8
--- /dev/null
+++ b/usr/src/lib/libprtdiag/common/prom.c
@@ -0,0 +1,134 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+
+void
+disp_prom_version(Prom_node *flashprom)
+{
+ Prop *version;
+ char *vers; /* OBP version */
+ char *temp;
+
+ /* Look version */
+ version = find_prop(flashprom, "version");
+
+ vers = (char *)get_prop_val(version);
+
+ if (vers != NULL) {
+ log_printf(" %s ", vers, 0);
+
+ /*
+ * POST string follows the NULL terminated OBP
+ * version string. Do not attempt to print POST
+ * string unless node size is larger than the
+ * length of the OBP version string.
+ */
+ if ((strlen(vers) + 1) < version->size) {
+ temp = vers + strlen(vers) + 1;
+ log_printf("%s", temp, 0);
+ }
+ }
+
+ log_printf("\n", 0);
+}
+
+
+void
+platform_disp_prom_version(Sys_tree *tree)
+{
+ Board_node *bnode;
+ Prom_node *pnode;
+
+ bnode = tree->bd_list;
+
+ /* Display Prom revision header */
+ log_printf(dgettext(TEXT_DOMAIN, "System PROM "
+ "revisions:\n"), 0);
+ log_printf("----------------------\n", 0);
+
+ if ((pnode = find_device(bnode, 0x1F, SBUS_NAME)) == NULL) {
+ pnode = find_pci_bus(bnode->nodes, 0x1F, 1);
+ }
+
+ /*
+ * in case of platforms with multiple flashproms, find and
+ * display all proms with a "version"(OBP) property. bug 4187301
+ */
+ for (pnode = dev_find_node(pnode, "flashprom"); pnode != NULL;
+ pnode = dev_next_node(pnode, "flashprom")) {
+ if (find_prop(pnode, "version") != NULL) {
+ disp_prom_version(pnode);
+ }
+ }
+}
+
+int
+get_pci_class_code_reg(Prom_node *card_node)
+{
+ void *value;
+
+ /*
+ * Get the class-code of this node and return it
+ * if it exists. Otherwise return (-1).
+ */
+ value = get_prop_val(find_prop(card_node, "class-code"));
+ if (value != NULL)
+ return (*(int *)value);
+ else
+ return (-1);
+}
diff --git a/usr/src/lib/libprtdiag/inc/display.h b/usr/src/lib/libprtdiag/inc/display.h
new file mode 100644
index 0000000000..d90f5dc219
--- /dev/null
+++ b/usr/src/lib/libprtdiag/inc/display.h
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _DISPLAY_H
+#define _DISPLAY_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int logging;
+extern int print_flag;
+
+#define NOPRINT 0
+#define PRINT 1
+#define MX_SBUS_SLOTS 4
+
+/*
+ * Define a structure to contain both the DRAM SIMM and NVRAM
+ * SIMM memory totals in MBytes.
+ */
+struct mem_total {
+ int dram;
+ int nvsimm;
+};
+
+/* Functions in common display.c module */
+void disp_powerfail(Prom_node *);
+void log_printf(char *, ...);
+char *get_time(uchar_t *);
+void print_header(int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DISPLAY_H */
diff --git a/usr/src/lib/libprtdiag/inc/display_sun4u.h b/usr/src/lib/libprtdiag/inc/display_sun4u.h
new file mode 100644
index 0000000000..f9c7ed4f8e
--- /dev/null
+++ b/usr/src/lib/libprtdiag/inc/display_sun4u.h
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _DISPLAY_SUN4U_H
+#define _DISPLAY_SUN4U_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <pdevinfo_sun4u.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Define the memory decode bits for easier reading. These are from
+ * the Sunfire Programmer's Manual.
+ */
+#define MEM_SIZE_64M 0x4
+#define MEM_SIZE_256M 0xb
+#define MEM_SIZE_1G 0xf
+#define MEM_SIZE_2G 0x2
+
+#define MEM_SPEED_50ns 0x0
+#define MEM_SPEED_60ns 0x3
+#define MEM_SPEED_70ns 0x2
+#define MEM_SPEED_80ns 0x1
+
+/*
+ * If a QLC card is present in the system, the following values are needed
+ * to decode what type of a QLC card it is.
+ */
+#define AMBER_SUBSYSTEM_ID 0x4082
+#define CRYSTAL_SUBSYSTEM_ID 0x4083
+
+#define AMBER_CARD_NAME "Amber"
+#define CRYSTAL_CARD_NAME "Crystal+"
+
+#define MAX_QLC_MODEL_LEN 10
+
+/*
+ * Define strings in this structure as arrays instead of pointers so
+ * that copying is easier.
+ */
+struct io_card {
+ int display; /* Should we display this card? */
+ int node_id; /* Node ID */
+ int board; /* Board number */
+ char bus_type[MAXSTRLEN]; /* Type of bus this IO card is on */
+ int schizo_portid; /* portid of the Schizo for this card */
+ char pci_bus; /* PCI bus A or B */
+ int slot; /* Slot number */
+ char slot_str[MAXSTRLEN]; /* Slot description string */
+ int freq; /* Frequency (in MHz) */
+ char status[MAXSTRLEN]; /* Card status */
+ char name[MAXSTRLEN]; /* Card name */
+ char model[MAXSTRLEN]; /* Card model */
+ int dev_no; /* device number */
+ int func_no; /* function number */
+ char notes[MAXSTRLEN]; /* notes */
+ struct io_card *next;
+};
+
+/* used to determine whether slot (int) or slot_str(char*) should be used */
+#define PCI_SLOT_IS_STRING (-99)
+
+int display(Sys_tree *, Prom_node *, struct system_kstat_data *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DISPLAY_SUN4U_H */
diff --git a/usr/src/lib/libprtdiag/inc/display_sun4v.h b/usr/src/lib/libprtdiag/inc/display_sun4v.h
new file mode 100644
index 0000000000..19a4c3d295
--- /dev/null
+++ b/usr/src/lib/libprtdiag/inc/display_sun4v.h
@@ -0,0 +1,60 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DISPLAY_SUN4V_H
+#define _DISPLAY_SUN4V_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <picl.h>
+
+#define CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000)
+#define MAXSTRLEN 256
+#define CPU_STRAND_NAC "MB/CMP0/P"
+#define H20_IMPL 0x5678
+#define IS_H20(impl) ((impl) == H20_IMPL)
+
+#define EM_INIT_FAIL dgettext(TEXT_DOMAIN,\
+ "picl_initialize failed: %s\n")
+#define EM_GET_ROOT_FAIL dgettext(TEXT_DOMAIN,\
+ "Getting root node failed: %s\n")
+
+void sun4v_display_pci(picl_nodehdl_t plafh);
+void sun4v_display_memoryconf();
+void sun4v_display_cpu_devices(picl_nodehdl_t plafh);
+int sun4v_display_cpus(picl_nodehdl_t cpuh, void* args);
+void sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh);
+int sun4v_display(Sys_tree *, Prom_node *, int, picl_nodehdl_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DISPLAY_SUN4V_H */
diff --git a/usr/src/lib/libprtdiag/inc/libprtdiag.h b/usr/src/lib/libprtdiag/inc/libprtdiag.h
new file mode 100644
index 0000000000..0354aea6a3
--- /dev/null
+++ b/usr/src/lib/libprtdiag/inc/libprtdiag.h
@@ -0,0 +1,202 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_LIBPRTDIAG_H
+#define _SYS_LIBPRTDIAG_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/openpromio.h>
+#include <sys/cheetahregs.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+
+#ifdef DEBUG
+#define D_PRINTF printf
+#else
+#define D_PRINTF
+#endif
+
+#define EXIT_MSG(msg, err) \
+ { printf("\n%s failed with %d\n", msg, err); exit(err); }
+
+/* global data */
+#define PCI_DEVICE(x) ((x >> 11) & 0x1f)
+#define PCI_REG_TO_DEV(x) ((x & 0xf800) >> 11)
+#define PCI_REG_TO_FUNC(x) ((x & 0x700) >> 8)
+#define BUS_TYPE "UPA"
+#define MAX_SLOTS_PER_IO_BD 8
+
+
+int sys_clk; /* System clock freq. (in MHz) */
+
+/*
+ * Defines for identifying PCI devices
+ */
+#define PCI_BRIDGE_CLASS 0x6
+#define PCI_CLASS_SHIFT 0x10
+#define PCI_PCI_BRIDGE_SUBCLASS 0x4
+#define PCI_SUBCLASS_SHIFT 0x8
+#define PCI_SUBCLASS_MASK 0xFF00
+#define PCI_SUBCLASS_OTHER 0x80
+
+#define CLASS_REG_TO_SUBCLASS(class) (((class) & PCI_SUBCLASS_MASK) \
+ >> PCI_SUBCLASS_SHIFT)
+#define CLASS_REG_TO_CLASS(class) ((class) >> PCI_CLASS_SHIFT)
+
+/*
+ * display functions
+ */
+int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
+int disp_fail_parts(Sys_tree *tree);
+void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void resolve_board_types(Sys_tree *);
+void display_boardnum(int num);
+void display_platform_specific_header(void);
+
+/*
+ * cpu functions
+ */
+void display_cpu_devices(Sys_tree *);
+void display_cpus(Board_node *);
+void display_mid(int mid);
+int get_cpu_freq(Prom_node *);
+int get_ecache_size(Prom_node *);
+
+/*
+ * io functions
+ */
+Prom_node *find_pci_bus(Prom_node *, int, int);
+int get_pci_bus(Prom_node *);
+int get_pci_device(Prom_node *);
+int get_pci_to_pci_device(Prom_node *);
+void free_io_cards(struct io_card *);
+struct io_card *insert_io_card(struct io_card *, struct io_card *);
+char *fmt_manf_id(unsigned int, char *);
+int get_sbus_slot(Prom_node *);
+void display_io_devices(Sys_tree *tree);
+void display_pci(Board_node *bnode);
+void display_io_cards(struct io_card *);
+void display_ffb(Board_node *, int);
+void display_sbus(Board_node *);
+int populate_slot_name_arr(Prom_node *pci, int *slot_name_bits,
+ char **slot_name_arr, int num_slots);
+int get_card_frequency(Prom_node *pci);
+void get_dev_func_num(Prom_node *card_node, int *dev_no, int *func_no);
+void get_pci_class_codes(Prom_node *card_node, int *class_code,
+ int *subclass_code);
+int is_pci_bridge(Prom_node *card_node, char *name);
+int is_pci_bridge_other(Prom_node *card_node, char *name);
+void get_pci_card_model(Prom_node *card_node, char *model);
+void create_io_card_name(Prom_node *card_node, char *name,
+ char *card_name);
+void display_psycho_pci(Board_node *bnode);
+void get_slot_number_str(struct io_card *card, char **slot_name_arr,
+ int slot_name_bits);
+void distinguish_identical_io_cards(char *name, Prom_node *node,
+ struct io_card *card);
+void decode_qlc_card_model_prop(Prom_node *card_node, struct io_card *card);
+
+/*
+ * kstat functions
+ */
+void read_platform_kstats(Sys_tree *tree,
+ struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep);
+void read_sun4u_kstats(Sys_tree *, struct system_kstat_data *);
+
+/*
+ * memory functions
+ */
+void display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats,
+ struct grp_info *grps, struct mem_total *memory_total);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+
+/*
+ * prom functions
+ */
+void platform_disp_prom_version(Sys_tree *);
+void disp_prom_version(Prom_node *);
+void add_node(Sys_tree *, Prom_node *);
+Prom_node *find_device(Board_node *, int, char *);
+Prom_node *walk(Sys_tree *, Prom_node *, int);
+int get_pci_class_code_reg(Prom_node *);
+
+/*
+ * libdevinfo functions
+ */
+int do_devinfo(int, char *, int, int);
+
+/*
+ * mc-us3 memory functions and structs
+ */
+typedef struct memory_bank {
+ int id;
+ int portid;
+ ushort_t valid;
+ ushort_t uk;
+ uint_t um;
+ uchar_t lk;
+ uchar_t lm;
+ uint64_t bank_size;
+ char *bank_status;
+ struct memory_bank *next; /* mc in the devtree */
+ struct memory_bank *seg_next; /* in the segment */
+} memory_bank_t;
+
+typedef struct memory_seg {
+ int id;
+ int intlv; /* interleave for this segment */
+ uint64_t base; /* base address for this segment */
+ uint64_t size; /* size of this segment */
+ int nbanks; /* number of banks in this segment */
+ memory_bank_t *banks; /* pointer to the banks of this seg */
+ struct memory_seg *next;
+} memory_seg_t;
+
+#define NUM_MBANKS_PER_MC 4
+
+int get_us3_mem_regs(Board_node *bnode);
+void display_us3_banks(void);
+int display_us3_failed_banks(int system_failed);
+void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
+void print_us3_failed_memory_line(int portid, int bank_id,
+ char *bank_status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LIBPRTDIAG_H */
diff --git a/usr/src/lib/libprtdiag/inc/pdevinfo.h b/usr/src/lib/libprtdiag/inc/pdevinfo.h
new file mode 100644
index 0000000000..fc6e1bc8e7
--- /dev/null
+++ b/usr/src/lib/libprtdiag/inc/pdevinfo.h
@@ -0,0 +1,192 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PDEVINFO_H
+#define _PDEVINFO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* structures necessary to hold Openprom data */
+
+/*
+ * 128 is the size of the largest (currently) property name
+ * 4096 - MAXPROPSIZE - sizeof (int) is the size of the largest
+ * (currently) property value that is allowed.
+ * the sizeof (u_int) is from struct openpromio
+ */
+#define MAXPROPSIZE 128
+#define MAXVALSIZE (4096 - MAXPROPSIZE - sizeof (uint_t))
+#define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (uint_t))
+typedef union {
+ char buf[BUFSIZE];
+ struct openpromio opp;
+ void *val_ptr;
+} Oppbuf;
+
+/*
+ * The prop structures associated with a Prom_node were formerly statically
+ * sized - via the buf element of the Oppbuf union. This was highly memory
+ * inefficient, so dynamic sizing capabilities have been introduced.
+ *
+ * This has been achieved via the creation of dynopenpromio and dynOppbuf
+ * structs, and altering the prop structure. The prop structure's name and value
+ * elements are now typed as dynOppbuf instead of Oppbuf.
+ *
+ * For legacy purposes, static_prop has been created. It is essentially the same
+ * as the former prop structure, but the *next element now points to a
+ * static_prop structure instead of a prop structure.
+ */
+typedef struct static_prop StaticProp;
+struct static_prop {
+ StaticProp *next;
+ Oppbuf name;
+ Oppbuf value;
+ int size; /* size of data in bytes */
+};
+
+/*
+ * dynopenpromio structs are similar to openpromio structs, but with 2 major
+ * differences. The first is that the opio_u.b element is char * instead of
+ * char [], which allows for dynamic sizing.
+ *
+ * The second regards opio_u.i, which was an int, but is now int []. In almost
+ * all cases, only opio_u.i (opio_u.i[0]) will be referenced. However, certain
+ * platforms rely on the fact that Prop structures formerly contained Oppbuf
+ * unions, the buf element of which was statically sized at 4k. In theory, this
+ * enabled those platforms to validly reference any part of the union up to 4k
+ * from the start. In reality, no element greater than opio_u.i[4] is currently
+ * referenced, hence OPROM_NODE_SIZE (named because opio_u.i is usually
+ * referenced as oprom_node) being set to 5.
+ *
+ * A minor difference is that the holds_array element has been added, which
+ * affords an easy way to determine whether opio_u contains char * or int.
+ */
+#define OPROM_NODE_SIZE 5
+struct dynopenpromio {
+ uint_t oprom_size;
+ union {
+ char *b;
+ int i[OPROM_NODE_SIZE];
+ } opio_u;
+ uint_t holds_array;
+};
+
+/*
+ * dynOppbuf structs are a dynamic alternative to Oppbuf unions. The statically
+ * sized Oppbuf.buf element has been removed, and the opp element common to both
+ * is of type struct dynopenpromio instead of struct openpromio. This allows us
+ * to take advantage of dynopenpromio's dynamic sizing capabilities.
+ */
+typedef struct dynoppbuf dynOppbuf;
+struct dynoppbuf {
+ struct dynopenpromio opp;
+ char *val_ptr;
+};
+
+typedef struct prop Prop;
+struct prop {
+ Prop *next;
+ dynOppbuf name;
+ dynOppbuf value;
+ int size; /* size of data in bytes */
+};
+
+typedef struct prom_node Prom_node;
+struct prom_node {
+ Prom_node *parent; /* points to parent node */
+ Prom_node *child; /* points to child PROM node */
+ Prom_node *sibling; /* point to next sibling */
+ Prop *props; /* points to list of properties */
+};
+
+/*
+ * Defines for board types.
+ */
+
+typedef struct board_node Board_node;
+struct board_node {
+ int node_id;
+ int board_num;
+ int board_type;
+ Prom_node *nodes;
+ Board_node *next; /* link for list */
+};
+
+typedef struct system_tree Sys_tree;
+struct system_tree {
+ Prom_node *sys_mem; /* System memory node */
+ Prom_node *boards; /* boards node holds bif info if present */
+ Board_node *bd_list; /* node holds list of boards */
+ int board_cnt; /* number of boards in the system */
+};
+
+int do_prominfo(int, char *, int, int);
+int is_openprom(void);
+void promclose(void);
+int promopen(int);
+extern char *badarchmsg;
+int _error(char *fmt, ...);
+
+/* Functions for building the user copy of the device tree. */
+Board_node *find_board(Sys_tree *, int);
+Board_node *insert_board(Sys_tree *, int);
+
+/* functions for searching for Prom nodes */
+char *get_node_name(Prom_node *);
+char *get_node_type(Prom_node *);
+Prom_node *dev_find_node(Prom_node *, char *);
+Prom_node *dev_next_node(Prom_node *, char *);
+Prom_node *dev_find_node_by_type(Prom_node *root, char *type, char *property);
+Prom_node *dev_next_node_by_type(Prom_node *root, char *type, char *property);
+Prom_node *dev_find_type(Prom_node *, char *);
+Prom_node *dev_next_type(Prom_node *, char *);
+Prom_node *sys_find_node(Sys_tree *, int, char *);
+Prom_node *find_failed_node(Prom_node *);
+Prom_node *next_failed_node(Prom_node *);
+Prom_node *dev_find_node_by_compatible(Prom_node *root, char *compat);
+Prom_node *dev_next_node_by_compatible(Prom_node *root, char *compat);
+int node_failed(Prom_node *);
+int node_status(Prom_node *node, char *status);
+void dump_node(Prom_node *);
+int next(int);
+int has_board_num(Prom_node *);
+int get_board_num(Prom_node *);
+int child(int);
+
+/* functions for searching for properties, extracting data from them */
+void *get_prop_val(Prop *);
+void getpropval(struct openpromio *);
+Prop *find_prop(Prom_node *, char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PDEVINFO_H */
diff --git a/usr/src/lib/libprtdiag/inc/pdevinfo_sun4u.h b/usr/src/lib/libprtdiag/inc/pdevinfo_sun4u.h
new file mode 100644
index 0000000000..7273d62b8d
--- /dev/null
+++ b/usr/src/lib/libprtdiag/inc/pdevinfo_sun4u.h
@@ -0,0 +1,233 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _PDEVINFO_SUN4U_H
+#define _PDEVINFO_SUN4U_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/obpdefs.h>
+#include <sys/fhc.h>
+#include <sys/sysctrl.h>
+#include <sys/environ.h>
+#include <sys/envctrl_gen.h>
+#include <sys/envctrl_ue250.h>
+#include <sys/envctrl_ue450.h>
+#include <sys/simmstat.h>
+#include <sys/ac.h>
+#include <sys/sram.h>
+#include <reset_info.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UNIX "unix"
+
+/* Define names of nodes to search for */
+#define CPU_NAME "SUNW,UltraSPARC"
+#define SBUS_NAME "sbus"
+#define PCI_NAME "pci"
+#define FFB_NAME "SUNW,ffb"
+#define AFB_NAME "SUNW,afb"
+
+struct mem_stat_data {
+ enum ac_bank_status status; /* bank status values */
+ enum ac_bank_condition condition; /* bank conditions */
+};
+
+struct bd_kstat_data {
+ u_longlong_t ac_memctl; /* Memctl register contents */
+ u_longlong_t ac_memdecode[2]; /* memory decode registers . */
+ int ac_kstats_ok; /* successful kstat read occurred */
+ uint_t fhc_bsr; /* FHC Board Status Register */
+ uint_t fhc_csr; /* FHC Control Status Register */
+ int fhc_kstats_ok; /* successful kstat read occurred */
+ uchar_t simm_status[SIMM_COUNT]; /* SIMM status */
+ int simmstat_kstats_ok; /* successful read occurred */
+ struct temp_stats tempstat;
+ int temp_kstat_ok;
+ struct mem_stat_data mem_stat[2]; /* raw kstat bank information */
+ int ac_memstat_ok; /* successful read of memory status */
+};
+
+/*
+ * Hot plug info structure. If a hotplug kstat is found, the bd_info
+ * structure from the kstat is filled in the the hp_info structure
+ * is marked OK.
+ */
+struct hp_info {
+ struct bd_info bd_info;
+ int kstat_ok;
+};
+
+/* Environmental info for Tazmo */
+struct envctrl_kstat_data {
+ envctrl_ps_t ps_kstats[MAX_DEVS]; /* kstats for powersupplies */
+ envctrl_fan_t fan_kstats[MAX_DEVS]; /* kstats for fans */
+ envctrl_encl_t encl_kstats[MAX_DEVS]; /* kstats for enclosure */
+};
+
+/* Environmental info for Javelin */
+struct envctrltwo_kstat_data {
+ envctrl_ps2_t ps_kstats[MAX_DEVS]; /* kstats for powersupplies */
+ int num_ps_kstats;
+ envctrl_fan_t fan_kstats[MAX_DEVS]; /* kstats for fans */
+ int num_fan_kstats;
+ envctrl_encl_t encl_kstats[MAX_DEVS]; /* kstats for enclosure */
+ int num_encl_kstats;
+ envctrl_temp_t temp_kstats[MAX_DEVS]; /* kstats for temperatures */
+ int num_temp_kstats;
+ envctrl_disk_t disk_kstats[MAX_DEVS]; /* kstats for disks */
+ int num_disk_kstats;
+};
+
+struct system_kstat_data {
+ uchar_t sysctrl; /* sysctrl register contents */
+ uchar_t sysstat1; /* system status1 register contents. */
+ uchar_t sysstat2; /* system status2 register contents. */
+ uchar_t ps_shadow[SYS_PS_COUNT]; /* power supply shadow */
+ int psstat_kstat_ok;
+ uchar_t clk_freq2; /* clock frequency register 2 contents */
+ uchar_t fan_status; /* shadow fan status */
+ uchar_t keysw_status; /* status of the key switch */
+ enum power_state power_state; /* redundant power state */
+ uchar_t clk_ver; /* clock version register */
+ int sys_kstats_ok; /* successful kstat read occurred */
+ struct temp_stats tempstat;
+ int temp_kstat_ok;
+ struct reset_info reset_info;
+ int reset_kstats_ok; /* kstat read OK */
+ struct bd_kstat_data bd_ksp_list[MAX_BOARDS];
+ struct hp_info hp_info[MAX_BOARDS];
+ struct ft_list *ft_array; /* fault array */
+ int nfaults; /* number of faults in fault array */
+ int ft_kstat_ok; /* Fault kstats OK */
+ struct envctrl_kstat_data env_data; /* environment data for Tazmo */
+ int envctrl_kstat_ok;
+ struct envctrltwo_kstat_data envc_data; /* environ data for Javelin */
+ int envctrltwo_kstat_ok;
+};
+
+/* Description of a single memory group */
+struct grp {
+ int valid; /* active memory group present */
+ u_longlong_t base; /* Phyiscal base of group */
+ uint_t size; /* size in bytes */
+ uint_t curr_size; /* current size in bytes */
+ int board; /* board number */
+ enum board_type type; /* board type */
+ int group; /* group # on board (0 or 1) */
+ int factor; /* interleave factor (0,2,4,8,16) */
+ int speed; /* Memory speed (in ns) */
+ char groupid; /* Alpha tag for group ID */
+ enum ac_bank_status status; /* bank status values */
+ enum ac_bank_condition condition; /* bank conditions */
+};
+
+#define MAX_GROUPS 32
+#define MAXSTRLEN 256
+
+/* Array of all possible groups in the system. */
+struct grp_info {
+ struct grp grp[MAX_GROUPS];
+};
+
+/* A memory interleave structure */
+struct inter_grp {
+ u_longlong_t base; /* Physical base of group */
+ int valid;
+ int count;
+ char groupid;
+};
+
+/* Array of all possible memory interleave structures */
+struct mem_inter {
+ struct inter_grp i_grp[MAX_GROUPS];
+};
+
+/* FFB info structure */
+struct ffbinfo {
+ int board;
+ int upa_id;
+ char *dev;
+ struct ffbinfo *next;
+};
+
+/* FFB strap reg union */
+union strap_un {
+ struct {
+ uint_t unused:24;
+ uint_t afb_flag:1;
+ uint_t major_rev:2;
+ uint_t board_rev:2;
+ uint_t board_mem:1;
+ uint_t cbuf:1;
+ uint_t bbuf:1;
+ } fld;
+ uint_t ffb_strap_bits;
+};
+
+/* known values for manufacturer's JED code */
+#define MANF_BROOKTREE 214
+#define MANF_MITSUBISHI 28
+
+/* FFB mnufacturer union */
+union manuf {
+ struct {
+ uint_t version:4; /* version of part number */
+ uint_t partno:16; /* part number */
+ uint_t manf:11; /* manufacturer's JED code */
+ uint_t one:1; /* always set to '1' */
+ } fld;
+ uint_t encoded_id;
+};
+
+#define FFBIOC ('F' << 8)
+#define FFB_SYS_INFO (FFBIOC| 80)
+
+struct ffb_sys_info {
+ unsigned int ffb_strap_bits; /* ffb_strapping register */
+#define FFB_B_BUFF 0x01 /* B buffer present */
+#define FFB_C_BUFF 0x02 /* C buffer present */
+#define FB_TYPE_AFB 0x80 /* AFB or FFB */
+ unsigned int fbc_version; /* revision of FBC chip */
+ unsigned int dac_version; /* revision of DAC chip */
+ unsigned int fbram_version; /* revision of FBRAMs chip */
+ unsigned int flags; /* miscellaneous flags */
+#define FFB_KSIM 0x00000001 /* kernel simulator */
+#define FFB_PAGE_FILL_BUG 0x00000002 /* FBRAM has page fill bug */
+ unsigned int afb_nfloats; /* no. of Float asics in AFB */
+ unsigned int pad[58]; /* padding for AFB chips & misc. */
+};
+
+int get_id(Prom_node *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PDEVINFO_SUN4U_H */
diff --git a/usr/src/lib/libprtdiag/inc/reset_info.h b/usr/src/lib/libprtdiag/inc/reset_info.h
new file mode 100644
index 0000000000..8f94813a6f
--- /dev/null
+++ b/usr/src/lib/libprtdiag/inc/reset_info.h
@@ -0,0 +1,108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _RESET_INFO_H
+#define _RESET_INFO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * All of the following data structures and defines come from sun4u server
+ * POST. If the data in POST changes, then these structures must reflect
+ * those changes.
+ */
+
+#include <sys/fhc.h> /* To get MAX_BOARDS constant */
+
+/* BDA bit assignments */
+#define BOARD_PRESENT (1<<0)
+#define BOARD_OK (1<<1)
+#define BOARD_TYPE_MSK (7<<2)
+#define BOARD_TYPE(x) (((x) & BOARD_TYPE_MSK) >> 2)
+
+/* Board state mask and defines */
+#define BD_STATE_MASK 0x3
+#define BD_LPM_FZN 0
+#define BD_ONLINE_FAIL 1
+#define BD_NOT_PRESENT 2
+#define BD_ONLINE_NORMAL 3
+
+/* define CPU 0 fields */
+#define CPU0_PRESENT (1<<8)
+#define CPU0_OK (1<<9)
+#define CPU0_FAIL_CODE_MSK (7<<10)
+
+/* define CPU 1 fields */
+#define CPU1_PRESENT (1<<16)
+#define CPU1_OK (1<<17)
+#define CPU1_FAIL_CODE_MSK (7<<18)
+
+/* supported board types */
+#define CPU_TYPE 0
+#define MEM_TYPE 1 /* CPU/MEM board with only memory */
+#define IO_TYPE1 2
+#define IO_TYPE2 3
+#define IO_TYPE3 4
+#define IO_TYPE4 5 /* same as IO TYPE 1 but no HM or PHY chip */
+#define CLOCK_TYPE 7
+
+/* for CPU type UPA ports */
+typedef struct {
+ u_longlong_t afsr; /* Fault status register for CPU */
+ u_longlong_t afar; /* Fault address register for CPU */
+} cpu_reset_state;
+
+/* For the clock board */
+typedef struct {
+ unsigned long clk_ssr_1; /* reset status for the clock board */
+} clock_reset_state;
+
+struct board_info {
+ u_longlong_t board_desc;
+ cpu_reset_state cpu[2]; /* could be a CPU */
+ u_longlong_t ac_error_status;
+ u_longlong_t dc_shadow_chain;
+ uint_t fhc_csr;
+ uint_t fhc_rcsr;
+};
+
+struct reset_info {
+ int length; /* size of the structure */
+ int version; /* Version of the structure */
+ struct board_info bd_reset_info[MAX_BOARDS];
+ clock_reset_state clk; /* one clock board */
+ unsigned char tod_timestamp[7];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RESET_INFO_H */
diff --git a/usr/src/lib/libprtdiag/sparc/Makefile b/usr/src/lib/libprtdiag/sparc/Makefile
new file mode 100644
index 0000000000..71383e8afa
--- /dev/null
+++ b/usr/src/lib/libprtdiag/sparc/Makefile
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# lib/libprtdiag/sparc/Makefile
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+SUBDIRS= sun4u sun4v
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all install clean clobber lint _msg : $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libprtdiag/sparc/sun4u/Makefile b/usr/src/lib/libprtdiag/sparc/sun4u/Makefile
new file mode 100644
index 0000000000..b67715c346
--- /dev/null
+++ b/usr/src/lib/libprtdiag/sparc/sun4u/Makefile
@@ -0,0 +1,80 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag/sparc/sun4u/Makefile
+#
+# Platform specific Makefile for libprtdiag.
+#
+# PLATFORM is the target for the binary installation.
+#
+
+PLATFORM = sun4u
+
+OBJECTS = io.o cpu.o memory.o kstat.o prom.o \
+ pdevinfo_funcs.o display_funcs.o \
+ pdevinfo_sun4u.o display_sun4u.o \
+ libdevinfo_sun4u.o
+
+include ../../Makefile.com
+
+SRCS = $(OBJECTS:%.o=../../common/%.c)
+LDLIBS += -ldevinfo
+
+#
+# used for creating message catalogue files
+#
+TEXT_DOMAIN= SUNW_OST_OSLIB
+SED= sed
+GREP= grep
+CP= cp
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: all $(USR_PSM_LIBS) $(USR_PSMLINT)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
+
+POFILE= libprtdiag_sun4u.po
+POFILES= generic.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../../common/*.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag/sparc/sun4v/Makefile b/usr/src/lib/libprtdiag/sparc/sun4v/Makefile
new file mode 100644
index 0000000000..bbd5bb119e
--- /dev/null
+++ b/usr/src/lib/libprtdiag/sparc/sun4v/Makefile
@@ -0,0 +1,79 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag/sparc/sun4v/Makefile
+#
+# Platform specific Makefile for libprtdiag.
+#
+# PLATFORM is the target for the binary installation.
+#
+
+PLATFORM = sun4v
+
+OBJECTS = io.o cpu.o memory.o kstat.o prom.o \
+ pdevinfo_funcs.o display_funcs.o \
+ pdevinfo_sun4v.o display_sun4v.o
+
+include ../../Makefile.com
+
+SRCS = $(OBJECTS:%.o=../../common/%.c)
+LDLIBS += -lpicl
+
+#
+# used for creating message catalogue files
+#
+TEXT_DOMAIN= SUNW_OST_OSLIB
+SED= sed
+GREP= grep
+CP= cp
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: all $(USR_PSM_LIBS)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
+
+POFILE= libprtdiag_sun4v.po
+POFILES= generic.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../../common/*.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/Makefile b/usr/src/lib/libprtdiag_psr/Makefile
new file mode 100644
index 0000000000..d52784045d
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/Makefile
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/Makefile
+
+include $(SRC)/Makefile.master
+
+SUBDIRS= $(MACH)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+delete := TARGET= delete
+install := TARGET= install
+lint := TARGET= lint
+package := TARGET= package
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all clean clobber delete install lint package _msg: $(SUBDIRS)
+
+$(MACH) $(MACH64): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/libprtdiag_psr/sparc/Makefile b/usr/src/lib/libprtdiag_psr/sparc/Makefile
new file mode 100644
index 0000000000..e9d36c0d44
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/Makefile
@@ -0,0 +1,49 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/Makefile
+
+PRTDIAG_PLATFORMS= desktop tazmo javelin sunfire starfire serengeti \
+ montecarlo littleneck starcat daktari cherrystone \
+ lw8 snowbird ontario schumacher
+
+all := TARGET= all
+lint := TARGET= lint
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all lint clean clobber install _msg : $(PRTDIAG_PLATFORMS)
+
+$(PRTDIAG_PLATFORMS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/Makefile.com b/usr/src/lib/libprtdiag_psr/sparc/Makefile.com
new file mode 100644
index 0000000000..18df32a634
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/Makefile.com
@@ -0,0 +1,71 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY= libprtdiag_psr.a
+VERS= .1
+
+#
+# PSR_MACH is defined sun4u so previous sun4u platforms can still continue
+# to use sun4u libraries but sun4v platforms can override it to use sun4v
+# libraries.
+#
+PSR_MACH= sun4u
+#
+# PLATFORM_OBJECTS is defined in ./desktop ./wgs ./sunfire ./starfire Makefiles
+#
+OBJECTS= $(PLATFORM_OBJECTS)
+
+# include library definitions
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/Makefile.psm
+
+SRCS= $(OBJECTS:%.o=./common/%.c)
+
+LIBS = $(DYNLIB)
+
+CFLAGS += $(CCVERBOSE)
+IFLAGS += -I $(UTSBASE)/sun4u
+IFLAGS += -I $(UTSCLOSED)/sun4u
+IFLAGS += -I $(UTSCLOSED)/sun4u/sunfire -I $(UTSBASE)/sun4u/sunfire
+CPPFLAGS = $(IFLAGS) $(CPPFLAGS.master)
+LDLIBS += -L $(ROOT)/usr/platform/$(PSR_MACH)/lib -lprtdiag -lc
+DYNFLAGS += -R /usr/platform/$(PSR_MACH)/lib
+INS.slink6= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/libprtdiag_psr.so.1 $@ $(CHOWNLINK) $(CHGRPLINK)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+# include library targets
+include $(SRC)/lib/Makefile.targ
+
+objs/%.o pics/%.o: ./common/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/libprtdiag_psr/sparc/cherrystone/Makefile b/usr/src/lib/libprtdiag_psr/sparc/cherrystone/Makefile
new file mode 100644
index 0000000000..c5b46abb4e
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/cherrystone/Makefile
@@ -0,0 +1,107 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/cherrystone/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= cherrystone.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+IFLAGS += -I $(SRC)/cmd/picl/plugins/sun4u/psvc/psvcobj
+IFLAGS += -I$(UTSBASE)/sun4u
+
+LDLIBS += -lpicl
+
+LINTFLAGS += $(IFLAGS)
+
+#
+# links in /usr/platform
+#
+LINKED_PLATFORMS = SUNW,Sun-Fire-V490
+
+LINKED_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%)
+LINKED_LIB_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib)
+LINKED_PRTDIAG_DIRS = \
+ $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/libprtdiag_psr.so.1)
+
+#
+# Workgroup Server platform library should install into
+# SUNW,Ultra-4. All other desktop platforms can
+# link to /usr/platform/SUNW,Ultra-4/lib/libprtdiag_psr.so
+#
+PLATFORM=SUNW,Sun-Fire-480R
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS) $(LINKED_PRTDIAG_DIRS)
+
+#
+# install rule
+#
+
+$(PLATLIBS):
+ $(INS.dir)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/cherrystone; pwd ; $(MAKE) $(USR_PSM_LIB_DIR)
+
+$(LINKED_DIRS): $(USR_PLAT_DIR)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIB_DIRS): $(LINKED_DIRS)
+ -$(INS.dir.root.sys)
+
+$(LINKED_PRTDIAG_DIRS): $(USR_PLAT_DIR)
+ -$(INS.slink6)
+
+#
+# used for message files
+#
+POFILE= libprtdiag_psr_cherrystone.po
+POFILES= cherrystone.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/*.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/cherrystone.c b/usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/cherrystone.c
new file mode 100644
index 0000000000..6f5f957591
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/cherrystone.c
@@ -0,0 +1,919 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ *
+ * Cherrystone platform-specific functions
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <note.h>
+#include <syslog.h>
+
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+
+#include <pdevinfo.h>
+#include <display.h>
+#include <pdevinfo_sun4u.h>
+#include <display_sun4u.h>
+
+#include <picl.h>
+
+#include <sys/cheetahregs.h>
+#include <sys/cherrystone.h>
+#include "workfile.c"
+
+#define SCHIZO_COMPAT_PROP "pci108e,8001"
+
+#define MULTIPLE_BITS_SET(x) ((x)&((x)-1))
+
+#define MAX_PS 2
+#define MAX_PS_SENSORS 3
+#define MAX_DISKS 2
+#define MAX_FANS 5
+#define NUM_PCI_SLOTS 5
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (workgroup server systems only)
+ */
+void display_cpu_devices(Sys_tree *tree);
+void display_pci(Board_node *board);
+void display_io_cards(struct io_card *list);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_ffb(Board_node *board, int table);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+
+/* local functions */
+static void disp_envc_status(void);
+static int print_temps(picl_nodehdl_t);
+static int print_keyswitch(picl_nodehdl_t);
+static int print_FSP_LEDS(picl_nodehdl_t);
+static int print_disk(picl_nodehdl_t);
+static int print_fans(picl_nodehdl_t);
+static int print_ps(picl_nodehdl_t);
+
+static void display_hw_revisions(Prom_node *root,
+ Board_node *bnode);
+static void display_schizo_revisions(Board_node *bdlist);
+
+
+void
+display_cpu_devices(Sys_tree *tree)
+{
+ Board_node *bnode;
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n========================= CPUs "
+ "===============================================\n\n"
+ " Run E$ CPU CPU \n"
+ "Brd CPU MHz MB Impl. Mask \n"
+ "--- ----- ---- ---- ------- ---- \n"));
+
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ display_cpus(bnode);
+ bnode = bnode->next;
+ }
+
+ log_printf("\n");
+}
+void
+display_cpus(Board_node *board)
+{
+ Prom_node *cpu;
+ int freq;
+ int ecache_size;
+ int *l3_shares;
+ int *mid;
+ int *impl;
+ int *mask;
+ int *coreid;
+ char fru_prev = 'X'; /* Valid frus are 'A','B' */
+ int mid_prev;
+ int ecache_size_prev = 0;
+ char fru_name;
+
+ /*
+ * display the CPUs' operating frequency, cache size, impl. field
+ * and mask revision.
+ */
+
+ for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
+ cpu = dev_next_type(cpu, "cpu")) {
+
+ mid = (int *)get_prop_val(find_prop(cpu, "portid"));
+ if (mid == NULL)
+ mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
+ freq = HZ_TO_MHZ(get_cpu_freq(cpu));
+ ecache_size = get_ecache_size(cpu);
+ impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
+ mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
+ l3_shares =
+ (int *)get_prop_val(find_prop(cpu, "l3-cache-sharing"));
+
+ /* Do not display a failed CPU node */
+ if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
+ continue;
+
+ fru_name = CHERRYSTONE_GETSLOT_LABEL(*mid);
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ coreid = (int *)get_prop_val(find_prop(cpu, "reg"));
+ if (coreid == NULL) {
+ continue;
+ }
+ if ((fru_prev == 'X') ||
+ ((fru_prev != 'X') &&
+ (fru_name != fru_prev))) {
+ fru_prev = fru_name;
+ mid_prev = *mid;
+ ecache_size_prev = ecache_size;
+ continue;
+ } else {
+ /*
+ * Some CMP chips have a split E$,
+ * so the size for both cores is added
+ * together to get the total size for
+ * the chip.
+ *
+ * Still, other CMP chips have E$ (L3)
+ * which is logically shared, so the
+ * total size is equal to the core size.
+ */
+ if ((l3_shares == NULL) ||
+ ((l3_shares != NULL) &&
+ MULTIPLE_BITS_SET(*l3_shares))) {
+ ecache_size += ecache_size_prev;
+ }
+ ecache_size_prev = 0;
+ fru_prev = 'X';
+ }
+ }
+
+ log_printf(" %c", fru_name);
+
+ /* CPU Module ID */
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ log_printf("%3d,%3d ", mid_prev, *mid, 0);
+ } else
+ log_printf(" %2d ", *mid);
+
+ /* Running frequency */
+ log_printf("%4d", freq);
+
+ if (ecache_size == 0)
+ log_printf(" N/A ");
+ else
+ log_printf(" %4.1f ",
+ (float)ecache_size / (float)(1<<20));
+ /* Implementation */
+ if (impl == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, " N/A "));
+ } else {
+ if (IS_CHEETAH(*impl))
+ log_printf(dgettext(TEXT_DOMAIN,
+ "US-III "));
+ else if (IS_CHEETAH_PLUS(*impl))
+ log_printf(dgettext(TEXT_DOMAIN,
+ "US-III+ "));
+ else if (IS_JAGUAR(*impl))
+ log_printf(dgettext(TEXT_DOMAIN,
+ "US-IV "));
+ else if (IS_PANTHER(*impl))
+ log_printf(dgettext(TEXT_DOMAIN,
+ "US-IV+ "));
+ else
+ log_printf("%-6x ", *impl);
+ }
+
+ /* CPU Mask */
+ if (mask == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, " N/A\n"));
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN, " %d.%d\n"),
+ (*mask >> 4) & 0xf, *mask & 0xf);
+ }
+ }
+}
+
+/*ARGSUSED0*/
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode = tree->bd_list;
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "========================= Memory Configuration"
+ " ===============================\n\n"
+ " Logical Logical Logical\n"
+ " MC Bank Bank Bank DIMM "
+ "Interleave Interleaved\n"
+ "Brd ID num size Status Size "
+ "Factor with\n"
+ "--- --- ---- ------ ----------- ------ "
+ "---------- -----------"));
+
+ while (bnode != NULL) {
+ if (get_us3_mem_regs(bnode)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nFailed to get memory information.\n"));
+ return;
+ }
+ bnode = bnode->next;
+ }
+
+ /* Display what we have found */
+ display_us3_banks();
+}
+
+/*ARGSUSED3*/
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is if the user
+ * told us to do logging, and we found a system failure.
+ */
+
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ disp_envc_status();
+
+ display_hw_revisions(root, tree->bd_list);
+ }
+ return;
+
+}
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+void
+display_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+ Prom_node *pci;
+ Prom_node *card_node;
+ static int banner = FALSE;
+
+ char *slot_name_arr[NUM_PCI_SLOTS];
+ int i;
+
+ if (board == NULL)
+ return;
+
+ memset(&card, 0, sizeof (struct io_card));
+ /* Initialize all the common information */
+ card.display = TRUE;
+ card.board = board->board_num;
+
+ /*
+ * Search for each pci instance, then find/display all nodes under
+ * each instance node found.
+ */
+ for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
+ pci != NULL;
+ pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
+ (void) snprintf(card.bus_type, MAXSTRLEN,
+ dgettext(TEXT_DOMAIN, "PCI"));
+ /*
+ * Get slot-name properties from parent node and
+ * store them in an array.
+ */
+ value = (char *)get_prop_val(
+ find_prop(pci, "slot-names"));
+
+ if (value != NULL) {
+ /* array starts after first int */
+ slot_name_arr[0] = (char *)value + sizeof (int);
+ for (i = 1; i < NUM_PCI_SLOTS; i++) {
+ slot_name_arr[i] = (char *)slot_name_arr[i - 1]
+ + strlen(slot_name_arr[i - 1]) +1;
+ }
+ }
+ /*
+ * Search for Children of this node ie. Cards.
+ * Note: any of these cards can be a pci-bridge
+ * that itself has children. If we find a
+ * pci-bridge we need to handle it specially.
+ */
+ card_node = pci->child;
+ /* Generate the list of pci cards on pci instance: pci */
+ fill_pci_card_list(pci, card_node, &card, &card_list,
+ slot_name_arr);
+ } /* end-for */
+
+ if (!banner && card_list != NULL) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ " Bus Max\n"
+ " IO Port Bus Freq Bus Dev,\n"
+ "Type ID Side Slot MHz Freq Func State "
+ "Name Model"
+#ifdef DEBUG
+ " Notes"
+#endif
+ "\n"
+ "---- ---- ---- ---- ---- ---- ---- ----- "
+ "-------------------------------- "
+#ifdef DEBUG
+ "---------------------- "
+#endif
+ "----------------------\n"));
+ banner = TRUE;
+ }
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ struct io_card *p;
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%-4s %-3d %c %-1s %-3d"),
+ p->bus_type, p->schizo_portid, p->pci_bus,
+ p->slot_str, p->freq);
+
+ switch (p->pci_bus) {
+ case 'A':
+ log_printf(dgettext(TEXT_DOMAIN, " 66 "));
+ break;
+ case 'B':
+ log_printf(dgettext(TEXT_DOMAIN, " 33 "));
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%-1d,%-1d %-5s %-32.32s"),
+ p->dev_no, p->func_no, p->status, p->name);
+ if (strlen(p->name) > 32)
+ log_printf(dgettext(TEXT_DOMAIN, "+ "));
+ else
+ log_printf(dgettext(TEXT_DOMAIN, " "));
+ log_printf(dgettext(TEXT_DOMAIN, "%-22.22s"), p->model);
+ if (strlen(p->model) > 22)
+ log_printf(dgettext(TEXT_DOMAIN, "+"));
+#ifdef DEBUG
+ log_printf("%s", p->notes);
+#endif
+ log_printf("\n");
+ }
+}
+
+/*ARGSUSED*/
+void
+display_ffb(Board_node *board, int table)
+{
+ /* NOP, since there are no FFB's on this platform. */
+}
+
+
+/*
+ * local functions
+ */
+
+
+static void
+disp_envc_status()
+{
+ int err;
+ char *system = "SYSTEM";
+ picl_nodehdl_t system_node, root;
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "========================= Environmental Status "
+ "=========================\n\n"));
+
+ err = picl_initialize();
+ if (err != PICL_SUCCESS)
+ goto err_out;
+ err = picl_get_root(&root);
+ if (err != PICL_SUCCESS)
+ goto err_out;
+ err = find_child_device(root, system, &system_node);
+ if (err != PICL_SUCCESS)
+ goto err_out;
+
+ err = print_temps(system_node);
+ err |= print_keyswitch(system_node);
+ err |= print_FSP_LEDS(system_node);
+ err |= print_disk(system_node);
+ err |= print_fans(system_node);
+ err |= print_ps(system_node);
+
+ if (err != PICL_SUCCESS)
+ goto err_out;
+
+ return;
+
+err_out:
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nEnvironmental reporting error: %s\n"),
+ picl_strerror(err));
+}
+
+static int
+print_ps(picl_nodehdl_t system_node)
+{
+ int i, j, err = 0;
+ int32_t number;
+ picl_nodehdl_t *ps;
+ picl_nodehdl_t *ps_fail_sensor;
+ char name[PICL_PROPNAMELEN_MAX];
+ char fault_state[PICL_PROPNAMELEN_MAX];
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n\n"
+ "Power Supplies:\n"
+ "---------------\n"
+ "\n"
+ "Supply Status Fault Fan Fail Temp Fail\n"
+ "------ ------------ -------- --------- ---------\n"));
+
+ err = fill_device_array_from_id(system_node, "PSVC_PS", &number, &ps);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ for (i = 0; i < MAX_PS; i++) {
+ err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS)
+ continue;
+
+ log_printf(dgettext(TEXT_DOMAIN, "%6-s"), name);
+ err = picl_get_propval_by_name(ps[i], "FaultInformation",
+ fault_state, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ free(ps);
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, " [%-12s]"), fault_state);
+ if (strcmp(fault_state, "NO AC POWER") == 0) {
+ log_printf("\n");
+ continue;
+ }
+
+ err = fill_device_array_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
+ &number, &ps_fail_sensor);
+
+ if (err != PICL_SUCCESS) {
+ free(ps);
+ return (err);
+ }
+ log_printf(" ");
+ for (j = 0; j < MAX_PS_SENSORS; j++) {
+ err = picl_get_propval_by_name(ps_fail_sensor[j],
+ "State", fault_state, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ if (err == PICL_FAILURE) {
+ break;
+ }
+ free(ps);
+ free(ps_fail_sensor);
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, "%-10s"), fault_state);
+ }
+ log_printf("\n");
+ free(ps_fail_sensor);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n=================================\n\n"));
+
+ free(ps);
+ return (PICL_SUCCESS);
+}
+
+static int
+print_fans(picl_nodehdl_t system_node)
+{
+ int i, err;
+ int32_t number;
+ picl_nodehdl_t *fans;
+ picl_nodehdl_t phdl;
+ char prop[PICL_PROPNAMELEN_MAX];
+ char parent[PICL_PROPNAMELEN_MAX];
+ int32_t rpm;
+
+ err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
+ &fans);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n=================================\n\n"
+ "Fan Status:\n"
+ "-----------\n\n"
+ "Fan Tray Fan RPM Status\n"
+ "----------- ---- ----- ----------\n"));
+
+ for (i = 0; i < MAX_FANS; i++) {
+ err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, prop,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS)
+ continue;
+
+ err = fill_device_from_id(fans[i], "PSVC_PARENT", &phdl);
+ if (err != PICL_SUCCESS)
+ continue;
+ err = picl_get_propval_by_name(phdl, PICL_PROP_NAME, parent,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS)
+ continue;
+
+ log_printf(dgettext(TEXT_DOMAIN, "%-16s"), parent);
+
+
+ log_printf(dgettext(TEXT_DOMAIN, "%-16s"), prop);
+
+ err = picl_get_propval_by_name(fans[i], "Fan-speed",
+ &rpm, sizeof (rpm));
+ if (err != PICL_SUCCESS) {
+ free(fans);
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, "%5d "), rpm);
+
+ err = picl_get_propval_by_name(fans[i], "FaultInformation",
+ prop, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ free(fans);
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, " [%s]\n"), prop);
+ }
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n=================================\n\n"));
+ free(fans);
+ return (PICL_SUCCESS);
+}
+
+static int
+print_disk(picl_nodehdl_t system_node)
+{
+ int i, err;
+ int32_t number;
+ picl_nodehdl_t *disks;
+ char state[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
+ &disks);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Disk Status:\n"
+ "------------\n"));
+ for (i = 0; i < MAX_DISKS; i++) {
+ err = picl_get_propval_by_name(disks[i], "FaultInformation",
+ state, PICL_PROPNAMELEN_MAX);
+
+ switch (err) {
+ case PICL_SUCCESS:
+ log_printf(dgettext(TEXT_DOMAIN,
+ "DISK %d: [%3s]\n"), i, state);
+ break;
+ case PICL_INVALIDHANDLE:
+ log_printf(dgettext(TEXT_DOMAIN,
+ "DISK %d: [ NOT PRESENT ]\n"), i);
+ break;
+ default:
+ free(disks);
+ return (err);
+ }
+ }
+ free(disks);
+ return (PICL_SUCCESS);
+}
+
+static int
+print_FSP_LEDS(picl_nodehdl_t system_node)
+{
+ int err;
+ int32_t number;
+ picl_nodehdl_t *fsp_led;
+ char fault_state[PICL_PROPNAMELEN_MAX];
+ char locate_state[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
+ &fsp_led);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ assert(number == 2);
+ err = picl_get_propval_by_name(fsp_led[0], "State", &fault_state,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ free(fsp_led);
+ return (err);
+ }
+ err = picl_get_propval_by_name(fsp_led[1], "State", &locate_state,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ free(fsp_led);
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System LED Status:\n\n"
+ " LOCATOR FAULT POWER\n"
+ " ------- ------- -------\n"
+ " [%3s] [%3s] [ ON]"),
+ locate_state, fault_state);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n\n=================================\n\n"));
+ free(fsp_led);
+ return (err);
+}
+
+static int
+print_keyswitch(picl_nodehdl_t system_node)
+{
+ int err;
+ picl_nodehdl_t *keyswitch;
+ int32_t number;
+ char ks_pos[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
+ &keyswitch);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+ err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ free(keyswitch);
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Front Status Panel:\n"
+ "-------------------\n"
+ "Keyswitch position: %s\n\n"), ks_pos);
+ free(keyswitch);
+ return (err);
+}
+
+static int
+print_temps(picl_nodehdl_t system_node)
+{
+ int i;
+ int err;
+ picl_nodehdl_t *system_ts_nodes;
+ int32_t temp;
+ int32_t number;
+ char label[PICL_PROPNAMELEN_MAX];
+ char state[PICL_PROPNAMELEN_MAX];
+ char *p;
+
+ err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
+ &system_ts_nodes);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System Temperatures (Celsius):\n"
+ "-------------------------------\n"
+ "Device\t\tTemperature\tStatus\n"
+ "---------------------------------------\n"));
+
+ for (i = 0; i < number; i++) {
+ err = picl_get_propval_by_name(system_ts_nodes[i],
+ "State", state, sizeof (state));
+ if (err != PICL_SUCCESS) {
+ if (err == PICL_INVALIDHANDLE) {
+ strcpy(state, "n/a");
+ } else {
+ free(system_ts_nodes);
+ return (err);
+ }
+ }
+ err = picl_get_propval_by_name(system_ts_nodes[i],
+ PICL_PROP_NAME, label, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ if (err == PICL_INVALIDHANDLE)
+ /* This FRU isn't present. Skip it. */
+ continue;
+ free(system_ts_nodes);
+ return (err);
+ }
+
+ /*
+ * The names in the tree are like "CPU0_DIE_TEMPERATURE_SENSOR".
+ * All we want to print is up to the first underscore.
+ */
+ p = strchr(label, '_');
+ if (p != NULL)
+ *p = '\0';
+
+ err = picl_get_propval_by_name(system_ts_nodes[i],
+ "Temperature", &temp, sizeof (temp));
+ if (err != PICL_SUCCESS) {
+ free(system_ts_nodes);
+ return (err);
+ }
+ log_printf("%s\t\t%3d\t\t%s\n", label, temp, state);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n=================================\n\n"));
+
+ free(system_ts_nodes);
+ return (PICL_SUCCESS);
+}
+
+static void
+display_hw_revisions(Prom_node *root, Board_node *bdlist)
+{
+ Prom_node *pnode;
+ char *value;
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n"
+ "========================= HW Revisions "
+ "=======================================\n\n"));
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System PROM revisions:\n"
+ "----------------------\n"));
+
+ pnode = dev_find_node(root, "openprom");
+ if (pnode != NULL) {
+ value = (char *)get_prop_val(find_prop(pnode, "version"));
+ log_printf(value);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n\n"
+ "IO ASIC revisions:\n"
+ "------------------\n"
+ " Port\n"
+ "Model ID Status Version\n"
+ "-------- ---- ------ -------\n"));
+
+ display_schizo_revisions(bdlist);
+}
+
+
+static void
+display_schizo_revisions(Board_node *bdlist)
+{
+ Prom_node *pnode;
+ int *int_val;
+ int portid;
+ int prev_portid = -1;
+ char *status_a = NULL;
+ char *status_b = NULL;
+ int revision;
+#ifdef DEBUG
+ uint32_t a_notes, b_notes;
+#endif
+ int pci_bus;
+ Board_node *bnode;
+ bnode = bdlist;
+
+ while (bnode != NULL) {
+ /*
+ * search this board node for all Schizos
+ */
+
+ for (pnode = dev_find_node_by_compat(bnode->nodes,
+ SCHIZO_COMPAT_PROP); pnode != NULL;
+ pnode = dev_next_node_by_compat(pnode,
+ SCHIZO_COMPAT_PROP)) {
+
+ /*
+ * get the reg property to determine
+ * whether we are looking at side A or B
+ */
+
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "reg"));
+ if (int_val != NULL) {
+ int_val ++; /* second integer in array */
+ pci_bus = ((*int_val) & 0x7f0000);
+ }
+
+ /* get portid */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "portid"));
+ if (int_val == NULL)
+ continue;
+
+ portid = *int_val;
+
+ /*
+ * If this is a new portid and it is PCI bus B,
+ * we skip onto the PCI bus A.
+ */
+ if ((portid != prev_portid) && (pci_bus == 0x700000)) {
+ prev_portid = portid;
+ /* status */
+ status_b = (char *)get_prop_val
+ (find_prop(pnode, "status"));
+#ifdef DEBUG
+ b_notes = pci_bus;
+#endif
+ continue; /* skip to the next schizo */
+ }
+
+ /*
+ * This must be side A of the same Schizo.
+ * Gather all its props and display them.
+ */
+#ifdef DEBUG
+ a_notes = pci_bus;
+#endif
+
+ prev_portid = portid;
+
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "version#"));
+ if (int_val != NULL)
+ revision = *int_val;
+ else
+ revision = -1;
+
+ status_a = (char *)get_prop_val(find_prop
+ (pnode, "status"));
+
+ log_printf(dgettext(TEXT_DOMAIN, "Schizo "));
+
+ log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
+
+
+ log_printf((status_a == NULL && status_b == NULL) ?
+ dgettext(TEXT_DOMAIN, " ok ") :
+ dgettext(TEXT_DOMAIN, " fail "));
+
+ log_printf(dgettext(TEXT_DOMAIN, " %4d "),
+ revision);
+#ifdef DEBUG
+ log_printf(" 0x%x 0x%x", a_notes, b_notes);
+#endif
+ log_printf("\n");
+ }
+ bnode = bnode->next;
+ }
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/workfile.c b/usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/workfile.c
new file mode 100644
index 0000000000..333d8420da
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/cherrystone/common/workfile.c
@@ -0,0 +1,832 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2001, 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Cherrystone platform-specific functions that aren't platform specific
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libprtdiag.h>
+#include <sys/mc.h>
+
+
+static Prom_node *dev_next_node_by_compat(Prom_node *root, char *model);
+static Prom_node *dev_find_node_by_compat(Prom_node *root, char *model);
+
+void print_us3_memory_line(int portid,
+ int bank_id,
+ uint64_t bank_size,
+ char *bank_status,
+ uint64_t dimm_size,
+ uint32_t intlv,
+ int seg_id);
+
+void add_node(Sys_tree *root, Prom_node *pnode);
+int do_prominfo(int syserrlog,
+ char *pgname,
+ int log_flag,
+ int prt_flag);
+
+void *get_prop_val(Prop *prop);
+Prop *find_prop(Prom_node *pnode, char *name);
+char *get_node_name(Prom_node *pnode);
+char *get_node_type(Prom_node *pnode);
+
+void fill_pci_card_list(Prom_node *pci_instance,
+ Prom_node *pci_card_node,
+ struct io_card *pci_card,
+ struct io_card **pci_card_list,
+ char **pci_slot_name_arr);
+
+static Prom_node *next_pci_card(Prom_node *curr_card, int *is_bridge,
+ int is_pcidev, Prom_node *curr_bridge,
+ Prom_node * parent_bridge, Prom_node *pci);
+
+#define HZ_TO_MHZ(x) (((x) + 500000) / 1000000)
+
+/*
+ * Start from the current node and return the next node besides
+ * the current one which has the requested model property.
+ */
+static Prom_node *
+dev_next_node_by_compat(Prom_node *root, char *compat)
+{
+ Prom_node *node;
+
+ if (root == NULL)
+ return (NULL);
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+/*
+ * Do a depth-first walk of a device tree and
+ * return the first node with the matching model.
+ */
+static Prom_node *
+dev_find_node_by_compat(Prom_node *root, char *compat)
+{
+ Prom_node *node;
+ char *compatible;
+ char *name;
+
+ if (root == NULL)
+ return (NULL);
+
+ if (compat == NULL)
+ return (NULL);
+
+ name = get_node_name(root);
+ if (name == NULL)
+ name = "";
+
+ compatible = (char *)get_prop_val(find_prop(root, "compatible"));
+
+ if (compatible == NULL)
+ return (NULL);
+
+ if ((strcmp(name, "pci") == 0) && (compatible != NULL) &&
+ (strcmp(compatible, compat) == 0)) {
+ return (root); /* found a match */
+ }
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+int32_t
+find_child_device(picl_nodehdl_t parent, char *child_name,
+ picl_nodehdl_t *child)
+{
+ int32_t err;
+ char name[PICL_PROPNAMELEN_MAX];
+
+ err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child),
+ sizeof (picl_nodehdl_t));
+ switch (err) {
+ case PICL_SUCCESS:
+ break;
+ case PICL_PROPNOTFOUND:
+ err = PICL_INVALIDHANDLE;
+ return (err);
+ default:
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed picl_get_propval_by_name with %s\n"),
+ picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+
+#ifdef WORKFILE_DEBUG
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed the get name for root\n"));
+ log_printf(dgettext(TEXT_DOMAIN, "%s\n"), picl_strerror(err));
+ }
+#endif
+
+ if (strcmp(name, child_name) == 0)
+ return (err);
+
+ while (err != PICL_PROPNOTFOUND) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN, "child name is %s\n"), name);
+#endif
+ err = picl_get_propval_by_name(*child, PICL_PROP_PEER,
+ &(*child), sizeof (picl_nodehdl_t));
+ switch (err) {
+ case PICL_SUCCESS:
+ err = picl_get_propval_by_name(*child, PICL_PROP_NAME,
+ name, PICL_PROPNAMELEN_MAX);
+ if (strcmp(name, child_name) == 0)
+ return (err);
+ break;
+ case PICL_PROPNOTFOUND:
+ break;
+ default:
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed picl_get_propval_by_name with %s\n"),
+ picl_strerror(err));
+#endif
+ return (err);
+ }
+ }
+ err = PICL_INVALIDHANDLE;
+ return (err);
+}
+
+int32_t
+fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id,
+ picl_nodehdl_t *device)
+{
+ int32_t err;
+ picl_prophdl_t tbl_hdl;
+ picl_prophdl_t reference_property;
+
+ err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
+ sizeof (picl_prophdl_t));
+ if (err != PICL_SUCCESS) {
+#ifdef WORKFILE_DEBUG
+ if (err != PICL_INVALIDHANDLE) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in "
+ "picl_get_propval_by_name err is %s\n"),
+ picl_strerror(err));
+ }
+#endif
+ return (err);
+ }
+
+ err = picl_get_next_by_row(tbl_hdl, &reference_property);
+ if (err != PICL_SUCCESS) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in picl_get_next_by_row"
+ " err is %s\n"), picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ /* get node associated with reference property */
+ err = picl_get_propval(reference_property, &(*device),
+ sizeof (picl_nodehdl_t));
+
+#ifdef WORKFILE_DEBUG
+ if (err != 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in picl_get_propval"
+ " err is %s\n"), picl_strerror(err));
+ }
+#endif
+
+ return (err);
+}
+
+int32_t
+fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id,
+ int32_t *number_of_devices, picl_nodehdl_t *device_array[])
+{
+ int32_t err;
+ int i;
+ picl_prophdl_t tbl_hdl;
+ picl_prophdl_t entry;
+ int devs = 0;
+
+ err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
+ sizeof (picl_prophdl_t));
+ if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_propval_by_name err is %s\n"), picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ entry = tbl_hdl;
+ while (picl_get_next_by_row(entry, &entry) == 0)
+ ++devs;
+
+ *device_array = calloc((devs), sizeof (picl_nodehdl_t));
+ if (*device_array == NULL) {
+
+#ifdef WORFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure getting memory"
+ " for array\n"));
+#endif
+ return (PICL_FAILURE);
+ }
+
+ entry = tbl_hdl;
+ for (i = 0; i < devs; i++) {
+ err = picl_get_next_by_row(entry, &entry);
+ if (err != 0) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_next_by_row err is %s\n"),
+ picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ /* get node associated with reference property */
+ err = picl_get_propval(entry, &((*device_array)[i]),
+ sizeof (picl_nodehdl_t));
+ if (err != 0) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_propval err is %s\n"), picl_strerror(err));
+#endif
+
+ return (err);
+ }
+ }
+ *number_of_devices = devs;
+ return (err);
+}
+
+/*
+ * add_node
+ *
+ * This function adds a board node to the board structure where that
+ * that node's physical component lives.
+ */
+void
+add_node(Sys_tree *root, Prom_node *pnode)
+{
+ int board = -1;
+ int portid = -1;
+
+ void *value = NULL;
+ Board_node *bnode = NULL;
+ Prom_node *p = NULL;
+
+ /* Get the board number of this board from the portid prop */
+ value = get_prop_val(find_prop(pnode, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+
+ board = CHERRYSTONE_GETSLOT(portid);
+
+ if ((bnode = find_board(root, board)) == NULL) {
+ bnode = insert_board(root, board);
+ }
+
+ /* now attach this prom node to the board list */
+ /* Insert this node at the end of the list */
+ pnode->sibling = NULL;
+ if (bnode->nodes == NULL)
+ bnode->nodes = pnode;
+ else {
+ p = bnode->nodes;
+ while (p->sibling != NULL)
+ p = p->sibling;
+ p->sibling = pnode;
+ }
+}
+
+/*
+ * This function provides formatting of the memory config
+ * information that get_us3_mem_regs() and display_us3_banks() code has
+ * gathered. It overrides the generic print_us3_memory_line() code
+ * which prints an error message.
+ */
+void
+print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
+{
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n %-1c %2d %2d %4lldMB %11-s %4lldMB "
+ " %2d-way %d"),
+ CHERRYSTONE_GETSLOT_LABEL(portid), portid,
+ (bank_id % 4), bank_size, bank_status, dimm_size,
+ intlv, seg_id, 0);
+}
+
+/*
+ * We call do_devinfo() in order to use the libdevinfo device tree
+ * instead of OBP's device tree.
+ */
+int
+do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+ return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
+}
+
+/*
+ * return the property value for the Prop
+ * passed in. (When using libdevinfo)
+ */
+void *
+get_prop_val(Prop *prop)
+{
+ if (prop == NULL)
+ return (NULL);
+
+ return ((void *)(prop->value.val_ptr));
+}
+
+/*
+ * Search a Prom node and retrieve the property with the correct
+ * name. (When using libdevinfo)
+ */
+Prop *
+find_prop(Prom_node *pnode, char *name)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ if (pnode->props == NULL)
+ return (NULL);
+
+ prop = pnode->props;
+ if (prop == NULL)
+ return (NULL);
+
+ if (prop->name.val_ptr == NULL)
+ return (NULL);
+
+ while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) {
+ prop = prop->next;
+ }
+ return (prop);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property.
+ * (When using libdevinfo)
+ */
+char *
+get_node_name(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("name", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the device_type property.
+ * (When using libdevinfo)
+ */
+char *
+get_node_type(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+
+/*
+ * Fills in the i/o card list to be displayed later in display_pci();
+ */
+void
+fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node,
+ struct io_card *pci_card,
+ struct io_card **pci_card_list, char **slot_name_arr)
+{
+ Prom_node *pci_bridge_node;
+ Prom_node *pci_parent_bridge;
+ int *int_val;
+ int pci_bridge = FALSE;
+ int pci_bridge_dev_no = -1;
+ int portid;
+ int pci_bus;
+ char buf[MAXSTRLEN];
+ char *slot_name = NULL; /* info in "slot-names" prop */
+ char *child_name;
+ char *name;
+ char *type;
+ void *value;
+
+ while (pci_card_node != NULL) {
+ int is_pci = FALSE;
+ type = NULL;
+ name = NULL;
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(pci_card_node, "name"));
+ if (name == NULL) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+
+ /*
+ * Get the portid of the schizo that this card
+ * lives under.
+ */
+ portid = -1;
+ value = get_prop_val(find_prop(pci_instance, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+ pci_card->schizo_portid = portid;
+ if (pci_card->schizo_portid != 8) {
+ /*
+ * Schizo0 (portid 8) has no slots on Cherrystone.
+ * So if that's who we're looking at, we're done.
+ */
+ return;
+ }
+
+ /*
+ * Find out whether this is PCI bus A or B
+ * using the 'reg' property.
+ */
+ int_val = (int *)get_prop_val(find_prop(pci_instance, "reg"));
+
+ if (int_val != NULL) {
+ int_val++; /* skip over first integer */
+ pci_bus = ((*int_val) & 0x7f0000);
+ if (pci_bus == 0x600000)
+ pci_card->pci_bus = 'A';
+ else if (pci_bus == 0x700000)
+ pci_card->pci_bus = 'B';
+ else {
+ assert(0); /* should never happen */
+ pci_card->pci_bus = '-';
+ }
+ } else {
+ assert(0); /* should never happen */
+ pci_card->pci_bus = '-';
+ }
+
+ /*
+ * get dev# and func# for this card from the
+ * 'reg' property.
+ */
+ int_val = (int *)get_prop_val(
+ find_prop(pci_card_node, "reg"));
+ if (int_val != NULL) {
+ pci_card->dev_no = (((*int_val) & 0xF800) >> 11);
+ pci_card->func_no = (((*int_val) & 0x700) >> 8);
+ } else {
+ pci_card->dev_no = -1;
+ pci_card->func_no = -1;
+ }
+
+ switch (pci_card->pci_bus) {
+ case 'A':
+ if ((pci_card->dev_no < 1 || pci_card->dev_no > 2) &&
+ (!pci_bridge)) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+ break;
+ case 'B':
+ if ((pci_card->dev_no < 2 || pci_card->dev_no > 5) &&
+ (!pci_bridge)) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+ break;
+ default:
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+
+ type = (char *)get_prop_val(
+ find_prop(pci_card_node, "device_type"));
+ /*
+ * If this is a pci-bridge, then store its dev#
+ * as its children nodes need this to get their slot#.
+ * We set the pci_bridge flag so that we know we are
+ * looking at a pci-bridge node. This flag gets reset
+ * every time we enter this while loop.
+ */
+
+ /*
+ * Check for a PCI-PCI Bridge for PCI and cPCI
+ * IO Boards using the name and type properties.
+ */
+ if ((type != NULL) && (strncmp(name, "pci", 3) == 0) &&
+ (strcmp(type, "pci") == 0)) {
+ pci_bridge_node = pci_card_node;
+ is_pci = TRUE;
+ if (!pci_bridge) {
+ pci_bridge_dev_no = pci_card->dev_no;
+ pci_parent_bridge = pci_bridge_node;
+ pci_bridge = TRUE;
+ }
+ }
+
+ /*
+ * Get slot-names property from slot_names_arr.
+ * If we are the child of a pci_bridge we use the
+ * dev# of the pci_bridge as an index to get
+ * the slot number. We know that we are a child of
+ * a pci-bridge if our parent is the same as the last
+ * pci_bridge node found above.
+ */
+ if (pci_card->dev_no != -1) {
+ /*
+ * We compare this cards parent node with the
+ * pci_bridge_node to see if it's a child.
+ */
+ if (pci_card_node->parent != pci_instance &&
+ pci_bridge) {
+ /* use dev_no of pci_bridge */
+ if (pci_card->pci_bus == 'B') {
+ slot_name =
+ slot_name_arr[pci_bridge_dev_no -2];
+ } else {
+ slot_name =
+ slot_name_arr[pci_bridge_dev_no -1];
+ }
+ } else {
+ if (pci_card->pci_bus == 'B') {
+ slot_name =
+ slot_name_arr[pci_card->dev_no-2];
+ } else {
+ slot_name =
+ slot_name_arr[pci_card->dev_no-1];
+ }
+ }
+
+ if (slot_name != NULL &&
+ strlen(slot_name) != 0) {
+ /* Slot num is last char in string */
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "%c", slot_name[strlen(slot_name) - 1]);
+ } else {
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "-");
+ }
+
+ } else {
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "%c", '-');
+ }
+
+ /*
+ * Check for failed status.
+ */
+ if (node_failed(pci_card_node))
+ strcpy(pci_card->status, "fail");
+ else
+ strcpy(pci_card->status, "ok");
+
+ /* Get the model of this pci_card */
+ value = get_prop_val(find_prop(pci_card_node, "model"));
+ if (value == NULL)
+ pci_card->model[0] = '\0';
+ else {
+ (void) snprintf(pci_card->model, MAXSTRLEN, "%s",
+ (char *)value);
+ }
+ /*
+ * The card may have a "clock-frequency" but we
+ * are not interested in that. Instead we get the
+ * "clock-frequency" of the PCI Bus that the card
+ * resides on. PCI-A can operate at 33Mhz or 66Mhz
+ * depending on what card is plugged into the Bus.
+ * PCI-B always operates at 33Mhz.
+ */
+ int_val = get_prop_val(find_prop(pci_instance,
+ "clock-frequency"));
+ if (int_val != NULL) {
+ pci_card->freq = HZ_TO_MHZ(*int_val);
+ } else {
+ pci_card->freq = -1;
+ }
+
+ /*
+ * Figure out how we want to display the name
+ */
+ value = get_prop_val(find_prop(pci_card_node,
+ "compatible"));
+ if (value != NULL) {
+ /* use 'name'-'compatible' */
+ (void) snprintf(buf, MAXSTRLEN, "%s-%s", name,
+ (char *)value);
+ } else {
+ /* just use 'name' */
+ (void) snprintf(buf, MAXSTRLEN, "%s", name);
+ }
+ name = buf;
+
+ /*
+ * If this node has children, add the device_type
+ * of the child to the name value of this pci_card->
+ */
+ child_name = (char *)get_node_name(pci_card_node->child);
+ if ((pci_card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(pci_card_node->child,
+ "device_type"));
+ if (value != NULL) {
+ /* add device_type of child to name */
+ (void) snprintf(pci_card->name, MAXSTRLEN,
+ "%s/%s (%s)", name, child_name,
+ (char *)value);
+ } else {
+ /* just add childs name */
+ (void) snprintf(pci_card->name, MAXSTRLEN,
+ "%s/%s", name, child_name);
+ }
+ } else {
+ (void) snprintf(pci_card->name, MAXSTRLEN, "%s",
+ (char *)name);
+ }
+
+ /*
+ * If this is a pci-bridge, then add the word
+ * 'pci-bridge' to its model. If we can't find
+ * a model, then we just describe what the device
+ * is based on some properties.
+ */
+ if (pci_bridge) {
+ if (strlen(pci_card->model) == 0) {
+ if (pci_card_node->parent == pci_bridge_node)
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "device on pci-bridge");
+ else if (pci_card_node->parent
+ == pci_parent_bridge)
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "pci-bridge/pci-bridge");
+ else
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "PCI-BRIDGE");
+ }
+ else
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s/pci-bridge", pci_card->model);
+ }
+ /* insert this pci_card in the list to be displayed later */
+
+ *pci_card_list = insert_io_card(*pci_card_list, pci_card);
+
+ /*
+ * If we are dealing with a pci-bridge, we need to move
+ * down to the children of this bridge if there are any.
+ *
+ * If we are not, we are either dealing with a regular
+ * card (in which case we move onto the sibling of this
+ * card) or we are dealing with a child of a pci-bridge
+ * (in which case we move onto the child's siblings or
+ * if there are no more siblings for this child, we
+ * move onto the parents siblings).
+ */
+ pci_card_node = next_pci_card(pci_card_node, &pci_bridge,
+ is_pci, pci_bridge_node,
+ pci_parent_bridge, pci_instance);
+ } /* end-while */
+}
+
+/*
+ * Helper function for fill_pci_card_list(). Indicates which
+ * card node to go to next.
+ * Parameters:
+ * -----------
+ * Prom_node * curr_card: pointer to the current card node
+ *
+ * int * is_bridge: indicates whether or not the card (is | is on)
+ * a pci bridge
+ *
+ * int is_pcidev: indicates whether or not the current card
+ * is a pci bridge
+ *
+ * Prom_node * curr_bridge: pointer to the current pci bridge. Eg:
+ * curr_card->parent.
+ *
+ * Prom_node * parent_bridge: pointer to the first pci bridge encountered.
+ * we could have nested pci bridges, this would
+ * be the first one.
+ *
+ * Prom_node * pci: pointer to the pci instance that we are attached to.
+ * This would be parent_bridge->parent, or
+ * curr_node->parent, if curr_node is not on a pci bridge.
+ */
+static Prom_node *
+next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev,
+ Prom_node *curr_bridge, Prom_node *parent_bridge,
+ Prom_node *pci)
+{
+ Prom_node * curr_node = curr_card;
+ if (*is_bridge) {
+ /*
+ * is_pcidev is used to prevent us from following the
+ * children of something like a scsi device.
+ */
+ if (curr_node->child != NULL && is_pcidev) {
+ curr_node = curr_node->child;
+ } else {
+ curr_node = curr_node->sibling;
+ if (curr_node == NULL) {
+ curr_node = curr_bridge->sibling;
+ while (curr_node == NULL &&
+ curr_bridge != parent_bridge &&
+ curr_bridge != NULL) {
+ curr_node =
+ curr_bridge->parent->sibling;
+ curr_bridge = curr_bridge->parent;
+ if (curr_node != NULL &&
+ curr_node->parent == pci)
+ break;
+ }
+ if (curr_bridge == NULL ||
+ curr_node == NULL ||
+ curr_node->parent == pci ||
+ curr_bridge == parent_bridge ||
+ curr_node == parent_bridge) {
+ *is_bridge = FALSE;
+ }
+ }
+ }
+
+ } else {
+ curr_node = curr_node->sibling;
+ }
+ return (curr_node);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/daktari/Makefile b/usr/src/lib/libprtdiag_psr/sparc/daktari/Makefile
new file mode 100644
index 0000000000..af6d11db23
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/daktari/Makefile
@@ -0,0 +1,101 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/daktari/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= daktari.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+IFLAGS += -I $(SRC)/cmd/picl/plugins/sun4u/psvc/psvcobj
+
+LDLIBS += -lpicl
+LINTFLAGS += $(IFLAGS)
+
+#
+# links in /usr/platform
+#
+LINKED_PLATFORMS = SUNW,Sun-Fire-V890
+
+LINKED_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%)
+LINKED_LIB_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib)
+LINKED_PRTDIAG_DIRS = \
+ $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/libprtdiag_psr.so.1)
+
+
+PLATFORM=SUNW,Sun-Fire-880
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS) $(LINKED_PRTDIAG_DIRS)
+
+#
+# install rules
+#
+
+$(PLATLIBS):
+ $(INS.dir)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/daktari; pwd ; $(MAKE) $(USR_PSM_LIB_DIR)
+
+$(LINKED_DIRS): $(USR_PLAT_DIR)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIB_DIRS): $(LINKED_DIRS)
+ -$(INS.dir.root.sys)
+
+$(LINKED_PRTDIAG_DIRS): $(USR_PLAT_DIR)
+ -$(INS.slink6)
+
+#
+# used for message files
+#
+POFILE= libprtdiag_psr_daktari.po
+POFILES= daktari.po
+
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/daktari.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/daktari/common/daktari.c b/usr/src/lib/libprtdiag_psr/sparc/daktari/common/daktari.c
new file mode 100644
index 0000000000..4139eec282
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/daktari/common/daktari.c
@@ -0,0 +1,1346 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Daktari Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_DAKTARI
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <note.h>
+
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+#include <sys/daktari.h>
+
+#include <pdevinfo.h>
+#include <display.h>
+#include <pdevinfo_sun4u.h>
+#include <display_sun4u.h>
+#include <libprtdiag.h>
+
+#include <picl.h>
+#include "workfile.c"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+#define DAK_MAX_SLOTS_PER_IO_BD 9
+#define DAK_MAX_DISKS 12
+#define DAK_MAX_FSP_LEDS 2
+#define DAK_MAX_PS 3
+#define DAK_MAX_PS_VOLTAGE_SENSORS 4
+#define DAK_MAX_PS_FAULT_SENSORS 3
+#define DAK_MAX_FANS 10
+#ifndef SCHIZO_COMPAT_PROP
+#define SCHIZO_COMPAT_PROP "pci108e,8001"
+#endif
+
+#define MULTIPLE_BITS_SET(x) ((x)&((x)-1))
+
+extern int print_flag;
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (workgroup server systems only)
+ */
+void display_cpu_devices(Sys_tree *tree);
+void display_cpus(Board_node *board);
+void display_pci(Board_node *board);
+void display_io_cards(struct io_card *list);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_ffb(Board_node *board, int table);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+
+/* local functions */
+static int disp_envc_status(void);
+static int dak_env_print_temps(picl_nodehdl_t);
+static int dak_env_print_keyswitch(picl_nodehdl_t);
+static int dak_env_print_FSP_LEDS(picl_nodehdl_t);
+static int dak_env_print_disk(picl_nodehdl_t);
+static int dak_env_print_fans(picl_nodehdl_t);
+static int dak_env_print_ps(picl_nodehdl_t);
+
+static void dak_display_hw_revisions(Prom_node *root,
+ Board_node *bnode);
+static void display_schizo_revisions(Board_node *bdlist);
+
+
+/*
+ * Defining the error_check function in order to return the
+ * appropriate error code.
+ */
+/*ARGSUSED0*/
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ int exit_code = 0; /* init to all OK */
+ /*
+ * silently check for any types of machine errors
+ */
+ print_flag = 0;
+ if (disp_fail_parts(tree)) {
+ /* set exit_code to show failures */
+ exit_code = 1;
+ }
+ print_flag = 1;
+
+ return (exit_code);
+}
+
+/*
+ * disp_fail_parts
+ *
+ * Display the failed parts in the system. This function looks for
+ * the status property in all PROM nodes. On systems where
+ * the PROM does not support passing diagnostic information
+ * through the device tree, this routine will be silent.
+ */
+int
+disp_fail_parts(Sys_tree *tree)
+{
+ int exit_code = 0;
+ int system_failed = 0;
+ Board_node *bnode = tree->bd_list;
+ Prom_node *pnode;
+
+ /* go through all of the boards looking for failed units. */
+ while (bnode != NULL) {
+ /* find failed chips */
+ pnode = find_failed_node(bnode->nodes);
+ if ((pnode != NULL) && !system_failed) {
+ system_failed = 1;
+ exit_code = 1;
+ if (print_flag == 0) {
+ return (exit_code);
+ }
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
+ "Replaceable Units (FRU) in System:\n"));
+ log_printf("=========================="
+ "====================\n");
+ }
+ while (pnode != NULL) {
+ void *value;
+ char *name; /* node name string */
+ char *type; /* node type string */
+ char *board_type = NULL;
+
+ value = get_prop_val(find_prop(pnode, "status"));
+ name = get_node_name(pnode);
+
+ /* sanity check of data retrieved from PROM */
+ if ((value == NULL) || (name == NULL)) {
+ pnode = next_failed_node(pnode);
+ continue;
+ }
+
+ /* Find the board type of this board */
+ if (bnode->board_type == CPU_BOARD) {
+ board_type = "CPU";
+ } else {
+ board_type = "IO";
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "%s unavailable "
+ "on %s Board #%d\n"), name, board_type,
+ bnode->board_num);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tPROM fault string: %s\n"), value);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tFailed Field Replaceable Unit is "));
+
+ /*
+ * Determine whether FRU is CPU module, system
+ * board, or SBus card.
+ */
+ if ((name != NULL) && (strstr(name, "sbus"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "SBus Card %d\n"),
+ get_sbus_slot(pnode));
+
+ } else if (((name = get_node_name(pnode->parent)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "PCI Card %d"),
+ get_pci_device(pnode));
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "cpu"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN, "UltraSPARC "
+ "module Board %d Module %d\n"), 0,
+ get_id(pnode));
+
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%s board %d\n"), board_type,
+ bnode->board_num);
+ }
+ pnode = next_failed_node(pnode);
+ }
+ bnode = bnode->next;
+ }
+
+ if (!system_failed) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "No failures found in System\n"));
+ log_printf("===========================\n\n");
+ }
+
+ if (system_failed)
+ return (1);
+ else
+ return (0);
+}
+
+/*ARGSUSED*/
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ /* Display failed units */
+ (void) disp_fail_parts(tree);
+}
+
+/*ARGSUSED*/
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode = tree->bd_list;
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "========================= Memory Configuration"
+ " ===============================\n"
+ "\n Logical Logical"
+ " Logical "
+ "\n MC Bank Bank Bank"
+ " DIMM Interleave Interleaved"
+ "\n Brd ID num size "
+ "Status Size "
+ "Factor with"
+ "\n---- --- ---- ------ "
+ "----------- ------ "
+ "---------- -----------"));
+
+ while (bnode != NULL) {
+ if (get_us3_mem_regs(bnode)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nFailed to get memory information.\n"));
+ return;
+ }
+ bnode = bnode->next;
+ }
+
+ /* Display what we have found */
+ display_us3_banks();
+}
+
+void
+display_cpu_devices(Sys_tree *tree)
+{
+ Board_node *bnode;
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision of all cpus.
+ */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "========================="
+ " CPUs "
+ "==============================================="
+ "\n"
+ "\n"
+ " Run E$ CPU CPU \n"
+ "Brd CPU MHz MB Impl. Mask \n"
+ "--- ----- ---- ---- ------- ---- \n"));
+
+ /* Now display all of the cpus on each board */
+ bnode = tree->bd_list;
+ if (bnode == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "CPU Board list was NULL\n"));
+ }
+ while (bnode != NULL) {
+ display_cpus(bnode);
+ bnode = bnode->next;
+ }
+
+ log_printf("\n");
+}
+
+/*
+ * Display the CPUs present on this board.
+ */
+void
+display_cpus(Board_node *board)
+{
+ Prom_node *cpu;
+ int freq; /* CPU clock frequency */
+ int ecache_size; /* External cache size */
+ int *l3_shares;
+ int *mid;
+ int *impl;
+ int *mask;
+ int *coreid;
+ char fru_prev = 'X'; /* Valid frus are 'A','B','C','D' */
+ int mid_prev;
+ int ecache_size_prev = 0;
+ char fru_name;
+
+ /*
+ * display the CPUs' operating frequency, cache size, impl. field
+ * and mask revision.
+ */
+ for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
+ cpu = dev_next_type(cpu, "cpu")) {
+
+ mid = (int *)get_prop_val(find_prop(cpu, "portid"));
+ if (mid == NULL)
+ mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
+ freq = DAK_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
+ ecache_size = get_ecache_size(cpu);
+ impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
+ mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
+ l3_shares =
+ (int *)get_prop_val(find_prop(cpu, "l3-cache-sharing"));
+
+ /* Do not display a failed CPU node */
+ if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
+ continue;
+
+ /* Board number */
+ fru_name = (char)('A' + DAK_GETSLOT(*mid));
+
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ coreid = (int *)get_prop_val(find_prop(cpu, "reg"));
+ if (coreid == NULL) {
+ continue;
+ }
+ if ((fru_prev == 'X') ||
+ ((fru_prev != 'X') &&
+ (fru_name != fru_prev))) {
+ fru_prev = fru_name;
+ mid_prev = *mid;
+ ecache_size_prev = ecache_size;
+ continue;
+ } else {
+ /*
+ * Some CMP chips have a split E$,
+ * so the size for both cores is added
+ * together to get the total size for
+ * the chip.
+ *
+ * Still, other CMP chips have E$ (L3)
+ * which is logically shared, so the
+ * total size is equal to the core size.
+ */
+ if ((l3_shares == NULL) ||
+ ((l3_shares != NULL) &&
+ MULTIPLE_BITS_SET(*l3_shares))) {
+ ecache_size += ecache_size_prev;
+ }
+ ecache_size_prev = 0;
+ fru_prev = 'X';
+ }
+ }
+
+ log_printf("%2c", fru_name);
+
+ /* CPU Module ID */
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ log_printf("%3d,%3d", mid_prev, *mid, 0);
+ } else
+ log_printf(" %d ", *mid);
+
+ /* Running frequency */
+ log_printf(" %4d ", freq);
+
+ /* Ecache size */
+ if (ecache_size == 0)
+ log_printf(dgettext(TEXT_DOMAIN, "%3s "),
+ "N/A");
+ else
+ log_printf("%4.1f ",
+ (float)ecache_size / (float)(1<<20));
+
+ /* Implementation */
+ if (impl == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, "%s "),
+ "N/A");
+ } else {
+ if (IS_CHEETAH(*impl))
+ log_printf("%7s", "US-III ", 0);
+ else if (IS_CHEETAH_PLUS(*impl))
+ log_printf("%7s", "US-III+", 0);
+ else if (IS_JAGUAR(*impl))
+ log_printf("%7s", "US-IV ", 0);
+ else if (IS_PANTHER(*impl))
+ log_printf("%7s", "US-IV+ ", 0);
+ else
+ log_printf("%-7x", *impl, 0);
+ }
+
+ /* CPU Mask */
+ if (mask == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, " %3s "),
+ "N/A");
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN, " %2d.%d"),
+ (*mask >> 4) & 0xf, *mask & 0xf);
+ }
+
+ log_printf("\n");
+ }
+}
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+void
+display_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+ Prom_node *pci;
+ Prom_node *card_node;
+ char *slot_name_arr[DAK_MAX_SLOTS_PER_IO_BD] = {NULL};
+ int i;
+#ifdef DEBUG
+ int slot_name_bits;
+#endif
+
+ if (board == NULL)
+ return;
+
+ memset(&card, 0, sizeof (struct io_card));
+ /* Initialize all the common information */
+ card.display = TRUE;
+ card.board = board->board_num;
+
+ /*
+ * Search for each pci instance, then find/display all nodes under
+ * each instance node found.
+ */
+ for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
+ pci != NULL;
+ pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
+ (void) snprintf(card.bus_type, MAXSTRLEN,
+ dgettext(TEXT_DOMAIN, "PCI"));
+ /*
+ * Get slot-name properties from parent node and
+ * store them in an array.
+ */
+ value = (char *)get_prop_val(
+ find_prop(pci, "slot-names"));
+
+ if (value != NULL) {
+#ifdef DEBUG
+ /* save the 4 byte bitmask */
+ slot_name_bits = *(int *)value;
+#endif
+
+ /* array starts after first int */
+ slot_name_arr[0] = (char *)value + sizeof (int);
+ for (i = 1; i < DAK_MAX_SLOTS_PER_IO_BD; i++) {
+ slot_name_arr[i] = (char *)slot_name_arr[i - 1]
+ + strlen(slot_name_arr[i - 1]) +1;
+ }
+ }
+ /*
+ * Search for Children of this node ie. Cards.
+ * Note: any of these cards can be a pci-bridge
+ * that itself has children. If we find a
+ * pci-bridge we need to handle it specially.
+ */
+ card_node = pci->child;
+ /* Generate the list of pci cards on pci instance: pci */
+ fill_pci_card_list(pci, card_node, &card, &card_list,
+ slot_name_arr);
+ } /* end-for */
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+ log_printf("\n");
+}
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == FALSE) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ " Bus Max\n"
+ " IO Port Bus Freq Bus Dev,"
+ "\n"
+ "Brd Type ID Side Slot MHz Freq "
+ "Func State Name "
+ "Model\n"
+ /* ---------Brd IO Port Bus Slot Bus Max Dev Stat */
+ "---- ---- ---- ---- ---- ---- ---- ----"
+ " ----- "
+ "-------------------------------- "
+ "----------------------\n"));
+ banner = TRUE;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf(dgettext(TEXT_DOMAIN, "I/O "));
+ log_printf("%-4s ", p->bus_type);
+ log_printf("%-3d ", p->schizo_portid);
+ log_printf("%c ", p->pci_bus);
+ log_printf("%-1s ", p->slot_str);
+ log_printf("%-3d ", p->freq);
+ switch (p->pci_bus) {
+ case 'A':
+ log_printf(dgettext(TEXT_DOMAIN, " 66 "));
+ break;
+ case 'B':
+ log_printf(dgettext(TEXT_DOMAIN, " 33 "));
+ break;
+ default:
+ log_printf(dgettext(TEXT_DOMAIN, " - "));
+ break;
+ }
+
+ log_printf("%-1d,%-1d ", p->dev_no, p->func_no);
+ log_printf("%-5s ", p->status);
+ log_printf("%-32.32s", p->name);
+ if (strlen(p->name) > 32)
+ log_printf(dgettext(TEXT_DOMAIN, "+ "));
+ else
+ log_printf(dgettext(TEXT_DOMAIN, " "));
+ log_printf("%-22.22s", p->model);
+ if (strlen(p->model) > 22)
+ log_printf(dgettext(TEXT_DOMAIN, "+"));
+
+#ifdef DEBUG
+ log_printf(dgettext(TEXT_DOMAIN, "%s "), p->notes);
+#endif
+ log_printf("\n");
+ }
+}
+
+/*
+ * display_ffb
+ *
+ * There are no FFB's on a Daktari, however in the generic library,
+ * the display_ffb() function is implemented so we have to define an
+ * empty function here.
+ */
+/* ARGSUSED */
+void
+display_ffb(Board_node *board, int table)
+{}
+
+
+/*
+ * ----------------------------------------------------------------------------
+ */
+
+/* ARGSUSED */
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ /* NOTE(ARGUNUSED(kstats)) */
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is if the user
+ * told us to do logging, and we found a system failure.
+ */
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ (void) disp_envc_status();
+
+ /* platform_disp_prom_version(tree); */
+ dak_display_hw_revisions(root, tree->bd_list);
+ }
+}
+
+/*
+ * local functions
+ */
+
+/*
+ * disp_envc_status
+ *
+ * This routine displays the environmental status passed up from
+ * device drivers via the envlibobj.so library.
+ * This is a Daktari specific environmental information display routine.
+ */
+int
+disp_envc_status()
+{
+ int err;
+ char *system = "SYSTEM";
+ picl_nodehdl_t system_node, root;
+
+ err = picl_initialize();
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_initialize failed\n"
+ "%s\nCannot display environmental status\n"),
+ picl_strerror(err));
+ return (err);
+ }
+ err = picl_get_root(&root);
+ err = find_child_device(root, system, &system_node);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_node_by_path for the SYSTEM node "
+ "failed\n"
+ "%s\nCannot display environmental status\n"),
+ picl_strerror(err));
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "========================= "
+ "Environmental Status "
+ "========================="
+ "\n"
+ "\n"));
+
+ dak_env_print_temps(system_node);
+ dak_env_print_keyswitch(system_node);
+ dak_env_print_FSP_LEDS(system_node);
+ dak_env_print_disk(system_node);
+ dak_env_print_fans(system_node);
+ dak_env_print_ps(system_node);
+
+ (void) picl_shutdown();
+ return (0);
+}
+
+int
+dak_env_print_ps(picl_nodehdl_t system_node)
+{
+ int i, r, fail, err = 0;
+ int32_t number;
+ char name[PICL_PROPNAMELEN_MAX];
+ picl_nodehdl_t *ps;
+ picl_nodehdl_t *ps_fail[DAK_MAX_PS_FAULT_SENSORS];
+ picl_nodehdl_t *ps_I_sensor[DAK_MAX_PS_VOLTAGE_SENSORS];
+ int32_t volts[DAK_MAX_PS_VOLTAGE_SENSORS];
+ char fault_state
+ [DAK_MAX_PS_FAULT_SENSORS][PICL_PROPNAMELEN_MAX];
+ char ps_state[PICL_PROPNAMELEN_MAX];
+ /* Printing out the Power Supply Heading information */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Power Supplies:\n"
+ "---------------\n"
+ " "
+ "Current Drain:\n"
+ "Supply Status Fan Fail Temp Fail CS Fail "
+ "3.3V 5V 12V 48V\n"
+ "------ ------------ -------- --------- "
+ "------- ---- -- --- ---\n"));
+
+ err = fill_device_array_from_id(system_node, "PSVC_PS", &number,
+ &ps);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_array_from_id for PS\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ /* Printing out the Power Supply Status information */
+ for (i = 0; i < DAK_MAX_PS; i++) {
+ /*
+ * Re initialize the fail variable so that if
+ * one power supply fails, they don't all do also.
+ */
+ fail = 0;
+
+ err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ continue;
+ }
+ err = picl_get_propval_by_name(ps[i], "State", ps_state,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Error getting ps[%d]'s state: %s"),
+ i, picl_strerror(err));
+ }
+
+ err = fill_device_array_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
+ &number, &ps_fail[i]);
+
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed to get present PS fault sensors\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ err = fill_device_array_from_id(ps[i], "PSVC_PS_I_SENSOR",
+ &number, &ps_I_sensor[i]);
+
+ if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed to get present PS I sensors\n"
+ "%s\n"), picl_strerror(err));
+ }
+
+ log_printf("%s", name);
+
+ /*
+ * If the AC cord is unplugged, then the power supply
+ * sensors will have unreliable values. In this case,
+ * skip to the next power supply.
+ */
+ if (strcmp(ps_state, "HOTPLUGGED") == 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ " UNPLUGGED\n"));
+ continue;
+ }
+
+ for (r = 0; r < DAK_MAX_PS_FAULT_SENSORS; r++) {
+ err = picl_get_propval_by_name(ps_fail[i][r], "State",
+ fault_state[r], PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ fail =
+ strcmp(fault_state[r], "OFF")
+ + fail;
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for ps "
+ "fault state failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ }
+ for (r = 0; r < DAK_MAX_PS_VOLTAGE_SENSORS; r++) {
+ err = picl_get_propval_by_name(ps_I_sensor[i][r],
+ "AtoDSensorValue", &volts[r],
+ sizeof (int32_t));
+ }
+
+ if (fail != 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ " FAIL "));
+ for (r = 0; r < DAK_MAX_PS_FAULT_SENSORS; r++) {
+ log_printf(dgettext(TEXT_DOMAIN, " %-4s"),
+ fault_state[r]);
+ }
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN, " GOOD "));
+ for (r = 0; r < DAK_MAX_PS_FAULT_SENSORS; r++) {
+ log_printf(dgettext(TEXT_DOMAIN, " "));
+ }
+ }
+ for (r = 0; r < DAK_MAX_PS_VOLTAGE_SENSORS; r++) {
+ log_printf(dgettext(TEXT_DOMAIN, " %2d"), volts[r]);
+ }
+ log_printf("\n");
+ }
+ log_printf("\n");
+ return (err);
+}
+
+int
+dak_env_print_fans(picl_nodehdl_t system_node)
+{
+ int i, err = 0;
+ int32_t number, fan_speed;
+ picl_nodehdl_t *fans;
+ char name[PICL_PROPNAMELEN_MAX];
+ char enabled[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
+ &fans);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_array_from_id "
+ "for FAN\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "=================================\n"));
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Fan Bank :\n"));
+ log_printf(dgettext(TEXT_DOMAIN, "----------\n"));
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Bank Speed "
+ " Status Fan State\n"));
+ log_printf(dgettext(TEXT_DOMAIN, " ( RPMS )"
+ " \n"));
+ log_printf(dgettext(TEXT_DOMAIN, "---- --------"
+ " --------- ---------\n"));
+
+
+ for (i = 0; i < DAK_MAX_FANS; i++) {
+ char fan_state[PICL_PROPNAMELEN_MAX];
+ fan_speed = 0;
+ err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, "%16-s"), name);
+ } else {
+ continue;
+ }
+
+ err = picl_get_propval_by_name(fans[i], "Fan-speed",
+ &fan_speed, sizeof (int32_t));
+ if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in picl_get_propval_by_name for "
+ "fan speed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ if ((strcmp(name, "CPU0_PRIM_FAN") != 0) &&
+ (strcmp(name, "CPU1_PRIM_FAN") != 0)) {
+ err = picl_get_propval_by_name(fans[i], "Fan-switch",
+ enabled, PICL_PROPNAMELEN_MAX);
+ if ((err != PICL_SUCCESS) &&
+ (err != PICL_INVALIDHANDLE)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in picl_get_propval_by_name for"
+ " fan enabled/disabled\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ /*
+ * Display the fan's speed and whether or not
+ * it's enabled.
+ */
+ if (strcmp(enabled, "ON") == 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\t %4d [ENABLED]"),
+ fan_speed);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\t 0 [DISABLED]"));
+ }
+
+ } else {
+ /* Display the fan's speed */
+ log_printf(dgettext(TEXT_DOMAIN, "\t %4d"),
+ fan_speed);
+ log_printf(dgettext(TEXT_DOMAIN,
+ " [ENABLED]"));
+ }
+
+ err = picl_get_propval_by_name(fans[i], "State", fan_state,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name failed: %s"),
+ picl_strerror(err));
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, "\t %s\n"), fan_state);
+ }
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "=================================\n"));
+ log_printf("\n");
+
+ return (err);
+}
+
+int
+dak_env_print_disk(picl_nodehdl_t system_node)
+{
+ int i, err;
+ int32_t number;
+ picl_nodehdl_t *disks;
+ picl_nodehdl_t disk_slots[DAK_MAX_DISKS];
+ picl_nodehdl_t disk_fault_leds[DAK_MAX_DISKS];
+ picl_nodehdl_t disk_remove_leds[DAK_MAX_DISKS];
+ char led_state[PICL_PROPNAMELEN_MAX];
+ char name[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
+ &disks);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_array_from_id for "
+ "DISK\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Disk Status:\n"
+ " Presence Fault LED Remove LED\n"));
+
+ for (i = 0; i < DAK_MAX_DISKS; i++) {
+ err = picl_get_propval_by_name(disks[i], PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+ switch (err) {
+ case PICL_SUCCESS:
+ log_printf(dgettext(TEXT_DOMAIN, "DISK %2d: [%7s]"),
+ i, "PRESENT");
+ break;
+ case PICL_INVALIDHANDLE:
+ log_printf(dgettext(TEXT_DOMAIN, "DISK %2d: [%7s]"),
+ i, "EMPTY");
+ log_printf("\n");
+ continue;
+ default:
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed picl_get_propval_by_name for "
+ "disk %d with %s\n"), i, picl_strerror(err));
+ return (err);
+ }
+
+ err = fill_device_from_id(disks[i], "PSVC_PARENT",
+ &(disk_slots[i]));
+ switch (err) {
+ case PICL_SUCCESS:
+ break;
+ case PICL_INVALIDHANDLE:
+ continue;
+ default:
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_from_id for disk "
+ "slot\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ err = fill_device_from_id(disk_slots[i], "PSVC_SLOT_FAULT_LED",
+ &disk_fault_leds[i]);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_from_id for disk slot "
+ "fault led\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ err = picl_get_propval_by_name(disk_fault_leds[i],
+ "State", led_state, PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, " [%3s]"),
+ led_state);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for fault led_state"
+ " failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ err = fill_device_from_id(disk_slots[i], "PSVC_SLOT_REMOVE_LED",
+ &disk_remove_leds[i]);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_from_id for disk slot "
+ "remove led\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(disk_remove_leds[i],
+ "State", led_state, PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ " [%3s]"), led_state);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for remove"
+ " led_state failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ log_printf("\n");
+ }
+ return (err);
+}
+
+int
+dak_env_print_FSP_LEDS(picl_nodehdl_t system_node)
+{
+ int i, err = 0;
+ int32_t number;
+ picl_nodehdl_t *fsp_leds;
+ char led_state[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
+ &fsp_leds);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_array_from_id for "
+ "FSP_LED\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System LED Status:\n"
+ " GEN FAULT REMOVE\n"));
+ for (i = 0; i < DAK_MAX_FSP_LEDS; i++) {
+ err = picl_get_propval_by_name(fsp_leds[i], "State",
+ led_state, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for led_state"
+ " failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ " [%3s]"), led_state);
+ }
+ log_printf("\n\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ " DISK FAULT "));
+ log_printf(dgettext(TEXT_DOMAIN, "POWER FAULT\n"));
+ for (i = 2; i < 4; i++) {
+ err = picl_get_propval_by_name(fsp_leds[i], "State",
+ led_state, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for led_state"
+ " failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, " [%3s]"),
+ led_state);
+ }
+ log_printf("\n\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ " LEFT THERMAL FAULT "
+ "RIGHT THERMAL FAULT\n"));
+ for (i = 4; i < 6; i++) {
+ err = picl_get_propval_by_name(fsp_leds[i], "State",
+ led_state, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for led_state "
+ "failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, " [%3s]"),
+ led_state);
+ }
+ log_printf("\n\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ " LEFT DOOR "
+ "RIGHT DOOR\n"));
+ for (i = 6; i < 8; i++) {
+ err = picl_get_propval_by_name(fsp_leds[i], "State",
+ led_state, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for led_state"
+ " failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+ log_printf(dgettext(TEXT_DOMAIN, " [%3s]"),
+ led_state);
+ }
+ log_printf("\n\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "=================================\n"));
+ log_printf("\n");
+
+ return (err);
+}
+
+int
+dak_env_print_keyswitch(picl_nodehdl_t system_node)
+{
+ int err = 0;
+ picl_nodehdl_t *keyswitch;
+ int32_t number;
+ char ks_pos[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
+ &keyswitch);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed in fill_device_array_from_id for "
+ " PSVC_KEYSWITCH\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "picl_get_propval_by_name for keyswitch state "
+ "failed\n"
+ "%s\n"), picl_strerror(err));
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Front Status Panel:\n"
+ "-------------------\n"
+ "Keyswitch position: "
+ "%s\n"), ks_pos);
+ log_printf("\n");
+
+ return (err);
+}
+
+int
+dak_env_print_temps(picl_nodehdl_t system_node)
+{
+ int i;
+ int err;
+ picl_nodehdl_t *system_ts_nodes;
+ int32_t temp;
+ int32_t number;
+ char label[PICL_PROPNAMELEN_MAX];
+ char state[PICL_PROPNAMELEN_MAX];
+ char *p;
+
+ err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
+ &system_ts_nodes);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System Temperatures (Celsius):\n"
+ "-------------------------------\n"
+ "Device\t\tTemperature\tStatus\n"
+ "---------------------------------------\n"));
+
+ for (i = 0; i < number; i++) {
+ err = picl_get_propval_by_name(system_ts_nodes[i],
+ "State", state, sizeof (state));
+ if (err != PICL_SUCCESS) {
+ if (err == PICL_INVALIDHANDLE) {
+ strcpy(state, "n/a");
+ } else {
+ log_printf("%s\n", picl_strerror(err));
+ return (err);
+ }
+ }
+ err = picl_get_propval_by_name(system_ts_nodes[i],
+ PICL_PROP_NAME, label, PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ if (err == PICL_INVALIDHANDLE)
+ /* This FRU isn't present. Skip it. */
+ continue;
+ log_printf("%s\n", picl_strerror(err));
+ return (err);
+ }
+
+ /*
+ * The names in the tree are like "CPU0_DIE_TEMPERATURE_SENSOR".
+ * All we want to print is up to the first underscore.
+ */
+ p = strchr(label, '_');
+ if (p != NULL)
+ *p = '\0';
+
+ err = picl_get_propval_by_name(system_ts_nodes[i],
+ "Temperature", &temp, sizeof (temp));
+ if (err != PICL_SUCCESS) {
+ log_printf("%s\n", picl_strerror(err));
+ return (err);
+ }
+ log_printf("%s\t\t%3d\t\t%s\n", label, temp, state);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n=================================\n\n"));
+
+ return (PICL_SUCCESS);
+}
+
+static void
+dak_display_hw_revisions(Prom_node *root, Board_node *bdlist)
+{
+ Prom_node *pnode;
+ char *value;
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n"
+ "========================= HW Revisions "
+ "=======================================\n\n"));
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System PROM revisions:\n"
+ "----------------------\n"));
+
+ pnode = dev_find_node(root, "openprom");
+ if (pnode != NULL) {
+ value = (char *)get_prop_val(find_prop(pnode, "version"));
+ log_printf(value);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n\n"
+ "IO ASIC revisions:\n"
+ "------------------\n"
+ " Port\n"
+ "Model ID Status Version\n"
+ "-------- ---- ------ -------\n"));
+
+ display_schizo_revisions(bdlist);
+}
+
+static void
+display_schizo_revisions(Board_node *bdlist)
+{
+ Prom_node *pnode;
+ int *int_val;
+ int portid;
+ int prev_portid = -1;
+ char *status_a = NULL;
+ char *status_b = NULL;
+ int revision;
+#ifdef DEBUG
+ uint32_t a_notes, b_notes;
+#endif
+ int pci_bus;
+ Board_node *bnode;
+ bnode = bdlist;
+
+ while (bnode != NULL) {
+ /*
+ * search this board node for all Schizos
+ */
+ for (pnode = dev_find_node_by_compat(bnode->nodes,
+ SCHIZO_COMPAT_PROP); pnode != NULL;
+ pnode = dev_next_node_by_compat(pnode,
+ SCHIZO_COMPAT_PROP)) {
+
+ /*
+ * get the reg property to determine
+ * whether we are looking at side A or B
+ */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "reg"));
+ if (int_val != NULL) {
+ int_val ++; /* second integer in array */
+ pci_bus = ((*int_val) & 0x7f0000);
+ }
+
+ /* get portid */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "portid"));
+ if (int_val == NULL)
+ continue;
+
+ portid = *int_val;
+
+ /*
+ * If this is a new portid and it is PCI bus B,
+ * we skip onto the PCI bus A.
+ */
+ if ((portid != prev_portid) && (pci_bus == 0x700000)) {
+ prev_portid = portid;
+ /* status */
+ status_b = (char *)get_prop_val
+ (find_prop(pnode, "status"));
+#ifdef DEBUG
+ b_notes = pci_bus;
+#endif
+ continue; /* skip to the next schizo */
+ }
+
+ /*
+ * This must be side A of the same Schizo.
+ * Gather all its props and display them.
+ */
+#ifdef DEBUG
+ a_notes = pci_bus;
+#endif
+
+ prev_portid = portid;
+
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "version#"));
+ if (int_val != NULL)
+ revision = *int_val;
+ else
+ revision = -1;
+
+ status_a = (char *)get_prop_val(find_prop
+ (pnode, "status"));
+
+ log_printf(dgettext(TEXT_DOMAIN, "Schizo "));
+
+ log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
+
+
+ log_printf((status_a == NULL && status_b == NULL) ?
+ dgettext(TEXT_DOMAIN, " ok ") :
+ dgettext(TEXT_DOMAIN, " fail "));
+
+ log_printf(dgettext(TEXT_DOMAIN, " %4d "),
+ revision);
+#ifdef DEBUG
+ log_printf(" 0x%x 0x%x", a_notes, b_notes);
+#endif
+ log_printf("\n");
+ }
+ bnode = bnode->next;
+ }
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/daktari/common/workfile.c b/usr/src/lib/libprtdiag_psr/sparc/daktari/common/workfile.c
new file mode 100644
index 0000000000..33ffdfb1da
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/daktari/common/workfile.c
@@ -0,0 +1,939 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000, 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Daktari Platform specific functions.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libdevinfo.h>
+#include <alloca.h>
+#include <inttypes.h>
+#include <libprtdiag.h>
+#include <sys/mc.h>
+
+#define EXIT_MSG(msg, err) \
+ { printf("\n%s failed with %d\n", msg, err); exit(err); }
+
+/* we only need the 5 LSB of the portid to calculate the board number */
+#define DAK_SAFARI_ID_MASK 0x1F /* 5 bits */
+#define DAK_NODE_MASK 0x1F /* 5 bits */
+#define DAK_PORTID_NODE_SHIFT 5
+#define DAK_MIN_CPU_SAFARI_ID 0 /* 0x00 */
+#define DAK_MAX_CPU_SAFARI_ID 23 /* 0x17 */
+#define DAK_MIN_IO_SAFARI_ID 24 /* 0x18 */
+#define DAK_MAX_IO_SAFARI_ID 31 /* 0x1F */
+#define NUM_MBANKS_PER_MC 4
+
+#define DAK_CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000)
+
+/*
+ * DAK_PORTID_IS_CPU_TYPE
+ *
+ * If the portid associated with a CPU board is passed in, TRUE is returned,
+ * otherwise FALSE.
+ */
+#define DAK_PORTID_IS_CPU_TYPE(portid) \
+ (((((portid) & DAK_SAFARI_ID_MASK) >= DAK_MIN_CPU_SAFARI_ID) && \
+ (((portid) & DAK_SAFARI_ID_MASK) <= DAK_MAX_CPU_SAFARI_ID)) ? \
+ TRUE: FALSE)
+/*
+ * DAK_CPU_BD_PORTID_TO_BD_NUM
+ *
+ * If the portid associated with a CPU board is passed in, the board number
+ * associated with this portid is returned, otherwise -1.
+ */
+#define DAK_CPU_BD_PORTID_TO_BD_NUM(portid) \
+ ((DAK_PORTID_IS_CPU_TYPE(portid)) ? \
+ (((portid) & DAK_SAFARI_ID_MASK) / 4) : (-1))
+
+/*
+ * DAK_PORTID_IS_IO_TYPE
+ *
+ * If the portid associated with an IO board is passed in, TRUE is returned,
+ * otherwise FALSE.
+ */
+#define DAK_PORTID_IS_IO_TYPE(portid) \
+ (((((portid) & DAK_SAFARI_ID_MASK) >= DAK_MIN_IO_SAFARI_ID) && \
+ (((portid) & DAK_SAFARI_ID_MASK) <= DAK_MAX_IO_SAFARI_ID)) ? \
+ TRUE: FALSE)
+
+/*
+ * DAK_IO_BD_PORTID_TO_BD_NUM
+ *
+ * If the portid associated with an IO board is passed in, the board number
+ * associated with this portid is returned, otherwise -1.
+ */
+#define DAK_IO_BD_PORTID_TO_BD_NUM(portid) \
+ (DAK_PORTID_IS_IO_TYPE(portid) ? \
+ (((((portid) & DAK_SAFARI_ID_MASK) - 24) / 2) + 6) : (-1))
+
+/*
+ * DAK_PORTID_TO_BOARD_NUM
+ *
+ * If a valid portid is passed in, this macro returns the board number
+ * associated with it, otherwise it returns -1.
+ */
+
+#define DAK_PORTID_TO_BOARD_NUM(portid) \
+ ((DAK_PORTID_IS_CPU_TYPE(portid)) ? \
+ (DAK_CPU_BD_PORTID_TO_BD_NUM(portid)) : \
+ ((DAK_PORTID_IS_IO_TYPE(portid)) ? \
+ DAK_IO_BD_PORTID_TO_BD_NUM(portid) : (-1)))
+
+
+/* Local Functions */
+char *get_node_name(Prom_node *pnode);
+char *get_node_type(Prom_node *pnode);
+void add_node(Sys_tree *root, Prom_node *pnode);
+Prop *find_prop(Prom_node *pnode, char *name);
+int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
+void *get_prop_val(Prop *prop);
+char *get_node_type(Prom_node *pnode);
+int get_us3_mem_regs(Board_node *bnode);
+
+void fill_pci_card_list(Prom_node *pci_instance,
+ Prom_node *pci_card_node,
+ struct io_card *pci_card,
+ struct io_card **pci_card_list,
+ char **pci_slot_name_arr);
+
+static Prom_node *next_pci_card(Prom_node *curr_card, int *is_bridge,
+ int is_pcidev, Prom_node *curr_bridge,
+ Prom_node * parent_bridge, Prom_node *pci);
+
+static Prom_node *dev_next_node_by_compat(Prom_node *root, char *compat);
+static Prom_node *dev_find_node_by_compat(Prom_node *root, char *compat);
+static Board_node *daktari_insert_board(Sys_tree *root, int board);
+static Board_node *daktari_find_board(Sys_tree *root, int board);
+
+static int32_t find_child_device(picl_nodehdl_t, char *, picl_nodehdl_t *);
+static int32_t fill_device_from_id(picl_nodehdl_t, char *, picl_nodehdl_t *);
+static int32_t fill_device_array_from_id(picl_nodehdl_t, char *, int32_t *,
+ picl_nodehdl_t **);
+
+/* Overlaying routines */
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property.
+ */
+char *
+get_node_name(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("name", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property.
+ */
+char *
+get_node_type(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+/*
+ * add_node
+ *
+ * This function adds a board node to the board structure where that
+ * that node's physical component lives.
+ */
+void
+add_node(Sys_tree *root, Prom_node *pnode)
+{
+ int board = -1;
+ int portid = -1;
+
+ void *value = NULL;
+ Board_node *bnode = NULL;
+ Prom_node *p = NULL;
+
+ /* Get the board number of this board from the portid prop */
+ value = get_prop_val(find_prop(pnode, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+ board = DAK_PORTID_TO_BOARD_NUM(portid);
+ /* board = DAK_GETSLOT(portid); */
+ /* find the board node with the same board number */
+ if ((bnode = daktari_find_board(root, board)) == NULL) {
+ bnode = daktari_insert_board(root, board);
+ }
+
+ /* now attach this prom node to the board list */
+ /* Insert this node at the end of the list */
+ pnode->sibling = NULL;
+ if (bnode->nodes == NULL)
+ bnode->nodes = pnode;
+ else {
+ p = bnode->nodes;
+ while (p->sibling != NULL)
+ p = p->sibling;
+ p->sibling = pnode;
+ }
+}
+
+/*
+ * Search a Prom node and retrieve the property with the correct
+ * name.
+ */
+Prop *
+find_prop(Prom_node *pnode, char *name)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ if (pnode->props == NULL)
+ return (NULL);
+
+ prop = pnode->props;
+
+ if (prop == NULL)
+ return (NULL);
+
+ if (prop->name.val_ptr == NULL)
+ return (NULL);
+
+ while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) {
+ prop = prop->next;
+ }
+ return (prop);
+}
+
+int
+do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+ return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
+}
+
+
+/*
+ * return the property value for the Prop
+ * passed in.
+ */
+void *
+get_prop_val(Prop *prop)
+{
+ if (prop == NULL)
+ return (NULL);
+
+ return ((void *)(prop->value.val_ptr));
+}
+
+/* Local Routines */
+
+/*
+ * Start from the current node and return the next node besides
+ * the current one which has the requested model property.
+ */
+static Prom_node *
+dev_next_node_by_compat(Prom_node *root, char *compat)
+{
+ Prom_node *node;
+
+ if (root == NULL)
+ return (NULL);
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+/*
+ * Do a depth-first walk of a device tree and
+ * return the first node with the matching model.
+ */
+static Prom_node *
+dev_find_node_by_compat(Prom_node *root, char *compat)
+{
+ Prom_node *node;
+ char *compatible;
+ char *name;
+
+ if (root == NULL)
+ return (NULL);
+
+ if (compat == NULL)
+ return (NULL);
+
+ name = get_node_name(root);
+ if (name == NULL)
+ name = "";
+
+ compatible = (char *)get_prop_val(find_prop(root, "compatible"));
+
+ if (compatible == NULL)
+ return (NULL);
+
+ if ((strcmp(name, "pci") == 0) && (compatible != NULL) &&
+ (strcmp(compatible, compat) == 0)) {
+ return (root); /* found a match */
+ }
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+
+/*
+ * Add a board to the system list in order (sorted by board#).
+ * Initialize all pointer fields to NULL.
+ */
+static Board_node *
+daktari_insert_board(Sys_tree *root, int board)
+{
+ Board_node *bnode;
+ Board_node *temp = root->bd_list;
+
+ if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ bnode->nodes = NULL;
+ bnode->next = NULL;
+ bnode->board_num = board;
+ bnode->board_type = UNKNOWN_BOARD;
+
+ if (temp == NULL)
+ root->bd_list = bnode;
+
+ else if (temp->board_num > board) {
+ bnode->next = temp;
+ root->bd_list = bnode;
+
+ } else {
+ while ((temp->next != NULL) && (board > temp->next->board_num))
+ temp = temp->next;
+
+ bnode->next = temp->next;
+ temp->next = bnode;
+ }
+ root->board_cnt++;
+
+ return (bnode);
+}
+
+/*
+ * Find the requested board struct in the system device tree.
+ *
+ * This function overrides the functionality of the generic find_board()
+ * function in libprtdiag, but since we need to pass another parameter,
+ * we cannot simply overlay the symbol table.
+ */
+static Board_node *
+daktari_find_board(Sys_tree *root, int board)
+{
+ Board_node *bnode = root->bd_list;
+
+ while ((bnode != NULL) && (board != bnode->board_num)) {
+ bnode = bnode->next;
+ }
+ return (bnode);
+}
+
+
+int32_t
+find_child_device(picl_nodehdl_t parent, char *child_name,
+ picl_nodehdl_t *child)
+{
+ int32_t err;
+ char name[PICL_PROPNAMELEN_MAX];
+
+ err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child),
+ sizeof (picl_nodehdl_t));
+ switch (err) {
+ case PICL_SUCCESS:
+ break;
+ case PICL_PROPNOTFOUND:
+ err = PICL_INVALIDHANDLE;
+ return (err);
+ default:
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed picl_get_propval_by_name with %s\n"),
+ picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+
+#ifdef WORKFILE_DEBUG
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed the get name for root\n"), 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%s\n"),
+ picl_strerror(err), 0);
+ }
+#endif
+
+ if (strcmp(name, child_name) == 0)
+ return (err);
+
+ while (err != PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(*child, PICL_PROP_PEER,
+ &(*child), sizeof (picl_nodehdl_t));
+ switch (err) {
+ case PICL_SUCCESS:
+ err = picl_get_propval_by_name(*child, PICL_PROP_NAME,
+ name, PICL_PROPNAMELEN_MAX);
+ if (strcmp(name, child_name) == 0)
+ return (err);
+ break;
+ case PICL_PROPNOTFOUND:
+ break;
+ default:
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed picl_get_propval_by_name with %s\n"),
+ picl_strerror(err), 0);
+#endif
+ return (err);
+ }
+ }
+ err = PICL_INVALIDHANDLE;
+ return (err);
+}
+
+int32_t
+fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id,
+ picl_nodehdl_t *device)
+{
+ int32_t err;
+ picl_prophdl_t tbl_hdl;
+ picl_prophdl_t reference_property;
+
+ err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
+ sizeof (picl_prophdl_t));
+ if (err != PICL_SUCCESS) {
+#ifdef WORKFILE_DEBUG
+ if (err != PICL_INVALIDHANDLE) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in "
+ "picl_get_propval_by_name err is %s\n"),
+ picl_strerror(err), 0);
+ }
+#endif
+ return (err);
+ }
+
+ err = picl_get_next_by_row(tbl_hdl, &reference_property);
+ if (err != PICL_SUCCESS) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in picl_get_next_by_row"
+ " err is %s\n"), picl_strerror(err), 0);
+#endif
+ return (err);
+ }
+
+ /* get node associated with reference property */
+ err = picl_get_propval(reference_property, &(*device),
+ sizeof (picl_nodehdl_t));
+
+#ifdef WORKFILE_DEBUG
+ if (err != 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in picl_get_propval"
+ " err is %s\n"), picl_strerror(err), 0);
+ }
+#endif
+ return (err);
+}
+
+int32_t
+fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id,
+ int32_t *number_of_devices, picl_nodehdl_t *device_array[])
+{
+ int32_t err;
+ int i;
+ picl_prophdl_t tbl_hdl;
+ picl_prophdl_t entry;
+ int devs = 0;
+ err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
+ sizeof (picl_prophdl_t));
+ if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_propval_by_name err is %s\n"),
+ picl_strerror(err), 0);
+#endif
+ return (err);
+ }
+
+ entry = tbl_hdl;
+ while (picl_get_next_by_row(entry, &entry) == 0)
+ ++devs;
+
+ *device_array = calloc((devs), sizeof (picl_nodehdl_t));
+ if (*device_array == NULL) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure getting memory"
+ " for array\n"), 0);
+#endif
+ return (PICL_FAILURE);
+ }
+
+ entry = tbl_hdl;
+ for (i = 0; i < (devs); i++) {
+ err = picl_get_next_by_row(entry, &entry);
+ if (err != 0) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_next_by_row err is %s\n"),
+ picl_strerror(err), 0);
+#endif
+ return (err);
+ }
+
+ /* get node associated with reference property */
+ err = picl_get_propval(entry, &((*device_array)[i]),
+ sizeof (picl_nodehdl_t));
+ if (err != 0) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_propval err is %s\n"),
+ picl_strerror(err), 0);
+#endif
+ return (err);
+ }
+ }
+ *number_of_devices = devs;
+ return (err);
+}
+
+/*
+ * This function provides formatting of the memory config
+ * information that get_us3_mem_regs() and display_us3_banks() code has
+ * gathered. It overrides the generic print_us3_memory_line() code
+ * which prints an error message.
+ */
+void
+print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
+{
+ int mcid;
+ mcid = portid;
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n %-1c %2d %2d %4lldMB %11-s %4lldMB "
+ " %2d-way %d"),
+ 'A' + DAK_GETSLOT(portid), mcid, (bank_id % 4),
+ bank_size, bank_status, dimm_size, intlv, seg_id, 0);
+}
+
+
+/*
+ * Fills in the i/o card list to be displayed later in display_pci();
+ */
+void
+fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node,
+ struct io_card *pci_card,
+ struct io_card **pci_card_list, char **slot_name_arr)
+{
+ Prom_node *pci_bridge_node;
+ Prom_node *pci_parent_bridge;
+ int *int_val;
+ int pci_bridge = FALSE;
+ int pci_bridge_dev_no = -1;
+ int portid;
+ int pci_bus;
+ char buf[MAXSTRLEN];
+ char *slot_name = NULL; /* info in "slot-names" prop */
+ char *child_name;
+ char *name;
+ char *type;
+ void *value;
+
+ while (pci_card_node != NULL) {
+ int is_pci = FALSE;
+ type = NULL;
+ name = NULL;
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(pci_card_node, "name"));
+ if (name == NULL) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+
+ /*
+ * Get the portid of the schizo that this card
+ * lives under.
+ */
+ portid = -1;
+ value = get_prop_val(find_prop(pci_instance, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+ pci_card->schizo_portid = portid;
+ /*
+ * Find out whether this is PCI bus A or B
+ * using the 'reg' property.
+ */
+ int_val = (int *)get_prop_val(find_prop(pci_instance, "reg"));
+
+ if (int_val != NULL) {
+ int_val++; /* skip over first integer */
+ pci_bus = ((*int_val) & 0x7f0000);
+ if (pci_bus == 0x600000)
+ pci_card->pci_bus = 'A';
+ else if (pci_bus == 0x700000)
+ pci_card->pci_bus = 'B';
+ else
+ pci_card->pci_bus = '-';
+ } else {
+ pci_card->pci_bus = '-';
+ }
+
+ if ((pci_card->schizo_portid == 8) &&
+ (pci_card->pci_bus == 'A')) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+
+ /*
+ * get dev# and func# for this card from the
+ * 'reg' property.
+ */
+ int_val = (int *)get_prop_val(
+ find_prop(pci_card_node, "reg"));
+ if (int_val != NULL) {
+ pci_card->dev_no = (((*int_val) & 0xF800) >> 11);
+ pci_card->func_no = (((*int_val) & 0x700) >> 8);
+ } else {
+ pci_card->dev_no = -1;
+ pci_card->func_no = -1;
+ }
+
+ type = (char *)get_prop_val(
+ find_prop(pci_card_node, "device_type"));
+ /*
+ * If this is a pci-bridge, then store its dev#
+ * as its children nodes need this to get their slot#.
+ * We set the pci_bridge flag so that we know we are
+ * looking at a pci-bridge node. This flag gets reset
+ * every time we enter this while loop.
+ */
+
+ /*
+ * Check for a PCI-PCI Bridge for PCI and cPCI
+ * IO Boards using the name and type properties.
+ */
+ if ((type != NULL) && (strncmp(name, "pci", 3) == 0) &&
+ (strcmp(type, "pci") == 0)) {
+ pci_bridge_node = pci_card_node;
+ is_pci = TRUE;
+ if (!pci_bridge) {
+ pci_bridge_dev_no = pci_card->dev_no;
+ pci_parent_bridge = pci_bridge_node;
+ pci_bridge = TRUE;
+ }
+ }
+ if ((pci_card->pci_bus == 'B') && (pci_card->dev_no == 1) &&
+ (!pci_bridge)) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+
+ /*
+ * Get slot-names property from slot_names_arr.
+ * If we are the child of a pci_bridge we use the
+ * dev# of the pci_bridge as an index to get
+ * the slot number. We know that we are a child of
+ * a pci-bridge if our parent is the same as the last
+ * pci_bridge node found above.
+ */
+ if (pci_card->dev_no != -1) {
+ /*
+ * We compare this cards parent node with the
+ * pci_bridge_node to see if it's a child.
+ */
+ if (pci_card_node->parent != pci_instance &&
+ pci_bridge) {
+ /* use dev_no of pci_bridge */
+ if (pci_card->pci_bus == 'B') {
+ slot_name =
+ slot_name_arr[pci_bridge_dev_no -2];
+ } else {
+ slot_name =
+ slot_name_arr[pci_bridge_dev_no -1];
+ }
+ } else {
+ if (pci_card->pci_bus == 'B') {
+ slot_name =
+ slot_name_arr[pci_card->dev_no-2];
+ } else {
+ slot_name =
+ slot_name_arr[pci_card->dev_no-1];
+ }
+ }
+
+ if (slot_name != NULL &&
+ strlen(slot_name) != 0) {
+ /* Slot num is last char in string */
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "%c", slot_name[strlen(slot_name) - 1]);
+ } else {
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "-");
+ }
+
+ } else {
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "%c", '-');
+ }
+
+ /*
+ * Check for failed status.
+ */
+ if (node_failed(pci_card_node))
+ strcpy(pci_card->status, "fail");
+ else
+ strcpy(pci_card->status, "ok");
+
+ /* Get the model of this pci_card */
+ value = get_prop_val(find_prop(pci_card_node, "model"));
+ if (value == NULL)
+ pci_card->model[0] = '\0';
+ else {
+ (void) snprintf(pci_card->model, MAXSTRLEN, "%s",
+ (char *)value);
+ }
+ /*
+ * The card may have a "clock-frequency" but we
+ * are not interested in that. Instead we get the
+ * "clock-frequency" of the PCI Bus that the card
+ * resides on. PCI-A can operate at 33Mhz or 66Mhz
+ * depending on what card is plugged into the Bus.
+ * PCI-B always operates at 33Mhz.
+ */
+ int_val = get_prop_val(find_prop(pci_instance,
+ "clock-frequency"));
+ if (int_val != NULL) {
+ pci_card->freq = DAK_CLK_FREQ_TO_MHZ(*int_val);
+ } else {
+ pci_card->freq = -1;
+ }
+
+ /*
+ * Figure out how we want to display the name
+ */
+ value = get_prop_val(find_prop(pci_card_node,
+ "compatible"));
+ if (value != NULL) {
+ /* use 'name'-'compatible' */
+ (void) snprintf(buf, MAXSTRLEN, "%s-%s", name,
+ (char *)value);
+ } else {
+ /* just use 'name' */
+ (void) snprintf(buf, MAXSTRLEN, "%s", name);
+ }
+ name = buf;
+
+ /*
+ * If this node has children, add the device_type
+ * of the child to the name value of this pci_card->
+ */
+ child_name = (char *)get_node_name(pci_card_node->child);
+ if ((pci_card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(pci_card_node->child,
+ "device_type"));
+ if (value != NULL) {
+ /* add device_type of child to name */
+ (void) snprintf(pci_card->name, MAXSTRLEN,
+ "%s/%s (%s)", name, child_name,
+ (char *)value);
+ } else {
+ /* just add childs name */
+ (void) snprintf(pci_card->name, MAXSTRLEN,
+ "%s/%s", name, child_name);
+ }
+ } else {
+ (void) snprintf(pci_card->name, MAXSTRLEN, "%s",
+ (char *)name);
+ }
+
+ /*
+ * If this is a pci-bridge, then add the word
+ * 'pci-bridge' to its model. If we can't find
+ * a model, then we just describe what the device
+ * is based on some properties.
+ */
+ if (pci_bridge) {
+ if (strlen(pci_card->model) == 0) {
+ if (pci_card_node->parent == pci_bridge_node)
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "device on pci-bridge");
+ else if (pci_card_node->parent
+ == pci_parent_bridge)
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "pci-bridge/pci-bridge");
+ else
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "PCI-BRIDGE");
+ }
+ else
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s/pci-bridge", pci_card->model);
+ }
+ /* insert this pci_card in the list to be displayed later */
+
+ *pci_card_list = insert_io_card(*pci_card_list, pci_card);
+
+ /*
+ * If we are dealing with a pci-bridge, we need to move
+ * down to the children of this bridge if there are any.
+ *
+ * If we are not, we are either dealing with a regular
+ * card (in which case we move onto the sibling of this
+ * card) or we are dealing with a child of a pci-bridge
+ * (in which case we move onto the child's siblings or
+ * if there are no more siblings for this child, we
+ * move onto the parents siblings).
+ */
+ pci_card_node = next_pci_card(pci_card_node, &pci_bridge,
+ is_pci, pci_bridge_node,
+ pci_parent_bridge, pci_instance);
+ } /* end-while */
+}
+
+
+/*
+ * Helper function for fill_pci_card_list(). Indicates which
+ * card node to go to next.
+ * Parameters:
+ * -----------
+ * Prom_node * curr_card: pointer to the current card node
+ *
+ * int * is_bridge: indicates whether or not the card (is | is on)
+ * a pci bridge
+ *
+ * int is_pcidev: indicates whether or not the current card
+ * is a pci bridge
+ *
+ * Prom_node * curr_bridge: pointer to the current pci bridge. Eg:
+ * curr_card->parent.
+ *
+ * Prom_node * parent_bridge: pointer to the first pci bridge encountered.
+ * we could have nested pci bridges, this would
+ * be the first one.
+ *
+ * Prom_node * pci: pointer to the pci instance that we are attached to.
+ * This would be parent_bridge->parent, or
+ * curr_node->parent, if curr_node is not on a pci bridge.
+ */
+static Prom_node *
+next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev,
+ Prom_node *curr_bridge, Prom_node *parent_bridge,
+ Prom_node *pci)
+{
+ Prom_node * curr_node = curr_card;
+ if (*is_bridge) {
+ /*
+ * is_pcidev is used to prevent us from following the
+ * children of something like a scsi device.
+ */
+ if (curr_node->child != NULL && is_pcidev) {
+ curr_node = curr_node->child;
+ } else {
+ curr_node = curr_node->sibling;
+ if (curr_node == NULL) {
+ curr_node = curr_bridge->sibling;
+
+ while (curr_node == NULL &&
+ curr_bridge != parent_bridge &&
+ curr_bridge != NULL) {
+ curr_node =
+ curr_bridge->parent->sibling;
+ curr_bridge = curr_bridge->parent;
+ if (curr_node != NULL &&
+ curr_node->parent == pci) {
+ break;
+ }
+ }
+
+ if (curr_bridge == NULL ||
+ curr_node == NULL ||
+ curr_node->parent == pci ||
+ curr_bridge == parent_bridge ||
+ curr_node == parent_bridge) {
+ *is_bridge = FALSE;
+ }
+ }
+ }
+
+ } else {
+ curr_node = curr_node->sibling;
+ }
+ return (curr_node);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/desktop/Makefile b/usr/src/lib/libprtdiag_psr/sparc/desktop/Makefile
new file mode 100644
index 0000000000..713cc7d570
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/desktop/Makefile
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2000 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/desktop/Makefile
+
+PRTDIAG_DIRS= nonpicl picl
+
+all := TARGET= all
+lint := TARGET= lint
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all lint clean clobber install _msg : $(PRTDIAG_DIRS)
+
+$(PRTDIAG_DIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/desktop/common/desktop.c b/usr/src/lib/libprtdiag_psr/sparc/desktop/common/desktop.c
new file mode 100644
index 0000000000..29d72ee246
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/desktop/common/desktop.c
@@ -0,0 +1,622 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Desktop Platform specific functions.
+ *
+ * Called when:
+ * machine_type == MTYPE_DARWIN &&
+ * machine_type == MTYPE_DEFAULT
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+
+#define PCI_BUS(x) ((x >> 16) & 0xff)
+
+/*
+ * State variable to signify the type of machine we're currently
+ * running on. Since prtdiag has come to be the dumping ground
+ * for lots of platform-specific routines, and machine architecture
+ * alone is not enough to determine our course of action, we need
+ * to enumerate the different machine types that we should worry
+ * about.
+ */
+enum machine_type {
+ MTYPE_DEFAULT = 0, /* Desktop-class machine */
+ MTYPE_DARWIN = 1
+};
+
+enum machine_type machine_type = MTYPE_DEFAULT;
+
+extern int print_flag;
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (desktop systems only)
+ */
+int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+int disp_fail_parts(Sys_tree *tree);
+void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_pci(Board_node *bnode);
+void read_platform_kstats(Sys_tree *tree,
+ struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep);
+void display_sbus(Board_node *);
+
+
+/* local functions */
+static void dt_disp_asic_revs(Sys_tree *);
+static void display_sabre_pci(Board_node *);
+static void display_dev_node(Prom_node *np, int depth);
+static void get_machine_type(void);
+
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ int exit_code = 0; /* init to all OK */
+
+#ifdef lint
+ kstats = kstats;
+#endif
+
+ /*
+ * silently check for any types of machine errors
+ */
+ print_flag = 0;
+ if (disp_fail_parts(tree)) {
+ /* set exit_code to show failures */
+ exit_code = 1;
+ }
+ print_flag = 1;
+
+ return (exit_code);
+}
+
+
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+#ifdef lint
+ tree = tree;
+ grps = grps;
+#endif
+}
+
+/*
+ * disp_fail_parts
+ *
+ * Display the failed parts in the system. This function looks for
+ * the status property in all PROM nodes. On systems where
+ * the PROM does not supports passing diagnostic information
+ * thruogh the device tree, this routine will be silent.
+ */
+int
+disp_fail_parts(Sys_tree *tree)
+{
+ int exit_code;
+ int system_failed = 0;
+ Board_node *bnode = tree->bd_list;
+ Prom_node *pnode;
+
+ exit_code = 0;
+
+ /* go through all of the boards looking for failed units. */
+ while (bnode != NULL) {
+ /* find failed chips */
+ pnode = find_failed_node(bnode->nodes);
+ if ((pnode != NULL) && !system_failed) {
+ system_failed = 1;
+ exit_code = 1;
+ if (print_flag == 0) {
+ return (exit_code);
+ }
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
+ "Replaceable Units (FRU) in System:\n"), 0);
+ log_printf("=========================="
+ "====================\n", 0);
+ }
+
+ while (pnode != NULL) {
+ void *value;
+ char *name; /* node name string */
+ char *type; /* node type string */
+ char *board_type = NULL;
+
+ value = get_prop_val(find_prop(pnode, "status"));
+ name = get_node_name(pnode);
+
+ /* sanity check of data retreived from PROM */
+ if ((value == NULL) || (name == NULL)) {
+ pnode = next_failed_node(pnode);
+ continue;
+ }
+
+ /* Find the board type of this board */
+ if (bnode->board_type == CPU_BOARD) {
+ board_type = "CPU";
+ } else {
+ board_type = "IO";
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "%s unavailable "
+ "on %s Board #%d\n"), name, board_type,
+ bnode->board_num, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tPROM fault string: %s\n"), value, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tFailed Field Replaceable Unit is "), 0);
+
+ /*
+ * Determine whether FRU is CPU module, system
+ * board, or SBus card.
+ */
+ if ((name != NULL) && (strstr(name, "sbus"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "SBus Card %d\n"),
+ get_sbus_slot(pnode), 0);
+
+ } else if (((name = get_node_name(pnode->parent)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "PCI Card %d"),
+ get_pci_device(pnode), 0);
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "cpu"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN, "UltraSPARC "
+ "module Board %d Module %d\n"), 0,
+ get_id(pnode));
+
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%s board %d\n"), board_type,
+ bnode->board_num, 0);
+ }
+ pnode = next_failed_node(pnode);
+ }
+ bnode = bnode->next;
+ }
+
+ if (!system_failed) {
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "No failures found in System\n"), 0);
+ log_printf("===========================\n", 0);
+ }
+
+ if (system_failed)
+ return (1);
+ else
+ return (0);
+}
+
+
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+
+#ifdef lint
+ kstats = kstats;
+#endif
+ /* Display failed units */
+ (void) disp_fail_parts(tree);
+}
+
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+
+#ifdef lint
+ kstats = kstats;
+#endif
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is iof the user
+ * told us to do logging, and we found a system failure.
+ */
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ dt_disp_asic_revs(tree);
+
+ platform_disp_prom_version(tree);
+ }
+ return;
+
+}
+
+void
+display_pci(Board_node *bnode)
+{
+ Prom_node *pci;
+
+ /*
+ * We have different routines for walking/displaying PCI
+ * devices depending on whether the PCI device is a
+ * Psycho or a Sabre.
+ */
+ pci = dev_find_node_by_type(bnode->nodes, "model", "SUNW,psycho");
+ if (pci != NULL) {
+ display_psycho_pci(bnode);
+ return;
+ }
+
+ pci = dev_find_node_by_type(bnode->nodes, "model", "SUNW,sabre");
+ if (pci != NULL) {
+ display_sabre_pci(bnode);
+ return;
+ }
+}
+
+void
+read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep)
+
+{
+#ifdef lint
+ tree = tree;
+ sys_kstat = sys_kstat;
+ bdp = bdp;
+ ep = ep;
+#endif
+}
+
+
+/*
+ * local functions
+ */
+
+void
+dt_disp_asic_revs(Sys_tree *tree)
+{
+ Board_node *bnode;
+ Prom_node *pnode;
+ char *name;
+ int *version;
+
+ /* Print the header */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(" HW Revisions ", 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ bnode = tree->bd_list;
+
+ log_printf("ASIC Revisions:\n", 0);
+ log_printf("---------------\n", 0);
+
+ /* Find sysio and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
+ pnode = dev_next_node(pnode, "sbus")) {
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ log_printf("SBus: %s Rev %d\n",
+ name, *version, 0);
+ }
+ }
+
+ /* Find Psycho and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
+ pnode = dev_next_node(pnode, "pci")) {
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL))
+ log_printf("PCI: %s Rev %d\n",
+ name, *version, 0);
+ }
+
+ /* Find Cheerio and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
+ pnode = dev_next_node(pnode, "ebus")) {
+ version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL))
+ log_printf("Cheerio: %s Rev %d\n", name, *version, 0);
+ }
+
+
+ /* Find the FEPS and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
+ pnode = dev_next_node(pnode, "SUNW,hme")) {
+ version = (int *)get_prop_val(find_prop(pnode, "hm-rev"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ log_printf("FEPS: %s Rev ", name);
+ if (*version == 0xa0) {
+ log_printf("2.0\n", 0);
+ } else if (*version == 0x20) {
+ log_printf("2.1\n", 0);
+ } else {
+ log_printf("%x\n", *version, 0);
+ }
+ }
+ }
+ log_printf("\n", 0);
+
+ display_ffb(bnode, 0);
+}
+
+/*
+ * print the header and call display_dev_node() to walk the device
+ * tree (darwin platform only).
+ */
+static void
+display_sabre_pci(Board_node *board)
+{
+ if (board == NULL)
+ return;
+
+ log_printf(" Bus# Freq\n", 0);
+ log_printf("Brd Type MHz Slot "
+ "Name Model", 0);
+ log_printf("\n", 0);
+ log_printf("--- ---- ---- ---- "
+ "-------------------------------- ----------------------", 0);
+ log_printf("\n", 0);
+ display_dev_node(board->nodes, 0);
+ log_printf("\n", 0);
+}
+
+
+/*
+ * Recursively traverse the device tree and use tree depth as filter.
+ * called by: display_sabre_pci()
+ */
+static void
+display_dev_node(Prom_node *np, int depth)
+{
+ char *name, *model, *compat, *regval;
+ unsigned int reghi;
+
+ if (!np)
+ return;
+ if (depth > 2)
+ return;
+
+ name = get_prop_val(find_prop(np, "name"));
+ model = get_prop_val(find_prop(np, "model"));
+ compat = get_prop_val(find_prop(np, "compatible"));
+ regval = get_prop_val(find_prop(np, "reg"));
+
+ if (!regval)
+ return;
+ else
+ reghi = *(int *)regval;
+
+ if (!model)
+ model = "";
+ if (!name)
+ name = "";
+
+ if (depth == 2) {
+ char buf[256];
+ if (compat)
+ (void) sprintf(buf, "%s-%s", name, compat);
+ else
+ (void) sprintf(buf, "%s", name);
+
+ log_printf(" 0 PCI-%d 33 ", PCI_BUS(reghi), 0);
+ log_printf("%3d ", PCI_DEVICE(reghi), 0);
+ log_printf("%-32.32s", buf, 0);
+ log_printf(strlen(buf) > 32 ? "+ " : " ", 0);
+ log_printf("%-22.22s", model, 0);
+ log_printf(strlen(model) > 22 ? "+" : "", 0);
+ log_printf("\n", 0);
+
+#ifdef DEBUG
+ if (!compat)
+ compat = "";
+ printf("bus=%d slot=%d name=%s model=%s compat=%s\n",
+ PCI_BUS(reghi), PCI_DEVICE(reghi), name, model, compat);
+#endif
+ }
+
+ if ((!strstr(name, "ebus")) && (!strstr(name, "ide")))
+ display_dev_node(np->child, depth+1);
+ display_dev_node(np->sibling, depth);
+}
+
+/*
+ * display_sbus
+ * Display all the SBus IO cards on this board.
+ */
+void
+display_sbus(Board_node *board)
+{
+ struct io_card card;
+ struct io_card *card_list = NULL;
+ int freq;
+ int card_num;
+ void *value;
+ Prom_node *sbus;
+ Prom_node *card_node;
+
+ if (board == NULL)
+ return;
+
+ for (sbus = dev_find_node(board->nodes, SBUS_NAME); sbus != NULL;
+ sbus = dev_next_node(sbus, SBUS_NAME)) {
+
+ /* Skip failed nodes for now */
+ if (node_failed(sbus))
+ continue;
+
+ /* Calculate SBus frequency in MHz */
+ value = get_prop_val(find_prop(sbus, "clock-frequency"));
+ if (value != NULL)
+ freq = ((*(int *)value) + 500000) / 1000000;
+ else
+ freq = -1;
+
+ for (card_node = sbus->child; card_node != NULL;
+ card_node = card_node->sibling) {
+ char *model;
+ char *name;
+ char *child_name;
+
+ card_num = get_sbus_slot(card_node);
+ if (card_num == -1)
+ continue;
+
+ /* Fill in card information */
+ card.display = 1;
+ card.freq = freq;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "SBus");
+ card.slot = card_num;
+ card.status[0] = '\0';
+
+ /* Try and get card status */
+ value = get_prop_val(find_prop(card_node, "status"));
+ if (value != NULL)
+ (void) strncpy(card.status, (char *)value,
+ MAXSTRLEN);
+
+ /* XXX - For now, don't display failed cards */
+ if (strstr(card.status, "fail") != NULL)
+ continue;
+
+ /*
+ * sets the machine_type var if not already set
+ */
+ get_machine_type();
+
+ /*
+ * For desktops, the only high slot number that
+ * needs to be displayed is the # 14 slot.
+ */
+ if (machine_type == MTYPE_DEFAULT &&
+ card_num >= MX_SBUS_SLOTS && card_num != 14) {
+ continue;
+ }
+
+ /* Now gather all of the node names for that card */
+ model = (char *)get_prop_val(find_prop(card_node,
+ "model"));
+ name = get_node_name(card_node);
+
+ if (name == NULL)
+ continue;
+
+ card.name[0] = '\0';
+ card.model[0] = '\0';
+
+ /* Figure out how we want to display the name */
+ child_name = get_node_name(card_node->child);
+ if ((card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(card_node->child,
+ "device_type"));
+ if (value != NULL)
+ (void) sprintf(card.name, "%s/%s (%s)",
+ name, child_name,
+ (char *)value);
+ else
+ (void) sprintf(card.name, "%s/%s", name,
+ child_name);
+ } else {
+ (void) strncpy(card.name, name, MAXSTRLEN);
+ }
+
+ if (model != NULL)
+ (void) strncpy(card.model, model, MAXSTRLEN);
+
+ card_list = insert_io_card(card_list, &card);
+ }
+ }
+
+ /* We're all done gathering card info, now print it out */
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+static void
+get_machine_type(void)
+{
+ char name[MAXSTRLEN];
+
+ machine_type = MTYPE_DEFAULT;
+
+ /* Figure out what kind of machine we're on */
+ if (sysinfo(SI_PLATFORM, name, MAXSTRLEN) != -1) {
+ if (strcmp(name, "SUNW,Ultra-5_10") == 0)
+ machine_type = MTYPE_DARWIN;
+ }
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/desktop/common/picldiag.c b/usr/src/lib/libprtdiag_psr/sparc/desktop/common/picldiag.c
new file mode 100644
index 0000000000..51677867f0
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/desktop/common/picldiag.c
@@ -0,0 +1,3687 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+#include <errno.h>
+#include <libintl.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/openpromio.h>
+#include <sys/ddi.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <locale.h>
+#include <picl.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "display_sun4u.h"
+#include "picldefs.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+#define EM_INIT_FAIL dgettext(TEXT_DOMAIN,\
+ "picl_initialize failed: %s\n")
+#define EM_GET_ROOT_FAIL dgettext(TEXT_DOMAIN,\
+ "Getting root node failed: %s\n")
+#define EM_PRTDIAG_FAIL dgettext(TEXT_DOMAIN, "Prtdiag failed!\n")
+
+#define SIGN_ON_MSG dgettext(TEXT_DOMAIN,\
+ "System Configuration: Sun Microsystems ")
+#define SYSCLK_FREQ_MSG dgettext(TEXT_DOMAIN,\
+ "System clock frequency: %d MHZ\n")
+#define SERIAL_NUM_MSG dgettext(TEXT_DOMAIN,\
+ "Chassis Serial Number:\n")
+#define MEM_SIZE_MSG dgettext(TEXT_DOMAIN, "Memory size: ")
+#define FFB_DOUBLE_BUF dgettext(TEXT_DOMAIN, "FFB, Double Buffered")
+#define FFB_SINGLE_BUF dgettext(TEXT_DOMAIN, "FFB, Single Buffered")
+
+#define DEFAULT_BOARD_NUM 0
+#define DEFAULT_PORTID 0
+#define CLK_FREQ_66MHZ 66
+#define USB -1
+#define HUB -2
+
+/* bus id */
+#define SBUS_TYPE 0
+#define PCI_TYPE 1
+#define UPA_TYPE 2
+#define PCIEX_TYPE 3
+
+#define UPA_NAME "upa"
+#define PCIEX_NAME "pciex"
+
+/*
+ * PICL classes
+ */
+#define PICL_CLASS_OPTIONS "options"
+
+/*
+ * Property names
+ */
+
+#define OBP_PROP_REG "reg"
+#define OBP_PROP_CLOCK_FREQ "clock-frequency"
+#define OBP_PROP_BOARD_NUM "board#"
+#define OBP_PROP_REVISION_ID "revision-id"
+#define OBP_PROP_VERSION_NUM "version#"
+#define OBP_PROP_MODREV_NUM "module-revision#"
+#define OBP_PROP_BOARD_TYPE "board_type"
+#define OBP_PROP_ECACHE_SIZE "ecache-size"
+#define OBP_PROP_IMPLEMENTATION "implementation#"
+#define OBP_PROP_MASK "mask#"
+#define OBP_PROP_COMPATIBLE "compatible"
+#define OBP_PROP_BANNER_NAME "banner-name"
+#define OBP_PROP_MODEL "model"
+#define OBP_PROP_66MHZ_CAPABLE "66mhz-capable"
+#define OBP_PROP_FBC_REG_ID "fbc_reg_id"
+#define OBP_PROP_VERSION "version"
+
+#define PROP_POWERFAIL_TIME "powerfail-time"
+#define PICL_PROP_LOW_WARNING_THRESHOLD "LowWarningThreshold"
+
+#define DEFAULT_LINE_WIDTH 78
+#define HEADING_SYMBOL "="
+
+#define MAX_IWAYS 32
+
+typedef struct bank_list {
+ picl_nodehdl_t nodeh;
+ uint32_t iway_count;
+ uint32_t iway[MAX_IWAYS];
+ struct bank_list *next;
+} bank_list_t;
+
+typedef struct {
+ uint64_t base;
+ uint64_t size;
+ int ifactor;
+ int bank_count;
+} seg_info_t;
+
+static struct io_card *io_card_list = NULL; /* The head of the IO card list */
+static bank_list_t *mem_banks = NULL;
+static int mem_xfersize;
+static int no_xfer_size = 0;
+
+static char *io_device_table[] = {
+ "block",
+ "disk",
+ "cdrom",
+ "floppy",
+ "tape",
+ "network",
+ "display",
+ "serial",
+ "parallel",
+ "scsi",
+ "scsi-2",
+ "scsi-3",
+ "ide",
+ "fcal",
+ "keyboard",
+ "mouse",
+ "dma"
+};
+
+#define NIODEVICE sizeof (io_device_table) / sizeof (io_device_table[0])
+
+static char *bus_table[] = {
+ "ebus",
+ "isa",
+ "pmu",
+ "pci",
+ "pciex"
+};
+
+#define NBUS sizeof (bus_table) / sizeof (bus_table[0])
+
+/* prtdiag exit codes */
+#define PD_SUCCESS 0
+#define PD_SYSTEM_FAILURE 1
+#define PD_INTERNAL_FAILURE 2
+
+/*
+ * Use of global assumes do_prominfo only called from main in prtdiag and
+ * access does not need to be multi-thread safe.
+ */
+static int exit_code = PD_SUCCESS;
+
+/*
+ * This function is called from every location where a status value is output.
+ * It checks the status arg and sets exit_code if an error is detected.
+ * The status is typically returned from a PICL query. A case-insensitive
+ * string comparison is done to check for any status that starts with "fail"
+ * or "fault".
+ */
+static void
+set_exit_code(char *status)
+{
+ if (status == NULL)
+ return;
+
+ if (strncasecmp(status, "fail", 4) == 0 ||
+ strncasecmp(status, "fault", 5) == 0)
+ exit_code = PD_SYSTEM_FAILURE;
+}
+
+/*
+ * check if it is an IO deice
+ */
+static int
+is_io_device(char *device_class)
+{
+ int i;
+
+ for (i = 0; i < NIODEVICE; i++) {
+ if (strcmp(device_class, io_device_table[i]) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * check if it is a bus
+ */
+static int
+is_bus(char *device_class)
+{
+ int i;
+
+ for (i = 0; i < NBUS; i++) {
+ if (strcmp(device_class, bus_table[i]) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * search children to get the node by the nodename
+ */
+static int
+picldiag_get_node_by_name(picl_nodehdl_t rooth, char *name,
+ picl_nodehdl_t *nodeh)
+{
+ picl_nodehdl_t childh;
+ int err;
+ char *nodename;
+
+ nodename = alloca(strlen(name) + 1);
+ if (nodename == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
+ nodename, (strlen(name) + 1));
+ if (err != PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ if (strcmp(nodename, name) == 0) {
+ *nodeh = childh;
+ return (PICL_SUCCESS);
+ }
+
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ return (err);
+}
+
+/*
+ * get the value by the property name of the string prop
+ * Caller must free the outbuf
+ */
+static int
+picldiag_get_string_propval(picl_nodehdl_t modh, char *prop_name, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ char *prop_value;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If it is not a string prop, return NULL
+ */
+ if (pinfo.type != PICL_PTYPE_CHARSTRING)
+ return (PICL_FAILURE);
+
+ prop_value = malloc(pinfo.size);
+ if (prop_value == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, prop_value, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(prop_value);
+ return (err);
+ }
+
+ *outbuf = prop_value;
+ return (PICL_SUCCESS);
+}
+
+
+/*
+ * return the value as a signed integer
+ */
+
+static int64_t
+picldiag_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int8_t int8v;
+ int16_t int16v;
+ int32_t int32v;
+ int64_t int64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int, uint or byte array prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
+ (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ switch (pinfo.size) {
+ case sizeof (int8_t):
+ err = picl_get_propval(proph, &int8v, sizeof (int8v));
+ *ret = err;
+ return (int8v);
+ case sizeof (int16_t):
+ err = picl_get_propval(proph, &int16v, sizeof (int16v));
+ *ret = err;
+ return (int16v);
+ case sizeof (int32_t):
+ err = picl_get_propval(proph, &int32v, sizeof (int32v));
+ *ret = err;
+ return (int32v);
+ case sizeof (int64_t):
+ err = picl_get_propval(proph, &int64v, sizeof (int64v));
+ *ret = err;
+ return (int64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+/*
+ * return the value of the uint prop
+ */
+static uint64_t
+picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ uint8_t uint8v;
+ uint16_t uint16v;
+ uint32_t uint32v;
+ uint64_t uint64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int or uint prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ /* uint prop */
+
+ switch (pinfo.size) {
+ case sizeof (uint8_t):
+ err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
+ *ret = err;
+ return (uint8v);
+ case sizeof (uint16_t):
+ err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
+ *ret = err;
+ return (uint16v);
+ case sizeof (uint32_t):
+ err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
+ *ret = err;
+ return (uint32v);
+ case sizeof (uint64_t):
+ err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
+ *ret = err;
+ return (uint64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+/*
+ * return the value of the float prop
+ */
+static float
+picldiag_get_float_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ float floatv;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return ((float)0);
+ }
+
+ /*
+ * If it is not a float prop, return failure
+ */
+ if (pinfo.type != PICL_PTYPE_FLOAT) {
+ *ret = PICL_FAILURE;
+ return ((float)0);
+ }
+
+ *ret = picl_get_propval(proph, &floatv, sizeof (floatv));
+ return (floatv);
+}
+
+/*
+ * get the clock frequency
+ */
+static int
+picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
+{
+#define ROUND_TO_MHZ(x) (((x) + 500000)/ 1000000)
+ int err;
+ uint64_t clk_freq;
+
+ clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ *freq = ROUND_TO_MHZ(clk_freq);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * get the clock frequency from parent
+ */
+static int
+picldiag_get_clock_from_parent(picl_nodehdl_t nodeh, uint32_t *clk)
+{
+ picl_nodehdl_t parenth;
+ int err;
+
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &parenth, sizeof (parenth));
+
+ while (err == PICL_SUCCESS) {
+ err = picldiag_get_clock_freq(parenth, clk);
+ if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
+ &parenth, sizeof (parenth));
+ }
+
+ return (err);
+}
+
+/*
+ * get _fru_parent prop
+ * If not found, then travese superiors (parent nodes) until
+ * a _fru_parent property is found.
+ * If not found, no fru parent
+ */
+static int
+picldiag_get_fru_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruparenth)
+{
+ picl_nodehdl_t fruh;
+ int err;
+
+ /* find fru parent */
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
+ &fruh, sizeof (fruh));
+
+ if (err != PICL_SUCCESS)
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_LOC_PARENT,
+ &fruh, sizeof (fruh));
+
+ while (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
+ &fruh, sizeof (fruh));
+ if (err != PICL_SUCCESS)
+ err = picl_get_propval_by_name(nodeh,
+ PICL_REFPROP_LOC_PARENT, &fruh, sizeof (fruh));
+ }
+
+ if (err == PICL_SUCCESS)
+ *fruparenth = fruh;
+
+ return (err);
+}
+
+/*
+ * get label
+ *
+ * To get the label, use the following algorithm:
+ * Lookup "Label" property in the fru node itself. If no
+ * Label found, then traverse superiors (parent nodes) until
+ * a Label property is found.
+ * if not found, then no label
+ */
+static int
+picldiag_get_label(picl_nodehdl_t nodeh, char **label)
+{
+ int err;
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, label);
+
+ while (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL,
+ label);
+ }
+
+ return (err);
+}
+
+/*
+ * get combined label
+ *
+ * like picldiag_get_label, except concatenates the labels of parent locations
+ * eg SB0/P3 for processor P3 on system board SB0
+ *
+ * if caller specifies non-zero label length, label will be cut to specified
+ * length.
+ * negative length is left justified, non-negative length is right justified
+ */
+static int
+picldiag_get_combined_label(picl_nodehdl_t nodeh, char **label, int lablen)
+{
+ int err;
+ char *ptr;
+ char *ptr1 = NULL;
+ char *ptr2;
+ int len;
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr1);
+ if (err != PICL_PROPNOTFOUND && err != PICL_SUCCESS)
+ return (err);
+
+ for (;;) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err == PICL_PROPNOTFOUND)
+ break;
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr);
+ if (err == PICL_SUCCESS) {
+ if (ptr1 == NULL) {
+ ptr1 = ptr;
+ } else {
+ ptr2 = malloc(strlen(ptr1) + strlen(ptr) + 2);
+ if (ptr2 == NULL)
+ return (PICL_FAILURE);
+ (void) strcpy(ptr2, ptr);
+ (void) strcat(ptr2, "/");
+ (void) strcat(ptr2, ptr1);
+ (void) free(ptr);
+ (void) free(ptr1);
+ ptr1 = ptr2;
+ }
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ }
+
+ if (ptr1 == NULL)
+ return (PICL_PROPNOTFOUND);
+
+ len = strlen(ptr1);
+ /* if no string truncation is desired or required */
+ if ((lablen == 0) || (len <= abs(lablen))) {
+ *label = ptr1;
+ return (PICL_SUCCESS);
+ }
+
+ /* string truncation is required; alloc space for (lablen + \0) */
+ ptr = malloc(abs(lablen) + 1);
+ if (ptr == 0)
+ return (PICL_FAILURE);
+ if (lablen > 0) {
+ /* right justification; label = "+<string>\0" */
+ strcpy(ptr, "+");
+ strncat(ptr, ptr1 + len - lablen + 1, lablen + 1);
+ } else {
+ /* left justification; label = "<string>+\0" */
+ strncpy(ptr, ptr1, abs(lablen) - 1);
+ strcat(ptr, "+");
+ }
+
+ *label = ptr;
+ return (PICL_SUCCESS);
+}
+
+/*
+ * return the first compatible value
+ */
+static int
+picldiag_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ char *pval;
+
+ err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE)
+ return (PICL_FAILURE);
+
+ /* get first string from table */
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print the header in the center
+ */
+static void
+logprintf_header(char *header, size_t line_width)
+{
+ size_t start_pos;
+ size_t i;
+
+ log_printf("\n");
+ start_pos = (line_width - strlen(header) - 2) / 2;
+
+ for (i = 0; i < start_pos; i++)
+ log_printf("%s", HEADING_SYMBOL);
+
+ log_printf(" %s ", header);
+
+ for (i = 0; i < start_pos; i++)
+ log_printf("%s", HEADING_SYMBOL);
+
+ log_printf("\n");
+}
+
+/*
+ * print the size
+ */
+static void
+logprintf_size(uint64_t size)
+{
+#define SIZE_FIELD 11
+
+ uint64_t kbyte = 1024;
+ uint64_t mbyte = 1024 * 1024;
+ uint64_t gbyte = 1024 * 1024 * 1024;
+ uint64_t residue;
+ char buf[SIZE_FIELD];
+
+ if (size >= gbyte) {
+ residue = size % gbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dGB",
+ (int)(size / gbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fGB",
+ (float)size / gbyte);
+ } else if (size >= mbyte) {
+ residue = size % mbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dMB",
+ (int)(size / mbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fMB",
+ (float)size / mbyte);
+ } else {
+ residue = size % kbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dKB",
+ (int)(size / kbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fKB",
+ (float)size / kbyte);
+ }
+
+ log_printf("%-10s ", buf);
+}
+
+/*
+ * display platform banner
+ */
+static int
+display_platform_banner(picl_nodehdl_t plafh)
+{
+ char *platform;
+ char *banner_name;
+ int err;
+
+ /*
+ * get PICL_PROP_MACHINE and PICL_PROP_BANNER_NAME
+ */
+ log_printf(SIGN_ON_MSG);
+ err = picldiag_get_string_propval(plafh, PICL_PROP_MACHINE,
+ &platform);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", platform);
+ free(platform);
+
+ err = picldiag_get_string_propval(plafh, OBP_PROP_BANNER_NAME,
+ &banner_name);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", banner_name);
+ free(banner_name);
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+serialnum_callback(picl_nodehdl_t serialh, void *arg)
+{
+ int *countp = arg;
+ int err;
+ picl_nodehdl_t fruph;
+ char *buf;
+
+ err = picl_get_propval_by_name(serialh, PICL_REFPROP_FRU_PARENT,
+ &fruph, sizeof (fruph));
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(serialh,
+ PICL_REFPROP_LOC_PARENT, &fruph, sizeof (fruph));
+ }
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE)
+ return (PICL_WALK_CONTINUE);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(serialh,
+ PICL_PROP_SERIAL_NUMBER, &buf);
+ if (err == PICL_SUCCESS) {
+ log_printf("\n");
+ log_printf(SERIAL_NUM_MSG);
+ log_printf("----------------------\n");
+ log_printf("%s\n", buf);
+ free(buf);
+ return (PICL_WALK_TERMINATE);
+ }
+ return (err);
+}
+
+/*
+ * display the chassis serial number
+ */
+static int
+display_serial_number(picl_nodehdl_t plafh)
+{
+ int print_header;
+
+ picl_walk_tree_by_class(plafh, PICL_CLASS_CHASSIS_SERIAL_NUM,
+ &print_header, serialnum_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * display the clock frequency
+ */
+static int
+display_system_clock(picl_nodehdl_t plafh)
+{
+ uint32_t system_clk;
+ int err;
+
+ err = picldiag_get_clock_freq(plafh, &system_clk);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf(SYSCLK_FREQ_MSG, system_clk);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback function to display the memory size
+ */
+/*ARGSUSED*/
+static int
+memory_callback(picl_nodehdl_t memh, void *args)
+{
+ uint64_t mem_size;
+ int err;
+
+ log_printf(MEM_SIZE_MSG);
+ mem_size = picldiag_get_uint_propval(memh, PICL_PROP_SIZE, &err);
+ if (err == PICL_SUCCESS)
+ logprintf_size(mem_size);
+ log_printf("\n");
+ no_xfer_size = 0;
+ mem_xfersize = picldiag_get_uint_propval(memh, PICL_PROP_TRANSFER_SIZE,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ no_xfer_size = 1;
+ return (PICL_WALK_TERMINATE);
+}
+
+/*
+ * callback function to print cpu information
+ */
+/*ARGSUSED*/
+static int
+cpu_callback(picl_nodehdl_t nodeh, void *args)
+{
+ int err;
+ int id;
+ uint64_t uintval;
+ uint32_t freq;
+ char *impl_name;
+ char *status;
+ picl_prophdl_t parenth;
+ char *label;
+
+ /*
+ * If no ID is found, return
+ */
+ id = picldiag_get_uint_propval(nodeh, PICL_PROP_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-3d ", id);
+
+ /*
+ * If no freq is found, return
+ */
+ err = picldiag_get_clock_freq(nodeh, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%4d MHz ", freq);
+
+ /* Ecache size */
+ uintval = picldiag_get_uint_propval(nodeh, OBP_PROP_ECACHE_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS)
+ logprintf_size(uintval);
+ else
+ return (err);
+
+ /* Implementation */
+ impl_name = NULL;
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_NAME, &impl_name);
+ if (err != PICL_SUCCESS)
+ log_printf(" <unknown> ");
+ else
+ log_printf(" %-22s ", impl_name);
+
+ /* CPU Mask */
+ uintval = picldiag_get_uint_propval(nodeh, OBP_PROP_MASK, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS)
+ log_printf("%2lld.%-2lld ", (uintval >> 4) & 0xf,
+ uintval & 0xf);
+ else
+ return (err);
+
+ /*
+ * Status - if the node has a status property then display that
+ * otherwise display the State property
+ */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s", status);
+ set_exit_code(status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err !=
+ PICL_PROPVALUNAVAILABLE && err != PICL_ENDOFLIST) {
+ return (err);
+ } else {
+ err = picldiag_get_string_propval(nodeh,
+ PICL_PROP_STATE, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s", status);
+ set_exit_code(status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err !=
+ PICL_PROPVALUNAVAILABLE && err !=
+ PICL_ENDOFLIST) {
+ return (err);
+ } else {
+ log_printf("unknown ");
+ }
+ }
+
+ /*
+ * Location: use label of fru parent
+ */
+ err = picldiag_get_fru_parent(nodeh, &parenth);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf(" - ");
+ } else if (err == PICL_SUCCESS) {
+ err = picldiag_get_combined_label(parenth, &label, 12);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS) {
+ log_printf("%s", label);
+ free(label);
+ } else
+ return (err);
+ } else
+ return (err);
+
+ log_printf("\n");
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * display cpu information
+ */
+static int
+display_cpu_info(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision on all the boards.
+ */
+ logprintf_header(dgettext(TEXT_DOMAIN, "CPUs"), DEFAULT_LINE_WIDTH);
+ log_printf(" E$ CPU "
+ "CPU\n");
+ log_printf("CPU Freq Size Implementation "
+ "Mask Status Location\n");
+ log_printf("--- -------- ---------- --------------------- "
+ "----- ------ --------\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
+ cpu_callback);
+ return (err);
+}
+
+/*
+ * Inserts an io_card structure into the list.
+ */
+static void
+add_io_card(uint32_t board, uint32_t bus_id, uint32_t slot, char *label,
+ uint32_t freq, char *name, char *model, char *status, char *devfs_path)
+{
+ struct io_card card;
+
+ card.display = 1;
+ card.board = board;
+ switch (bus_id) {
+ case SBUS_TYPE:
+ strlcpy(card.bus_type, SBUS_NAME, MAXSTRLEN);
+ break;
+ case PCI_TYPE:
+ strlcpy(card.bus_type, PCI_NAME, MAXSTRLEN);
+ break;
+ case PCIEX_TYPE:
+ strlcpy(card.bus_type, PCIEX_NAME, MAXSTRLEN);
+ break;
+ case UPA_TYPE:
+ strlcpy(card.bus_type, UPA_NAME, MAXSTRLEN);
+ break;
+ default: /* won't reach here */
+ strlcpy(card.bus_type, "", MAXSTRLEN);
+ break;
+ }
+ if (label == NULL)
+ card.slot = slot;
+ else {
+ card.slot = PCI_SLOT_IS_STRING;
+ (void) strlcpy(card.slot_str, label, MAXSTRLEN);
+ }
+ card.freq = freq;
+ card.status[0] = '\0';
+ card.name[0] = '\0';
+ card.model[0] = '\0';
+ card.notes[0] = '\0';
+ if (status != NULL)
+ strlcpy(card.status, status, MAXSTRLEN);
+ if (name != NULL)
+ strlcpy(card.name, name, MAXSTRLEN);
+ if (model != NULL)
+ strlcpy(card.model, model, MAXSTRLEN);
+ if (status != NULL)
+ strlcpy(card.status, status, MAXSTRLEN);
+ if (devfs_path != NULL)
+ strlcpy(card.notes, devfs_path, MAXSTRLEN);
+
+ io_card_list = insert_io_card(io_card_list, &card);
+}
+
+static void
+append_to_bank_list(bank_list_t *newptr)
+{
+ bank_list_t *ptr;
+
+ if (mem_banks == NULL) {
+ mem_banks = newptr;
+ return;
+ }
+ ptr = mem_banks;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = newptr;
+}
+
+static void
+free_bank_list(void)
+{
+ bank_list_t *ptr;
+ bank_list_t *tmp;
+
+ for (ptr = mem_banks; ptr != NULL; ptr = tmp) {
+ tmp = ptr->next;
+ free(ptr);
+ }
+ mem_banks = NULL;
+}
+
+
+/*
+ * print label for memory module
+ */
+static int
+logprintf_memory_module_label(picl_nodehdl_t moduleh)
+{
+ picl_nodehdl_t fruparenth;
+ int err;
+ char *label;
+
+ err = picldiag_get_fru_parent(moduleh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-");
+ return (PICL_SUCCESS);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruparenth, &label, 30);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("-");
+ else if (err == PICL_SUCCESS) {
+ log_printf("%-15s", label);
+ free(label);
+ } else
+ return (err);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print the bank id and add the bank handle in the bank list
+ * return the head of the bank list
+ */
+static int
+membank_callback(picl_nodehdl_t bankh, void *args)
+{
+ int err;
+ int64_t id;
+ uint64_t match;
+ uint64_t mask;
+ int i;
+ bank_list_t *newptr;
+ seg_info_t *segp = args;
+
+ /*
+ * print the bank id in the segment table contains column
+ */
+ id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
+ if (segp->bank_count > 0)
+ log_printf(",");
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("-");
+ else if (err == PICL_SUCCESS)
+ log_printf("%-lld", id);
+ else
+ return (err);
+ segp->bank_count++;
+
+ /*
+ * Save the bank information for later (print_bank_table)
+ */
+ newptr = malloc(sizeof (*newptr));
+ if (newptr == NULL)
+ return (PICL_FAILURE);
+
+ newptr->nodeh = bankh;
+ newptr->iway_count = 0;
+ newptr->next = NULL;
+ append_to_bank_list(newptr);
+
+ /*
+ * Compute the way numbers for the bank
+ */
+ if (no_xfer_size)
+ return (PICL_WALK_CONTINUE);
+
+ match = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMATCH, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ mask = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMASK, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ i = 0;
+ while ((i < segp->ifactor) && (newptr->iway_count < MAX_IWAYS)) {
+ if (((segp->base + i * mem_xfersize) & mask) == match)
+ newptr->iway[newptr->iway_count++] = i;
+ ++i;
+ }
+ return (PICL_WALK_CONTINUE);
+}
+
+
+/*
+ * find the memory bank and add the bank handle in the bank list
+ * return the head of the bank list
+ */
+static int
+logprintf_bankinfo(picl_nodehdl_t segh, seg_info_t *segp)
+{
+ int err;
+
+ log_printf("BankIDs ");
+ /*
+ * find memory-bank
+ */
+ segp->bank_count = 0;
+ err = picl_walk_tree_by_class(segh, PICL_CLASS_MEMORY_BANK, segp,
+ membank_callback);
+ log_printf("\n");
+ return (err);
+}
+
+/*
+ * print the label of memory module or the memory module bank ids
+ */
+static int
+logprintf_seg_contains_col(picl_nodehdl_t nodeh, seg_info_t *segp)
+{
+ picl_nodehdl_t moduleh;
+ int err;
+
+ /*
+ * find memory-module if referenced directly from the memory-segment
+ * (ie no memory banks)
+ */
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_MEMORY_MODULE,
+ &moduleh, sizeof (moduleh));
+ if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
+ return (err);
+ if (err == PICL_SUCCESS) {
+ err = logprintf_memory_module_label(moduleh);
+ log_printf("\n");
+ return (err);
+ }
+
+ /*
+ * memory-module not referenced directly from the memory segment
+ * so list memory banks instead
+ */
+ err = logprintf_bankinfo(nodeh, segp);
+ return (err);
+}
+
+/*
+ * find all memory modules under the given memory module group
+ * and print its label
+ */
+static int
+logprintf_memory_module_group_info(picl_nodehdl_t memgrph, uint64_t mcid)
+{
+ int err;
+ int64_t id;
+ boolean_t got_status;
+ picl_nodehdl_t moduleh;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ picl_nodehdl_t fruparenth;
+ char *status;
+
+ id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ id = -1;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(memgrph, PICL_PROP_CHILD, &moduleh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ /* controller id */
+ log_printf("%-8lld ", mcid);
+
+ /* group id */
+ if (id == -1) {
+ log_printf("- ");
+ } else {
+ log_printf("%-8lld ", id);
+ }
+
+ err = picl_get_propval_by_name(moduleh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE) == 0) {
+ err = logprintf_memory_module_label(moduleh);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ got_status = B_FALSE;
+ err = picldiag_get_fru_parent(moduleh, &fruparenth);
+ if (err == PICL_SUCCESS) {
+ err = picldiag_get_string_propval(fruparenth,
+ PICL_PROP_OPERATIONAL_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ got_status = B_TRUE;
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ if (!got_status) {
+ err = picldiag_get_string_propval(moduleh,
+ PICL_PROP_STATUS, &status);
+ if (err == PICL_SUCCESS)
+ got_status = B_TRUE;
+ else if (err != PICL_PROPNOTFOUND)
+ return (err);
+ }
+ if (got_status) {
+ log_printf("%s", status);
+ set_exit_code(status);
+ free(status);
+ }
+ err = picl_get_propval_by_name(moduleh, PICL_PROP_PEER,
+ &moduleh, sizeof (picl_nodehdl_t));
+
+ log_printf("\n");
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * search children to find memory module group under memory-controller
+ */
+static int
+find_memory_module_group(picl_nodehdl_t mch, int *print_header)
+{
+ picl_nodehdl_t memgrph;
+ uint64_t mcid;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+
+ mcid = picldiag_get_uint_propval(mch, OBP_PROP_PORTID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ mcid = DEFAULT_PORTID;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(mch, PICL_PROP_CHILD,
+ &memgrph, sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(memgrph,
+ PICL_PROP_CLASSNAME, piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE_GROUP) == 0) {
+ if (*print_header == 1) {
+ log_printf(
+ dgettext(TEXT_DOMAIN,
+ "\nMemory Module Groups:\n"));
+ log_printf("--------------------------");
+ log_printf("------------------------\n");
+ log_printf("ControllerID GroupID Labels");
+ log_printf(" Status\n");
+ log_printf("--------------------------");
+ log_printf("------------------------\n");
+ *print_header = 0;
+ }
+ err = logprintf_memory_module_group_info(memgrph, mcid);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(memgrph, PICL_PROP_PEER,
+ &memgrph, sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * print memory module group table per memory-controller
+ */
+static int
+print_memory_module_group_table(picl_nodehdl_t plafh)
+{
+ picl_nodehdl_t mch;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ int print_header;
+
+ print_header = 1;
+
+ /*
+ * find memory-controller
+ */
+ err = picl_get_propval_by_name(plafh, PICL_PROP_CHILD, &mch,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(mch, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_CONTROLLER) != 0) {
+ err = print_memory_module_group_table(mch);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
+ &mch, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ err = find_memory_module_group(mch, &print_header);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
+ &mch, sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+
+ return (err);
+}
+
+/*
+ * print bank table
+ */
+static int
+print_bank_table(void)
+{
+ bank_list_t *ptr;
+ picl_nodehdl_t bankh;
+ picl_nodehdl_t memgrph;
+ picl_nodehdl_t mch;
+ int err;
+ int32_t i;
+ uint64_t size;
+ int id;
+
+ log_printf(dgettext(TEXT_DOMAIN, "\nBank Table:\n"));
+ log_printf("---------------------------------------");
+ log_printf("--------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, " Physical Location\n"));
+ log_printf(dgettext(TEXT_DOMAIN, "ID ControllerID GroupID "));
+ log_printf(dgettext(TEXT_DOMAIN, "Size Interleave Way\n"));
+ log_printf("---------------------------------------");
+ log_printf("--------------------\n");
+
+ for (ptr = mem_banks; ptr != NULL; ptr = ptr->next) {
+ bankh = ptr->nodeh;
+ id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
+ if (err != PICL_SUCCESS)
+ log_printf("%-8s ", "-");
+ else
+ log_printf("%-8d ", id);
+
+ /* find memory-module-group */
+ err = picl_get_propval_by_name(bankh,
+ PICL_REFPROP_MEMORY_MODULE_GROUP, &memgrph,
+ sizeof (memgrph));
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("%-8s ", "-");
+ log_printf("%-8s ", "-");
+ } else if (err != PICL_SUCCESS)
+ return (err);
+ else {
+ /*
+ * get controller id
+ */
+ err = picl_get_propval_by_name(memgrph,
+ PICL_PROP_PARENT, &mch, sizeof (picl_nodehdl_t));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ id = picldiag_get_uint_propval(mch, OBP_PROP_PORTID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ id = DEFAULT_PORTID; /* use default */
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-8d ", id);
+
+ /* get group id */
+ id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("- ");
+ else if (err == PICL_SUCCESS)
+ log_printf("%-8d ", id);
+ else
+ return (err);
+ }
+
+ size = picldiag_get_uint_propval(bankh, PICL_PROP_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("- ");
+ else if (err == PICL_SUCCESS)
+ logprintf_size(size);
+ else
+ return (err);
+
+ log_printf(" ");
+ for (i = 0; i < ptr->iway_count; i++) {
+ if (i != 0)
+ log_printf(",");
+ log_printf("%d", ptr->iway[i]);
+ }
+
+ log_printf("\n");
+ }
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback function to print segment, add the bank in the list and
+ * return the bank list
+ */
+/* ARGSUSED */
+static int
+memseg_callback(picl_nodehdl_t segh, void *args)
+{
+ seg_info_t seginfo;
+ int err;
+
+ /* get base address */
+ seginfo.base = picldiag_get_uint_propval(segh, PICL_PROP_BASEADDRESS,
+ &err);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ log_printf("0x%-16llx ", seginfo.base);
+ else
+ return (err);
+
+ /* get size */
+ seginfo.size = picldiag_get_uint_propval(segh, PICL_PROP_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ logprintf_size(seginfo.size);
+ else
+ return (err);
+
+ /* get interleave factor */
+ seginfo.ifactor = picldiag_get_uint_propval(segh,
+ PICL_PROP_INTERLEAVE_FACTOR, &err);
+
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf(" -\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ log_printf(" %-2d ", seginfo.ifactor);
+ else
+ return (err);
+
+ seginfo.bank_count = 0;
+ err = logprintf_seg_contains_col(segh, &seginfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * search children to find memory-segment and set up the bank list
+ */
+static int
+find_segments(picl_nodehdl_t plafh)
+{
+ int err;
+
+ log_printf(dgettext(TEXT_DOMAIN, "Segment Table:\n"));
+ log_printf("------------------------------");
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Base Address Size "));
+ log_printf(dgettext(TEXT_DOMAIN, "Interleave Factor Contains\n"));
+ log_printf("------------------------------");
+ log_printf("-----------------------------------------\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
+ NULL, memseg_callback);
+ return (err);
+}
+
+/*
+ * display memory configuration
+ */
+static int
+display_memory_config(picl_nodehdl_t plafh)
+{
+ int err;
+
+ logprintf_header(dgettext(TEXT_DOMAIN, "Memory Configuration"),
+ DEFAULT_LINE_WIDTH);
+
+ mem_banks = NULL;
+ err = find_segments(plafh);
+
+ if ((err == PICL_SUCCESS) && (mem_banks != NULL))
+ print_bank_table();
+
+ free_bank_list();
+
+ return (print_memory_module_group_table(plafh));
+}
+
+/*
+ * print the hub device
+ */
+static int
+logprintf_hub_devices(picl_nodehdl_t hubh)
+{
+ char *name;
+ int portnum;
+ char *labelp;
+ picl_nodehdl_t parenth;
+ int err;
+
+ err = picldiag_get_string_propval(hubh, PICL_PROP_NAME, &name);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-12.12s ", name);
+ free(name);
+
+ err = picl_get_propval_by_name(hubh, PICL_REFPROP_LOC_PARENT, &parenth,
+ sizeof (picl_nodehdl_t));
+
+ if (err == PICL_SUCCESS) {
+ /* Read the Label */
+ err = picldiag_get_label(parenth, &labelp);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s\n", labelp);
+ free(labelp);
+ return (PICL_SUCCESS);
+ } else if (err != PICL_PROPNOTFOUND) {
+ log_printf("\n");
+ return (err);
+ }
+ } else if (err != PICL_PROPNOTFOUND) {
+ log_printf("\n");
+ return (err);
+ }
+
+ /* No Label, try the reg */
+ err = picl_get_propval_by_name(hubh, OBP_PROP_REG, &portnum,
+ sizeof (portnum));
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" -\n");
+ else if (err != PICL_SUCCESS) {
+ log_printf("\n");
+ return (err);
+ } else
+ log_printf("%3d\n", portnum);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback functions to display hub devices
+ */
+/* ARGSUSED */
+static int
+print_usb_devices(picl_nodehdl_t hubh, void *arg)
+{
+ picl_nodehdl_t chdh;
+ char *rootname;
+ int type = *(int *)arg;
+ int hubnum;
+ int err;
+
+ err = picl_get_propval_by_name(hubh, PICL_PROP_CHILD, &chdh,
+ sizeof (picl_nodehdl_t));
+
+ /* print header */
+ if (err == PICL_SUCCESS) {
+ err = picldiag_get_string_propval(hubh, PICL_PROP_NAME,
+ &rootname);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (type == USB) {
+ log_printf("\n===============================");
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s Devices "), rootname);
+ } else {
+ /* Get its hub number */
+ err = picl_get_propval_by_name(hubh,
+ OBP_PROP_REG, &hubnum, sizeof (hubnum));
+ if ((err != PICL_SUCCESS) &&
+ (err != PICL_PROPNOTFOUND)) {
+ free(rootname);
+ return (err);
+ }
+
+ log_printf("\n===============================");
+ if (err == PICL_SUCCESS)
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s#%d Devices "),
+ rootname, hubnum);
+ else
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s Devices "), rootname);
+ }
+
+ log_printf("===============================\n\n");
+ log_printf("Name Port#\n");
+ log_printf("------------ -----\n");
+ free(rootname);
+
+ do {
+ logprintf_hub_devices(chdh);
+
+ err = picl_get_propval_by_name(chdh, PICL_PROP_PEER,
+ &chdh, sizeof (picl_nodehdl_t));
+ } while (err == PICL_SUCCESS);
+ }
+
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback functions to display usb devices
+ */
+/* ARGSUSED */
+static int
+usb_callback(picl_nodehdl_t usbh, void *args)
+{
+ int err;
+ int type;
+
+ type = USB;
+ err = print_usb_devices(usbh, &type);
+ if (err != PICL_WALK_CONTINUE)
+ return (err);
+ type = HUB;
+ err = picl_walk_tree_by_class(usbh, NULL, &type, print_usb_devices);
+ if (err == PICL_SUCCESS)
+ err = PICL_WALK_CONTINUE;
+ return (err);
+}
+
+
+/*
+ * find usb devices and print its information
+ */
+static int
+display_usb_devices(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * get the usb node
+ */
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_USB, NULL,
+ usb_callback);
+ return (err);
+}
+
+
+
+/*
+ * If nodeh is the io device, add it into the io list and return
+ * If it is not an io device and it has the subtree, traverse the subtree
+ * and add all leaf io devices
+ */
+static int
+add_io_leaves(picl_nodehdl_t nodeh, char *parentname, uint32_t board,
+ uint32_t bus_id, uint64_t slot, uint32_t freq, char *model, char *status)
+{
+ picl_nodehdl_t childh;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int err;
+ char *nameval;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char nodename[MAXSTRLEN];
+ char name[MAXSTRLEN];
+ char *devfs_path;
+ char *compatible;
+ picl_nodehdl_t fruparenth;
+ char *label;
+ char binding_name[MAXSTRLEN];
+
+ err = picl_get_propinfo_by_name(nodeh, PICL_PROP_NAME, &pinfo,
+ &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ nameval = alloca(pinfo.size);
+ if (nameval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, nameval, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ (void) strlcpy(nodename, nameval, MAXSTRLEN);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /* if binding_name is found, name will be <nodename>-<binding_name> */
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+ binding_name, sizeof (binding_name));
+ if (err == PICL_PROPNOTFOUND) {
+ /*
+ * if compatible prop is found, name will be
+ * <nodename>-<compatible>
+ */
+ err = picldiag_get_first_compatible_value(nodeh, &compatible);
+ if (err == PICL_SUCCESS) {
+ strlcat(nodename, "-", MAXSTRLEN);
+ strlcat(nodename, compatible, MAXSTRLEN);
+ free(compatible);
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else if (strcmp(nodename, binding_name) != 0) {
+ if (strcmp(nodename, piclclass) == 0) {
+ /*
+ * nodename same as binding name -
+ * no need to display twice
+ */
+ strlcpy(nodename, binding_name, MAXSTRLEN);
+ } else {
+ strlcat(nodename, "-", MAXSTRLEN);
+ strlcat(nodename, binding_name, MAXSTRLEN);
+ }
+ }
+
+ /*
+ * If it is an immediate child under pci/pciex/sbus/upa and not
+ * a bus node, add it to the io list.
+ * If it is a child under sub-bus and it is in an io
+ * device, add it to the io list.
+ */
+ if (((parentname == NULL) && (!is_bus(piclclass))) ||
+ ((parentname != NULL) && (is_io_device(piclclass)))) {
+ if (parentname == NULL)
+ (void) snprintf(name, MAXSTRLEN, "%s", nodename);
+ else
+ (void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
+ nodename);
+
+ /*
+ * append the class if its class is not a generic
+ * obp-device class
+ */
+ if (strcmp(piclclass, PICL_CLASS_OBP_DEVICE))
+ (void) snprintf(name, MAXSTRLEN, "%s (%s)", name,
+ piclclass);
+
+ err = picldiag_get_fru_parent(nodeh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ label = NULL;
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ err = picldiag_get_combined_label(fruparenth, &label,
+ 15);
+ if (err == PICL_PROPNOTFOUND)
+ label = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+ }
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH,
+ &devfs_path);
+ if (err == PICL_PROPNOTFOUND)
+ devfs_path = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ add_io_card(board, bus_id, slot, label, freq, name,
+ model, status, devfs_path);
+ if (label != NULL)
+ free(label);
+ if (devfs_path != NULL)
+ free(devfs_path);
+ return (PICL_SUCCESS);
+ }
+
+ /*
+ * If there is any child, Go through each child.
+ */
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
+ &childh, sizeof (picl_nodehdl_t));
+
+ /* there is a child */
+ while (err == PICL_SUCCESS) {
+ if (parentname == NULL)
+ (void) strlcpy(name, nodename, MAXSTRLEN);
+ else
+ (void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
+ nodename);
+
+ err = add_io_leaves(childh, name, board, bus_id, slot, freq,
+ model, status);
+ if (err != PICL_SUCCESS)
+ return (err);
+ /*
+ * get next child
+ */
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * callback function to add all io devices under sbus in io list
+ */
+/*ARGSUSED*/
+static int
+sbus_callback(picl_nodehdl_t sbush, void *args)
+{
+ picl_nodehdl_t nodeh;
+ int err;
+ uint32_t boardnum;
+ uint32_t bus_id;
+ uint32_t slot;
+ uint32_t freq;
+ char *model;
+ char *status;
+
+ /* Fill in common infomation */
+ bus_id = SBUS_TYPE;
+
+ err = picldiag_get_clock_freq(sbush, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ /*
+ * If no board# is found, set boardnum to 0
+ */
+ boardnum = picldiag_get_uint_propval(sbush, OBP_PROP_BOARD_NUM, &err);
+ if (err == PICL_PROPNOTFOUND)
+ boardnum = DEFAULT_BOARD_NUM;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(sbush, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ slot = picldiag_get_uint_propval(nodeh,
+ PICL_PROP_SLOT, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS,
+ &status);
+ if (err == PICL_PROPNOTFOUND) {
+ status = malloc(5);
+ if (status == NULL)
+ return (PICL_FAILURE);
+ strncpy(status, "okay", 5);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = add_io_leaves(nodeh, NULL, boardnum, bus_id, slot, freq,
+ model, status);
+ if (model != NULL)
+ free(model);
+ if (status != NULL)
+ free(status);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * add all io devices under pci/pciex in io list
+ */
+/* ARGSUSED */
+static int
+pci_pciex_callback(picl_nodehdl_t pcih, void *args)
+{
+ picl_nodehdl_t nodeh;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ uint32_t boardnum;
+ uint32_t bus_id;
+ uint32_t slot;
+ uint32_t freq;
+ char *model;
+ char *status;
+
+ if (strcmp(args, PICL_CLASS_PCIEX) == 0)
+ bus_id = PCIEX_TYPE;
+ else
+ bus_id = PCI_TYPE;
+
+ /*
+ * Check if it has the freq, if not,
+ * If not, use its parent's freq
+ * if its parent's freq is not found, return
+ */
+ err = picldiag_get_clock_freq(pcih, &freq);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picldiag_get_clock_from_parent(pcih, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If no board# is found, set boardnum to 0
+ */
+ boardnum = picldiag_get_uint_propval(pcih, OBP_PROP_BOARD_NUM, &err);
+ if (err == PICL_PROPNOTFOUND)
+ boardnum = DEFAULT_BOARD_NUM;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Walk through the children */
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Skip PCIEX, PCI bridge and USB devices because they will be
+ * processed later
+ */
+ if ((strcmp(piclclass, PICL_CLASS_PCI) == 0) ||
+ (strcmp(piclclass, PICL_CLASS_PCIEX) == 0) ||
+ (strcmp(piclclass, PICL_CLASS_USB) == 0)) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ /* Get the device id for pci card */
+ slot = picldiag_get_uint_propval(nodeh,
+ PICL_PROP_DEVICE_ID, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Get the model of this card */
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS,
+ &status);
+ if (err == PICL_PROPNOTFOUND) {
+ status = malloc(5);
+ if (status == NULL)
+ return (PICL_FAILURE);
+ strncpy(status, "okay", 5);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = add_io_leaves(nodeh, NULL, boardnum, bus_id, slot,
+ freq, model, status);
+
+ if (model != NULL)
+ free(model);
+
+ if (status != NULL)
+ free(status);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+
+ return (err);
+}
+
+/*
+ * add io devices in io list
+ * Its slot number is drived from upa-portid
+ */
+static int
+add_io_devices(picl_nodehdl_t nodeh)
+{
+ int err;
+ uint64_t board_type;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char name[MAXSTRLEN];
+ char *devfs_path;
+ char *nameval;
+ uint32_t boardnum;
+ uint32_t bus_id;
+ uint32_t slot;
+ uint32_t freq;
+ char *model;
+ char *status;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_nodehdl_t fruparenth;
+ char *label;
+
+
+ bus_id = UPA_TYPE;
+
+ /*
+ * If clock frequency can't be found from its parent, don't add
+ */
+ err = picldiag_get_clock_from_parent(nodeh, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If no board# is found, set boardnum to 0
+ */
+ boardnum = picldiag_get_uint_propval(nodeh, OBP_PROP_BOARD_NUM, &err);
+ if (err == PICL_PROPNOTFOUND)
+ boardnum = DEFAULT_BOARD_NUM;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * get upa portid as slot number
+ * If upa portid is not found, don't add the card.
+ */
+ slot = picldiag_get_uint_propval(nodeh, OBP_PROP_UPA_PORTID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Get the model of this card */
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL, &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * check if it is a ffb device
+ * If it's a ffb device, append its board type to name
+ * otherwise, use its nodename
+ */
+ err = picl_get_prop_by_name(nodeh, PICL_PROP_FFB_BOARD_REV, &proph);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propinfo_by_name(nodeh, PICL_PROP_NAME,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ nameval = alloca(pinfo.size);
+ if (nameval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, nameval, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ (void) strlcpy(name, nameval, MAXSTRLEN);
+ } else if (err == PICL_SUCCESS) {
+ /* Find out if it's single or double buffered */
+ board_type = picldiag_get_uint_propval(nodeh,
+ OBP_PROP_BOARD_TYPE, &err);
+ if (err == PICL_PROPNOTFOUND)
+ (void) strlcpy(name, FFB_NAME, sizeof (name));
+ if (err == PICL_SUCCESS) {
+ if (board_type & FFB_B_BUFF)
+ (void) strlcpy(name, FFB_DOUBLE_BUF,
+ sizeof (name));
+ else
+ (void) strlcpy(name, FFB_SINGLE_BUF,
+ sizeof (name));
+ } else
+ return (err);
+ } else
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ (void) snprintf(name, sizeof (name), "%s (%s)", name, piclclass);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND) {
+ status = malloc(5);
+ if (status == NULL)
+ return (PICL_FAILURE);
+ strncpy(status, "okay", 5);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_fru_parent(nodeh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ label = NULL;
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ err = picldiag_get_combined_label(fruparenth, &label, 15);
+ if (err == PICL_PROPNOTFOUND)
+ label = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+ }
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH,
+ &devfs_path);
+ if (err == PICL_PROPNOTFOUND)
+ devfs_path = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ add_io_card(boardnum, bus_id, slot, label, freq, name, model, status,
+ devfs_path);
+ if (label != NULL)
+ free(label);
+ if (model != NULL)
+ free(model);
+ if (status != NULL)
+ free(status);
+ if (devfs_path != NULL)
+ free(devfs_path);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * loop through all children and add io devices in io list
+ */
+static int
+process_io_leaves(picl_nodehdl_t rooth)
+{
+ picl_nodehdl_t nodeh;
+ char classval[PICL_CLASSNAMELEN_MAX];
+ int err;
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ classval, sizeof (classval));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (is_io_device(classval))
+ err = add_io_devices(nodeh);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+
+ return (err);
+}
+
+/*
+ * callback function to add all io devices under upa in io list
+ */
+/*ARGSUSED*/
+static int
+upa_callback(picl_nodehdl_t upah, void *args)
+{
+ int err;
+
+ err = process_io_leaves(upah);
+
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * display ffb hardware configuration
+ */
+/* ARGSUSED */
+static int
+ffbconfig_callback(picl_nodehdl_t ffbh, void *arg)
+{
+ int err;
+ uint64_t board_rev;
+ uint64_t fbc_ver;
+ char *dac_ver;
+ char *fbram_ver;
+
+ /*
+ * If it has PICL_PROP_FFB_BOARD_REV, it is a ffb device
+ * Otherwise, return.
+ */
+ board_rev = picldiag_get_uint_propval(ffbh, PICL_PROP_FFB_BOARD_REV,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("FFB Hardware Configuration:\n");
+ log_printf("-----------------------------------\n");
+ log_printf("Board rev: %lld\n", board_rev);
+
+ fbc_ver = picldiag_get_uint_propval(ffbh, OBP_PROP_FBC_REG_ID,
+ &err);
+ if (err == PICL_SUCCESS)
+ log_printf("FBC version: 0x%llx\n", fbc_ver);
+ else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picldiag_get_string_propval(ffbh, PICL_PROP_FFB_DAC_VER,
+ &dac_ver);
+ if (err == PICL_SUCCESS) {
+ log_printf("DAC: %s\n", dac_ver);
+ free(dac_ver);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picldiag_get_string_propval(ffbh, PICL_PROP_FFB_FBRAM_VER,
+ &fbram_ver);
+ if (err == PICL_SUCCESS) {
+ log_printf("3DRAM: %s\n", fbram_ver);
+ free(fbram_ver);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ log_printf("\n");
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * find all io devices and add them in the io list
+ */
+static int
+gather_io_cards(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * look for io devices under the immediate children of platform
+ */
+ err = process_io_leaves(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_SBUS,
+ PICL_CLASS_SBUS, sbus_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
+ PICL_CLASS_PCI, pci_pciex_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX,
+ PICL_CLASS_PCIEX, pci_pciex_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_UPA,
+ PICL_CLASS_UPA, upa_callback);
+
+ return (err);
+}
+
+static void
+picldiag_display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == 0) {
+ log_printf("Bus Freq Slot + Name +\n", 0);
+ log_printf("Type MHz Status Path"
+ " Model", 0);
+ log_printf("\n", 0);
+ log_printf("------ ---- ---------- "
+ "---------------------------- "
+ "--------------------", 0);
+ log_printf("\n", 0);
+ banner = 1;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf("%-6s ", p->bus_type, 0);
+ log_printf("%-3d ", p->freq, 0);
+ /*
+ * We check to see if it's an int or
+ * a char string to display for slot.
+ */
+ if (p->slot == PCI_SLOT_IS_STRING)
+ log_printf("%-10s ", p->slot_str, 0);
+ else
+ log_printf("%-10d ", p->slot, 0);
+
+ log_printf("%-28.28s", p->name, 0);
+ if (strlen(p->name) > 28)
+ log_printf("+ ", 0);
+ else
+ log_printf(" ", 0);
+ log_printf("%-19.19s", p->model, 0);
+ if (strlen(p->model) > 19)
+ log_printf("+", 0);
+ log_printf("\n", 0);
+ log_printf(" %-10s ", p->status, 0);
+ set_exit_code(p->status);
+ if (strlen(p->notes) > 0)
+ log_printf("%s", p->notes, 0);
+ log_printf("\n\n", 0);
+ }
+}
+
+/*
+ * display all io devices
+ */
+static int
+display_io_device_info(picl_nodehdl_t plafh)
+{
+ int err;
+
+ err = gather_io_cards(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ logprintf_header(dgettext(TEXT_DOMAIN, "IO Devices"),
+ DEFAULT_LINE_WIDTH);
+
+ picldiag_display_io_cards(io_card_list);
+
+ free_io_cards(io_card_list);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print fan device information
+ */
+static int
+logprintf_fan_info(picl_nodehdl_t fanh)
+{
+ int err;
+ char *label;
+ char *unit;
+ int64_t speed;
+ int64_t min_speed;
+ picl_nodehdl_t fruph;
+
+ err = picldiag_get_fru_parent(fanh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 20);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-20s ", label);
+ free(label);
+
+ err = picldiag_get_label(fanh, &label);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-14s ", label);
+ free(label);
+ } else if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" - ");
+ } else
+ return (err);
+
+ speed = picldiag_get_uint_propval(fanh, PICL_PROP_FAN_SPEED, &err);
+ if (err == PICL_SUCCESS) {
+ min_speed = picldiag_get_uint_propval(fanh,
+ PICL_PROP_LOW_WARNING_THRESHOLD, &err);
+ if (err != PICL_SUCCESS)
+ min_speed = 0;
+ if (speed < min_speed) {
+ log_printf("failed (%lld", speed);
+ err = picldiag_get_string_propval(fanh,
+ PICL_PROP_FAN_SPEED_UNIT, &unit);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", unit);
+ free(unit);
+ }
+ log_printf(")");
+ exit_code = PD_SYSTEM_FAILURE;
+ } else {
+ log_printf("okay");
+ }
+ } else {
+ err = picldiag_get_string_propval(fanh,
+ PICL_PROP_FAN_SPEED_UNIT, &unit);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s ", unit);
+ free(unit);
+ }
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+fan_callback(picl_nodehdl_t fanh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+ log_printf(dgettext(TEXT_DOMAIN, "Fan Status:\n"));
+ log_printf("-------------------------------------------\n");
+ log_printf("Location Sensor Status\n");
+ log_printf("-------------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_fan_info(fanh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find fan device and print its speed
+ */
+static int
+display_fan_speed(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_FAN,
+ &print_header, fan_callback);
+ return (err);
+}
+
+/*
+ * print temperature sensor information
+ */
+static int
+logprintf_temp_info(picl_nodehdl_t temph)
+{
+ int err;
+ char *label;
+ int64_t temperature;
+ int64_t threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_temp = 0;
+
+ err = picldiag_get_fru_parent(temph, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 14);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-14s ", label);
+ free(label);
+
+ err = picldiag_get_label(temph, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-19s ", label);
+ free(label);
+
+ temperature = picldiag_get_int_propval(temph, PICL_PROP_TEMPERATURE,
+ &err);
+ if (err == PICL_SUCCESS) {
+ got_temp = 1;
+ status = "okay";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(temph, PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", status);
+ set_exit_code(status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ set_exit_code(status);
+ if (strcmp(status, "failed") == 0 ||
+ strcmp(status, "warning") == 0)
+ log_printf("(%.2lldC)", temperature);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+temp_callback(picl_nodehdl_t temph, void *arg)
+{
+ int err;
+ int *countp = arg;
+
+ if (*countp == 0) {
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Temperature sensors:\n"));
+ log_printf("-----------------------------------------\n");
+ log_printf("Location Sensor Status\n");
+ log_printf("-----------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_temp_info(temph);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find temp sensors and print the temp
+ */
+/* ARGSUSED */
+static int
+display_temp(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_SENSOR,
+ &print_header, temp_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_INDICATOR,
+ &print_header, temp_callback);
+ return (err);
+}
+
+/*
+ * print current sensor information
+ */
+static int
+logprintf_current_info(picl_nodehdl_t currenth)
+{
+ int err;
+ char *label;
+ float current;
+ float threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_current = 0;
+
+ err = picldiag_get_fru_parent(currenth, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 20);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-20s ", label);
+ free(label);
+
+ err = picldiag_get_label(currenth, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-10s ", label);
+ free(label);
+
+ current = picldiag_get_float_propval(currenth, PICL_PROP_CURRENT, &err);
+ if (err == PICL_SUCCESS) {
+ status = "okay";
+ got_current = 1;
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth,
+ PICL_PROP_HIGH_SHUTDOWN, &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(currenth,
+ PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf(" %s", status);
+ set_exit_code(status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ set_exit_code(status);
+ if (strcmp(status, "failed") == 0 ||
+ strcmp(status, "warning") == 0)
+ log_printf("(%.2fA)", current);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+current_callback(picl_nodehdl_t currh, void *arg)
+{
+ int err;
+ int *countp = arg;
+
+ if (*countp == 0) {
+ log_printf("------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Current sensors:\n"));
+ log_printf("----------------------------------------\n");
+ log_printf("Location Sensor Status\n");
+ log_printf("----------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_current_info(currh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find curr sensors and print the curr
+ */
+/* ARGSUSED */
+static int
+display_current(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_SENSOR,
+ &print_header, current_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_INDICATOR,
+ &print_header, current_callback);
+ return (err);
+}
+
+/*
+ * print voltage sensor information
+ */
+static int
+logprintf_voltage_info(picl_nodehdl_t voltageh)
+{
+ int err;
+ char *label;
+ float voltage;
+ float threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_voltage = 0;
+
+ err = picldiag_get_fru_parent(voltageh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 14);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-14s ", label);
+ free(label);
+
+ err = picldiag_get_label(voltageh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-12s ", label);
+ free(label);
+
+ voltage = picldiag_get_float_propval(voltageh, PICL_PROP_VOLTAGE, &err);
+ if (err == PICL_SUCCESS) {
+ status = "okay";
+ got_voltage = 1;
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh,
+ PICL_PROP_HIGH_SHUTDOWN, &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(voltageh,
+ PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", status);
+ set_exit_code(status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ set_exit_code(status);
+ if (strcmp(status, "warning") == 0 ||
+ strcmp(status, "failed") == 0)
+ log_printf("(%.2fV)", voltage);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+voltage_callback(picl_nodehdl_t voltageh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+ log_printf("------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Voltage sensors:\n"));
+ log_printf("-----------------------------------\n");
+ log_printf("Location Sensor Status\n");
+ log_printf("-----------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_voltage_info(voltageh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find voltage sensors and print voltage
+ */
+/* ARGSUSED */
+static int
+display_voltage(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_SENSOR,
+ &print_header, voltage_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_INDICATOR,
+ &print_header, voltage_callback);
+ return (err);
+}
+
+/*
+ * print led device information
+ */
+static int
+logprintf_led_info(picl_nodehdl_t ledh)
+{
+ int err;
+ char *label;
+ char *state;
+ char *color;
+ picl_nodehdl_t fruph;
+
+ err = picldiag_get_fru_parent(ledh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 22);
+ if (err != PICL_SUCCESS) {
+ log_printf(" - ", label);
+ } else {
+ log_printf("%-22s ", label);
+ free(label);
+ }
+
+ err = picldiag_get_label(ledh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-20s ", label);
+ free(label);
+
+ err = picldiag_get_string_propval(ledh, PICL_PROP_STATE, &state);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" - ");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%-10s ", state);
+ free(state);
+ }
+
+ err = picldiag_get_string_propval(ledh, PICL_PROP_COLOR, &color);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf("\n");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%-16s\n", color);
+ free(color);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+static int
+led_callback(picl_nodehdl_t ledh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+
+ log_printf("--------------------------------------"
+ "------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Led State:\n"));
+ log_printf("----------------------------------------"
+ "----------------------\n");
+ log_printf("Location Led State"
+ " Color\n");
+ log_printf("----------------------------------------"
+ "----------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_led_info(ledh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find led devices and print status
+ */
+/* ARGSUSED */
+static int
+display_led_status(picl_nodehdl_t plafh)
+{
+ int print_header;
+
+ print_header = 0;
+ picl_walk_tree_by_class(plafh, PICL_CLASS_LED,
+ &print_header, led_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print keyswitch device information
+ */
+static int
+logprintf_keyswitch_info(picl_nodehdl_t keyswitchh, picl_nodehdl_t fruph)
+{
+ int err;
+ char *label;
+ char *state;
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS) {
+ log_printf("%-14s", " -");
+ } else {
+ log_printf("%-14s ", label);
+ free(label);
+ }
+
+ err = picldiag_get_label(keyswitchh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-11s ", label);
+ free(label);
+
+ err = picldiag_get_string_propval(keyswitchh, PICL_PROP_STATE, &state);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" -\n");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%s\n", state);
+ free(state);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+static int
+keyswitch_callback(picl_nodehdl_t keyswitchh, void *arg)
+{
+ int *countp = arg;
+ int err;
+ picl_nodehdl_t fruph;
+
+ /*
+ * Tamale simulates a key-switch on ENxS. So the presence of a
+ * node of class keyswitch is not sufficient. If it has a fru parent
+ * or location parent, then believe it.
+ */
+ err = picl_get_propval_by_name(keyswitchh, PICL_REFPROP_FRU_PARENT,
+ &fruph, sizeof (fruph));
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(keyswitchh,
+ PICL_REFPROP_LOC_PARENT, &fruph, sizeof (fruph));
+ }
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE)
+ return (PICL_WALK_CONTINUE);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (*countp == 0) {
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Keyswitch:\n"));
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Keyswitch State\n"));
+ log_printf("-----------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_keyswitch_info(keyswitchh, fruph);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * search children to find keyswitch device(s) and print status
+ */
+/* ARGSUSED */
+static int
+display_keyswitch(picl_nodehdl_t plafh)
+{
+ int print_header = 0;
+
+ picl_walk_tree_by_class(plafh, PICL_CLASS_KEYSWITCH,
+ &print_header, keyswitch_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * display environment status
+ */
+static int
+display_envctrl_status(picl_nodehdl_t plafh)
+{
+ logprintf_header(dgettext(TEXT_DOMAIN, "Environmental Status"),
+ DEFAULT_LINE_WIDTH);
+
+ display_fan_speed(plafh);
+ display_temp(plafh);
+ display_current(plafh);
+ display_voltage(plafh);
+ display_keyswitch(plafh);
+ display_led_status(plafh);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print fru operational status
+ */
+static int
+logprintf_fru_oper_status(picl_nodehdl_t fruh, int *countp)
+{
+ int err;
+ char *label;
+ char *status;
+
+ err = picldiag_get_combined_label(fruh, &label, 23);
+ if (err != PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+
+ err = picldiag_get_string_propval(fruh,
+ PICL_PROP_OPERATIONAL_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ if (*countp == 0) {
+ logprintf_header(dgettext(TEXT_DOMAIN,
+ "FRU Operational Status"),
+ DEFAULT_LINE_WIDTH);
+ log_printf("---------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Fru Operational Status:\n"));
+ log_printf("---------------------------------\n");
+ log_printf("Location Status\n");
+ log_printf("---------------------------------\n");
+ }
+ *countp += 1;
+ log_printf("%-23s ", label);
+ free(label);
+ log_printf("%s\n", status);
+ set_exit_code(status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ free(label);
+ return (err);
+ } else {
+ free(label);
+ }
+ return (PICL_WALK_CONTINUE);
+}
+
+static int
+fru_oper_status_callback(picl_nodehdl_t fruh, void *arg)
+{
+ int err;
+
+ err = logprintf_fru_oper_status(fruh, (int *)arg);
+ return (err);
+}
+
+/*
+ * display fru operational status
+ */
+static int
+display_fru_oper_status(picl_nodehdl_t frutreeh)
+{
+ int print_header;
+
+ print_header = 0;
+ picl_walk_tree_by_class(frutreeh, PICL_CLASS_FRU,
+ &print_header, fru_oper_status_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * check if the node having the version prop
+ * If yes, print its nodename and version
+ */
+/* ARGSUSED */
+static int
+asicrev_callback(picl_nodehdl_t nodeh, void *arg)
+{
+ uint32_t version;
+ char *name;
+ char *model;
+ char *status;
+ int err;
+
+ /*
+ * Fire based platforms use "module-revision#" in place of "version#",
+ * so we need to look for this property if we don't find "version#"
+ */
+ version = picldiag_get_uint_propval(nodeh, OBP_PROP_VERSION_NUM, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ version = picldiag_get_uint_propval(nodeh, OBP_PROP_MODREV_NUM,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ }
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH, &name);
+ if (err == PICL_PROPNOTFOUND)
+ name = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* model */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_BINDING_NAME,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* status */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND)
+ status = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Display the data
+ */
+
+ /* name */
+ if (name != NULL) {
+ log_printf("%-22s ", name);
+ free(name);
+ } else
+ log_printf("%-22s ", "unknown");
+ /* model */
+ if (model != NULL) {
+ log_printf("%-15s ", model);
+ free(model);
+ } else
+ log_printf("%-15s ", "unknown");
+ /* status */
+ if (status == NULL)
+ log_printf("%-15s ", "okay");
+ else {
+ log_printf("%-15s ", status);
+ set_exit_code(status);
+ free(status);
+ }
+ /* revision */
+ log_printf(" %-4d\n", version);
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * traverse the tree to display asic revision id for ebus
+ */
+/* ARGSUSED */
+static int
+ebus_callback(picl_nodehdl_t ebush, void *arg)
+{
+ uint32_t id;
+ char *name;
+ int err;
+ char *model;
+ char *status;
+
+ id = picldiag_get_uint_propval(ebush, OBP_PROP_REVISION_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* devfs-path */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_DEVFS_PATH, &name);
+ if (err == PICL_PROPNOTFOUND)
+ name = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* model */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_BINDING_NAME,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* status */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND)
+ status = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Display the data
+ */
+
+ /* name */
+ if (name != NULL) {
+ log_printf("%-22s ", name);
+ free(name);
+ } else
+ log_printf("%-22s ", "unknown");
+ /* model */
+ if (model != NULL) {
+ log_printf("%-15s ", model);
+ free(model);
+ } else
+ log_printf("%-15s ", "unknown");
+ /* status */
+ if (status == NULL)
+ log_printf("%-15s ", "okay");
+ else {
+ log_printf("%-15s ", status);
+ set_exit_code(status);
+ free(status);
+ }
+ /* revision */
+ log_printf(" %-4d\n", id);
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * display asic revision id
+ */
+static int
+display_hw_revisions(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /* Print the header */
+ logprintf_header(dgettext(TEXT_DOMAIN, "HW Revisions"),
+ DEFAULT_LINE_WIDTH);
+
+ log_printf("ASIC Revisions:\n");
+ log_printf("-----------------------------");
+ log_printf("--------------------------------------\n");
+ log_printf("Path Device");
+ log_printf(" Status Revision\n");
+ log_printf("-----------------------------");
+ log_printf("--------------------------------------\n");
+
+ err = picl_walk_tree_by_class(plafh, NULL, NULL, asicrev_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_EBUS,
+ NULL, ebus_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_DISPLAY,
+ NULL, ffbconfig_callback);
+ return (err);
+}
+
+/*
+ * find the options node and its powerfail_time prop
+ * If found, display the list of latest powerfail.
+ */
+/* ARGSUSED */
+static int
+options_callback(picl_nodehdl_t nodeh, void *arg)
+{
+ time_t value;
+ char *failtime;
+ int err;
+
+ err = picldiag_get_string_propval(nodeh, PROP_POWERFAIL_TIME,
+ &failtime);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_TERMINATE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ value = (time_t)atoi(failtime);
+ free(failtime);
+ if (value == 0)
+ return (PICL_WALK_TERMINATE);
+
+ log_printf(dgettext(TEXT_DOMAIN, "Most recent AC Power Failure:\n"));
+ log_printf("=============================\n");
+ log_printf("%s", ctime(&value));
+ log_printf("\n");
+ return (PICL_WALK_TERMINATE);
+}
+
+/*
+ * display the OBP and POST prom revisions
+ */
+/* ARGSUSED */
+static int
+flashprom_callback(picl_nodehdl_t flashpromh, void *arg)
+{
+ picl_prophdl_t proph;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ picl_propinfo_t pinfo;
+ char *prom_version = NULL;
+ char *obp_version = NULL;
+ int err;
+
+ err = picl_get_propinfo_by_name(flashpromh, OBP_PROP_VERSION,
+ &pinfo, &proph);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_TERMINATE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf(dgettext(TEXT_DOMAIN, "System PROM revisions:\n"));
+ log_printf("----------------------\n");
+
+ /*
+ * If it's a table prop, the first element is OBP revision
+ * The second one is POST revision.
+ * If it's a charstring prop, the value will be only OBP revision
+ */
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ prom_version = alloca(pinfo.size);
+ if (prom_version == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, prom_version, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", prom_version);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE) /* not supported type */
+ return (PICL_WALK_TERMINATE);
+
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err == PICL_SUCCESS) {
+ /* get first row */
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ prom_version = alloca(pinfo.size);
+ if (prom_version == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, prom_version, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", prom_version);
+
+ /* get second row */
+ err = picl_get_next_by_col(rowproph, &rowproph);
+ if (err == PICL_SUCCESS) {
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ obp_version = alloca(pinfo.size);
+ if (obp_version == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(rowproph, obp_version,
+ pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", obp_version);
+ }
+ }
+
+ return (PICL_WALK_TERMINATE);
+}
+
+static int
+display_system_info(int serrlog, int log_flag, picl_nodehdl_t rooth)
+{
+ int err;
+ picl_nodehdl_t plafh;
+ picl_nodehdl_t frutreeh;
+
+ err = picldiag_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (!log_flag) {
+ err = display_platform_banner(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_system_clock(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY,
+ PICL_CLASS_MEMORY, memory_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_cpu_info(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_io_device_info(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_memory_config(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_usb_devices(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ if (serrlog) {
+ err = picl_walk_tree_by_class(rooth, PICL_CLASS_OPTIONS,
+ NULL, options_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_envctrl_status(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_node_by_name(rooth, PICL_NODE_FRUTREE,
+ &frutreeh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_fru_oper_status(frutreeh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_hw_revisions(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_FLASHPROM,
+ NULL, flashprom_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_serial_number(plafh);
+ if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
+ return (err);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * do_prominfo is called from main in prtdiag. It returns PD_SYSTEM_FAILURE if
+ * any system failure is detected, PD_INTERNAL_FAILURE for internal errors and
+ * PD_SUCCESS otherwise. main uses the return value as the exit code.
+ */
+/* ARGSUSED */
+int
+do_prominfo(int serrlog, char *pgname, int log_flag, int prt_flag)
+{
+ int err;
+ char *errstr;
+ int done;
+ picl_nodehdl_t rooth;
+
+ err = picl_initialize();
+ if (err != PICL_SUCCESS) {
+ fprintf(stderr, EM_INIT_FAIL, picl_strerror(err));
+ return (PD_INTERNAL_FAILURE);
+ }
+
+ do {
+ done = 1;
+ err = picl_get_root(&rooth);
+ if (err != PICL_SUCCESS) {
+ fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err));
+ return (PD_INTERNAL_FAILURE);
+ }
+
+ err = display_system_info(serrlog, log_flag, rooth);
+
+ if ((err == PICL_STALEHANDLE) || (err == PICL_INVALIDHANDLE))
+ done = 0;
+ } while (!done);
+
+ if (err != PICL_SUCCESS) {
+ errstr = picl_strerror(err);
+ fprintf(stderr, EM_PRTDIAG_FAIL);
+ fprintf(stderr, "%s\n", errstr? errstr : " ");
+ exit_code = PD_INTERNAL_FAILURE;
+ }
+
+ (void) picl_shutdown();
+
+ return (exit_code);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/desktop/nonpicl/Makefile b/usr/src/lib/libprtdiag_psr/sparc/desktop/nonpicl/Makefile
new file mode 100644
index 0000000000..1f15ae4d58
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/desktop/nonpicl/Makefile
@@ -0,0 +1,107 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/desktop/nonpicl/Makefile
+
+UTSBASE = $(SRC)/uts
+
+PLATFORM_OBJECTS= desktop.o
+
+objs/%.o pics/%.o: ../common/%.c
+ $(COMPILE.c) $(IFLAGS) -o $@ $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/lib/libprtdiag_psr/sparc/Makefile.com
+
+SRCS= $(OBJECTS:%.o=../common/%.c)
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../../libprtdiag/inc
+LINTFLAGS += $(IFLAGS)
+
+#
+# desktop platform library should install into
+# SUNW,Ultra-2. All other desktop platforms can
+# link to /usr/platform/SUNW,Ultra-2/lib/libprtdiag_psr.so
+#
+PLATFORM=SUNW,Ultra-2
+
+#
+# For all other sun4u platforms NOT delivered by ON (ie. delivered
+# by SME or external hardware vendors) we add a default library in
+# /usr/platform/sun4u/lib so that prtdiag will default to using
+# the desktop library for any of these platforms. (this will be a
+# link to ../../SUNW,Ultra-2/lib
+#
+DEF_PLATFORM=sun4u
+USR_DEF_PSM_LIB_DIR=$(USR_PLAT_DIR)/$(DEF_PLATFORM)/lib
+USR_DEF_PSM_LIBS=$(LIBS:%=$(USR_DEF_PSM_LIB_DIR)/%)
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS) $(USR_DEF_PSM_LIBS)
+
+#
+# install rules for SUNW,Ultra-2/lib/libprtdiag_psr.so.1
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u; $(MAKE) $(USR_PSM_LIB_DIR)
+
+#
+# install rules for sun4u/lib/libprtdiag_psr.so.1
+#
+$(USR_DEF_PSM_LIB_DIR)/%: % $(USR_DEF_PSM_LIB_DIR)
+ $(RM) -r $@; \
+ $(SYMLINK) ../../$(PLATFORM)/lib/libprtdiag_psr.so.1 $@ $(CHOWNLINK) $(CHGRPLINK)
+
+$(USR_DEF_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u; $(MAKE) $(USR_DEF_PSM_LIB_DIR)
+
+
+#
+# Rules for making message files
+#
+POFILE= libprtdiag_psr_desktop.po
+POFILES= desktop.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../common/desktop.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/desktop/picl/Makefile b/usr/src/lib/libprtdiag_psr/sparc/desktop/picl/Makefile
new file mode 100644
index 0000000000..f0e48afa83
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/desktop/picl/Makefile
@@ -0,0 +1,120 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/desktop/picl/Makefile
+
+UTSBASE = $(SRC)/uts
+
+PLATFORM_OBJECTS= picldiag.o
+
+objs/%.o pics/%.o: ../common/%.c
+ $(COMPILE.c) $(IFLAGS) -o $@ $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/lib/libprtdiag_psr/sparc/Makefile.com
+
+SRCS= $(OBJECTS:%.o=../common/%.c)
+
+LDLIBS += -lpicl
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../../libprtdiag/inc
+IFLAGS += -I$(SRC)/cmd/picl/plugins/inc
+LINTFLAGS += $(IFLAGS)
+
+#
+# links in /usr/platform
+#
+LINKED_PLATFORMS = SUNW,Sun-Blade-1000 SUNW,Netra-T4
+LINKED_PLATFORMS += SUNW,Sun-Blade-1500
+LINKED_PLATFORMS += SUNW,Sun-Blade-2500
+LINKED_PLATFORMS += SUNW,A70
+LINKED_PLATFORMS += SUNW,Sun-Fire-V445
+LINKED_PLATFORMS += SUNW,Sun-Fire-V215
+LINKED_PLATFORMS += SUNW,Serverblade1
+LINKED_PLATFORMS += SUNW,Sun-Fire-V240
+LINKED_PLATFORMS += SUNW,Sun-Fire-V250
+LINKED_PLATFORMS += SUNW,Sun-Fire-V440
+
+LINKED_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%)
+LINKED_LIB_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib)
+LINKED_PRTDIAG_DIRS = \
+ $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/libprtdiag_psr.so.1)
+
+#
+# Sun-Blade-100 and Sun-Blade-1000 platform library should install into
+# SUNW,Sun-Blade-100. Sun-Blade-100 platforms can
+# link to /usr/platform/SUNW,Sun-Blade-100/lib/libprtdiag_psr.so
+#
+PLATFORM= SUNW,Sun-Blade-100
+
+.KEEP_STATE:
+
+PLATLIBS= $(PLATFORM:%=$(USR_PLAT_DIR)/%/lib/)
+
+install: all $(PLATLIBS) $(USR_PSM_LIBS) \
+ $(LINKED_PRTDIAG_DIRS)
+
+#
+# install rules for SUNW,Sun-Blade-100/lib/libprtdiag_psr.so.1
+#
+$(PLATLIBS):
+ $(INS.dir)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(USR_PSM_LIB_DIR):
+ $(INS.dir)
+
+$(LINKED_DIRS): $(USR_PLAT_DIR)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIB_DIRS): $(LINKED_DIRS)
+ -$(INS.dir.root.sys)
+
+$(LINKED_PRTDIAG_DIRS): $(USR_PLAT_DIR)
+ -$(INS.slink6)
+
+#
+# Rules for making message files
+#
+POFILE= libprtdiag_psr_desktop_picl.po
+POFILES= desktop.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../common/picldiag.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/javelin/Makefile b/usr/src/lib/libprtdiag_psr/sparc/javelin/Makefile
new file mode 100644
index 0000000000..294cd3d4cd
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/javelin/Makefile
@@ -0,0 +1,77 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/javelin/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= javelin.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+LINTFLAGS += $(IFLAGS)
+LDLIBS += -lkstat
+
+#
+# Workgroup Server platform library should install into
+# SUNW,Ultra-4. All other desktop platforms can
+# link to /usr/platform/SUNW,Ultra-4/lib/libprtdiag_psr.so
+#
+PLATFORM=SUNW,Ultra-250
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/javelin; $(MAKE) $(USR_PSM_LIB_DIR)
+
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+POFILE= libprtdiag_psr_javelin.po
+POFILES= javelin.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/javelin.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/javelin/common/javelin.c b/usr/src/lib/libprtdiag_psr/sparc/javelin/common/javelin.c
new file mode 100644
index 0000000000..2c2d77b1fa
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/javelin/common/javelin.c
@@ -0,0 +1,1375 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Javelin Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_JAVELIN
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+extern int print_flag;
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (workgroup server systems only)
+ */
+int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+int disp_fail_parts(Sys_tree *tree);
+void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_boardnum(int num);
+void display_pci(Board_node *);
+void display_io_cards(struct io_card *list);
+void display_ffb(Board_node *, int);
+void read_platform_kstats(Sys_tree *tree,
+ struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep);
+
+/* local functions */
+static int disp_envc_status(struct system_kstat_data *);
+static void tazjav_disp_asic_revs(Sys_tree *);
+static int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
+static Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
+
+
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ int exit_code = 0; /* init to all OK */
+
+#ifdef lint
+ kstats = kstats;
+#endif
+ /*
+ * silently check for any types of machine errors
+ */
+ print_flag = 0;
+ if (disp_fail_parts(tree) || disp_envc_status(kstats)) {
+ /* set exit_code to show failures */
+ exit_code = 1;
+ }
+ print_flag = 1;
+
+ return (exit_code);
+}
+
+/* Search for and return the node's sibling */
+static Prom_node *
+dev_next_node_sibling(Prom_node *root, char *name)
+{
+ if (root == NULL)
+ return (NULL);
+
+ /* look at your siblings */
+ if (dev_find_node(root->sibling, name) != NULL)
+ return (root->sibling);
+
+ return (NULL); /* not found */
+}
+
+/*
+ * This function displays memory configurations specific to Tazmo/Javelin.
+ * The PROM device tree is read to obtain this information.
+ * Some of the information obtained is memory interleave factor,
+ * DIMM sizes, DIMM socket names.
+ */
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode;
+ Prom_node *memory;
+ Prom_node *bank;
+ Prom_node *dimm;
+ uint_t *preg;
+ uint_t interlv;
+ unsigned long size = 0;
+ int bank_count = 0;
+ char *sock_name;
+ char *status;
+ Prop *status_prop;
+ char interleave[8];
+ int total_size = 0;
+#ifdef lint
+ grps = grps;
+#endif
+
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+ bnode = tree->bd_list;
+ memory = dev_find_node(bnode->nodes, "memory");
+ preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave")));
+ if (preg) {
+ interlv = preg[4];
+ log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0);
+ }
+ log_printf(" Interlv. Socket Size\n", 0);
+ log_printf("Bank Group Name (MB) Status\n", 0);
+ log_printf("---- ----- ------ ---- ------\n", 0);
+
+ dimm = bnode->nodes;
+ for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL;
+ bank = dev_next_node(bank, "bank")) {
+ int bank_size = 0;
+ uint_t *reg_prop;
+
+ preg = (uint_t *)(get_prop_val(
+ find_prop(bank, "bank-interleave")));
+
+ reg_prop = (uint_t *)(get_prop_val(
+ find_prop(bank, "reg")));
+
+ /*
+ * Skip empty banks
+ */
+ if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) {
+ bank_count++;
+ continue;
+ }
+
+ if (preg) {
+ interlv = preg[2];
+ (void) sprintf(interleave, " %d ", interlv);
+ bank_size = (preg[0]<<12) + (preg[1]>>20);
+ } else {
+ (void) sprintf(interleave, "%s", "none");
+ preg = (uint_t *)(get_prop_val(find_prop(bank, "reg")));
+ if (preg) {
+ bank_size = (preg[2]<<12) + (preg[3]>>20);
+ }
+ }
+ for (dimm = dev_find_node(bank, "dimm"); dimm != NULL;
+ dimm = dev_next_node_sibling(dimm, "dimm")) {
+ char dimm_status[16];
+
+ sock_name = (char *)(get_prop_val(
+ find_prop(dimm, "socket-name")));
+ preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg")));
+ size = (preg[2]<<12) + (preg[3]>>20);
+ if ((status_prop = find_prop(dimm, "status")) == NULL) {
+ (void) sprintf(dimm_status, "%s", "OK");
+ } else {
+ status = (char *)(get_prop_val(status_prop));
+ (void) sprintf(dimm_status, "%s", status);
+ }
+ log_printf("%3d %5s %6s %4d %6s\n",
+ bank_count, interleave, sock_name,
+ size, dimm_status, 0);
+ }
+ total_size += bank_size;
+ bank_count++;
+ }
+ log_printf("\n", 0);
+}
+
+/*
+ * disp_fail_parts
+ *
+ * Display the failed parts in the system. This function looks for
+ * the status property in all PROM nodes. On systems where
+ * the PROM does not supports passing diagnostic information
+ * thruogh the device tree, this routine will be silent.
+ */
+int
+disp_fail_parts(Sys_tree *tree)
+{
+ int exit_code;
+ int system_failed = 0;
+ Board_node *bnode = tree->bd_list;
+ Prom_node *pnode;
+ char *fru;
+ char *sock_name;
+ char slot_str[MAXSTRLEN];
+
+ exit_code = 0;
+
+ /* go through all of the boards looking for failed units. */
+ while (bnode != NULL) {
+ /* find failed chips */
+ pnode = find_failed_node(bnode->nodes);
+ if ((pnode != NULL) && !system_failed) {
+ system_failed = 1;
+ exit_code = 1;
+ if (print_flag == 0) {
+ return (exit_code);
+ }
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
+ "Replaceable Units (FRU) in System:\n"), 0);
+ log_printf("=========================="
+ "====================\n", 0);
+ }
+
+ while (pnode != NULL) {
+ void *value;
+ char *name; /* node name string */
+ char *type; /* node type string */
+
+ value = get_prop_val(find_prop(pnode, "status"));
+ name = get_node_name(pnode);
+
+ /* sanity check of data retreived from PROM */
+ if ((value == NULL) || (name == NULL)) {
+ pnode = next_failed_node(pnode);
+ continue;
+ }
+
+
+ log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"),
+ name, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN, "\tPROM fault "
+ "string: %s\n"), value, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN, "\tFailed Field "
+ "Replaceable Unit is "), 0);
+
+ /*
+ * Determine whether FRU is CPU module, system
+ * board, or SBus card.
+ */
+ if ((name != NULL) && (strstr(name, "sbus"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN, "SBus "
+ "Card %d\n"), get_sbus_slot(pnode), 0);
+
+ } else if (((name = get_node_name(pnode)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN, "system "
+ "board\n"), 0);
+
+ } else if (((name = get_node_name(pnode)) !=
+ NULL) && (strstr(name, "ffb"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN, "FFB "
+ "Card %d\n"), tazmo_physical_slot(
+ dev_find_node(bnode->nodes, "slot2dev"),
+ pnode, -1, slot_str), 0);
+
+ } else if (((name = get_node_name(pnode->parent)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ (void) tazmo_physical_slot(
+ NULL,
+ pnode->parent,
+ get_pci_device(pnode),
+ slot_str);
+ log_printf(dgettext(TEXT_DOMAIN, "PCI Card "
+ "in %s\n"), slot_str, 0);
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "cpu"))) {
+
+ log_printf(
+ dgettext(TEXT_DOMAIN, "UltraSPARC "
+ "module Module %d\n"),
+ get_id(pnode));
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "memory-module"))) {
+
+ fru = (char *)(get_prop_val(
+ find_prop(pnode, "fru")));
+ sock_name = (char *)(get_prop_val(
+ find_prop(pnode, "socket-name")));
+ log_printf(
+ dgettext(TEXT_DOMAIN, "%s in "
+ "socket %s\n"), fru,
+ sock_name, 0);
+ }
+ pnode = next_failed_node(pnode);
+ }
+ bnode = bnode->next;
+ }
+
+ if (!system_failed) {
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN, "No failures found "
+ "in System\n"), 0);
+ log_printf("===========================\n", 0);
+ }
+
+ if (system_failed)
+ return (1);
+ else
+ return (0);
+}
+
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+#ifdef lint
+ kstats = kstats;
+#endif
+ /* Display failed units */
+ (void) disp_fail_parts(tree);
+}
+
+
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is iof the user
+ * told us to do logging, and we found a system failure.
+ */
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ (void) disp_envc_status(kstats);
+
+ tazjav_disp_asic_revs(tree);
+
+ platform_disp_prom_version(tree);
+ }
+ return;
+
+}
+
+/* ARGSUSED */
+void
+display_boardnum(int num)
+{
+ log_printf("SYS ", 0);
+}
+
+
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+
+/* ARGSUSED */
+void
+display_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+ Prom_node *pci;
+ Prom_node *card_node;
+
+ if (board == NULL)
+ return;
+
+ /* Initialize all the common information */
+ card.display = 1;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "PCI");
+
+ for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL;
+ pci = dev_next_node(pci, PCI_NAME)) {
+ char *name;
+ Prom_node *prev_parent = NULL;
+ int prev_device = -1;
+ int pci_pci_bridge = 0;
+
+ /*
+ * If we have reached a pci-to-pci bridge node,
+ * we are one level below the 'pci' nodes level
+ * in the device tree. To get back to that level,
+ * the search should continue with the sibling of
+ * the parent or else the remaining 'pci' cards
+ * will not show up in the output.
+ */
+ if (find_prop(pci, "upa-portid") == NULL) {
+ if ((pci->parent->sibling != NULL) &&
+ (strcmp(get_prop_val(
+ find_prop(pci->parent->sibling,
+ "name")), PCI_NAME) == 0))
+ pci = pci->parent->sibling;
+ else {
+ pci = pci->parent->sibling;
+ continue;
+ }
+ }
+
+ /* Skip all failed nodes for now */
+ if (node_failed(pci))
+ continue;
+
+ /* Fill in frequency */
+ value = get_prop_val(find_prop(pci, "clock-frequency"));
+ if (value == NULL)
+ card.freq = -1;
+ else
+ card.freq = ((*(int *)value) + 500000) / 1000000;
+
+ /* Walk through the PSYCHO children */
+ card_node = pci->child;
+ while (card_node != NULL) {
+ Prop *compat = NULL;
+
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(card_node, "name"));
+ if (name == NULL) {
+ card_node = card_node->sibling;
+ continue;
+ }
+
+ /*
+ * If this is a PCI bridge, then display its
+ * children.
+ */
+ if (strcmp(name, "pci") == 0) {
+ card_node = card_node->child;
+ pci_pci_bridge = 1;
+ continue;
+ }
+
+ /* Get the slot number for this card */
+ if (pci_pci_bridge) {
+ card.slot = tazmo_physical_slot(
+ dev_find_node(board->nodes, "slot2dev"),
+ pci,
+ get_pci_to_pci_device(
+ card_node->parent),
+ card.slot_str);
+ } else
+ card.slot = tazmo_physical_slot(
+ dev_find_node(board->nodes,
+ "slot2dev"),
+ pci,
+ get_pci_device(card_node),
+ card.slot_str);
+
+ /*
+ * Check that duplicate devices are not reported
+ * on Tazmo.
+ */
+ if ((card_node->parent == prev_parent) &&
+ (get_pci_device(card_node) == prev_device) &&
+ (pci_pci_bridge == 0))
+ card.slot = -1;
+ prev_parent = card_node->parent;
+ prev_device = get_pci_device(card_node);
+
+
+ if (card.slot == -1 || strstr(name, "ebus")) {
+ card_node = card_node->sibling;
+ continue;
+ }
+
+ /* XXX - Don't know how to get status for PCI cards */
+ card.status[0] = '\0';
+
+ /* Get the model of this card */
+ value = get_prop_val(find_prop(card_node, "model"));
+ if (value == NULL)
+ card.model[0] = '\0';
+ else
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+
+ /*
+ * Check if further processing is necessary to display
+ * this card uniquely.
+ */
+ distinguish_identical_io_cards(name, card_node, &card);
+
+
+ /*
+ * If we haven't figured out the frequency yet,
+ * try and get it from the card.
+ */
+ value = get_prop_val(find_prop(pci, "clock-frequency"));
+ if (value != NULL && card.freq == -1)
+ card.freq = ((*(int *)value) + 500000)
+ / 1000000;
+
+
+ value = get_prop_val(find_prop(card_node,
+ "compatible"));
+
+ /*
+ * On Tazmo, we would like to print out the last
+ * string of the "compatible" property if it exists.
+ * The IEEE 1275 spec. states that this last string
+ * will be the classcode name.
+ */
+ if (value != NULL) {
+ char *tval;
+ int index;
+ const int always = 1;
+
+ tval = (char *)value;
+ index = 0;
+ compat = find_prop(card_node, "compatible");
+ while (always) {
+ if ((strlen(tval) + 1) ==
+ (compat->size - index))
+ break;
+ index += strlen(tval) + 1;
+ tval += strlen(tval) + 1;
+ }
+ value = (void *)tval;
+ }
+
+ if (value != NULL)
+ (void) sprintf(card.name, "%s-%s",
+ (char *)name, (char *)value);
+ else
+ (void) sprintf(card.name, "%s",
+ (char *)name);
+
+ if (card.freq != -1)
+ card_list = insert_io_card(card_list, &card);
+
+ /*
+ * If we are done with the children of the pci bridge,
+ * we must continue with the remaining siblings of
+ * the pci-to-pci bridge.
+ */
+ if ((card_node->sibling == NULL) && pci_pci_bridge) {
+ card_node = card_node->parent->sibling;
+ pci_pci_bridge = 0;
+ } else
+ card_node = card_node->sibling;
+ }
+ }
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == 0) {
+ log_printf(" Bus Freq\n", 0);
+ log_printf("Brd Type MHz Slot "
+ "Name "
+ "Model", 0);
+ log_printf("\n", 0);
+ log_printf("--- ---- ---- ---- "
+ "-------------------------------- "
+ "----------------------", 0);
+ log_printf("\n", 0);
+ banner = 1;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf("SYS ", p->board, 0);
+ log_printf("%-4s ", p->bus_type, 0);
+ log_printf("%3d ", p->freq, 0);
+ log_printf("%3d ", p->slot, 0);
+ log_printf("%-32.32s", p->name, 0);
+ if (strlen(p->name) > 32)
+ log_printf("+ ", 0);
+ else
+ log_printf(" ", 0);
+ log_printf("%-22.22s", p->model, 0);
+ if (strlen(p->model) > 22)
+ log_printf("+", 0);
+ log_printf("\n", 0);
+ }
+}
+
+/*
+ * display_ffb
+ * Display all FFBs on this board. It can either be in tabular format,
+ * or a more verbose format.
+ */
+void
+display_ffb(Board_node *board, int table)
+{
+ Prom_node *ffb;
+ void *value;
+ struct io_card *card_list = NULL;
+ struct io_card card;
+
+ if (board == NULL)
+ return;
+
+ /* Fill in common information */
+ card.display = 1;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "UPA");
+ card.freq = sys_clk;
+
+ for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
+ ffb = dev_next_node(ffb, FFB_NAME)) {
+ if (table == 1) {
+ /* Print out in table format */
+
+ /* XXX - Get the slot number (hack) */
+ card.slot = tazmo_physical_slot(
+ dev_find_node(board->nodes, "slot2dev"),
+ ffb,
+ -1,
+ card.slot_str);
+
+ /* Find out if it's single or double buffered */
+ (void) sprintf(card.name, "FFB");
+ value = get_prop_val(find_prop(ffb, "board_type"));
+ if (value != NULL)
+ if ((*(int *)value) & FFB_B_BUFF)
+ (void) sprintf(card.name,
+ "FFB, Double Buffered");
+ else
+ (void) sprintf(card.name,
+ "FFB, Single Buffered");
+
+ /* Print model number */
+ card.model[0] = '\0';
+ value = get_prop_val(find_prop(ffb, "model"));
+ if (value != NULL)
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+
+ card_list = insert_io_card(card_list, &card);
+ } else {
+ /* print in long format */
+ char device[MAXSTRLEN];
+ int fd = -1;
+ struct dirent *direntp;
+ DIR *dirp;
+ union strap_un strap;
+ struct ffb_sys_info fsi;
+
+ /* Find the device node using upa address */
+ value = get_prop_val(find_prop(ffb, "upa-portid"));
+ if (value == NULL)
+ continue;
+
+ (void) sprintf(device, "%s@%x", FFB_NAME,
+ *(int *)value);
+ if ((dirp = opendir("/devices")) == NULL)
+ continue;
+
+ while ((direntp = readdir(dirp)) != NULL) {
+ if (strstr(direntp->d_name, device) != NULL) {
+ (void) sprintf(device, "/devices/%s",
+ direntp->d_name);
+ fd = open(device, O_RDWR, 0666);
+ break;
+ }
+ }
+ (void) closedir(dirp);
+
+ if (fd == -1)
+ continue;
+
+ if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
+ continue;
+
+ log_printf("FFB Hardware Configuration:\n", 0);
+ log_printf("-----------------------------------\n", 0);
+
+ strap.ffb_strap_bits = fsi.ffb_strap_bits;
+ log_printf("\tBoard rev: %d\n",
+ (int)strap.fld.board_rev, 0);
+ log_printf("\tFBC version: "
+ "0x%x\n", fsi.fbc_version, 0);
+ log_printf("\tDAC: %s\n",
+ fmt_manf_id(fsi.dac_version, device), 0);
+ log_printf("\t3DRAM: %s\n",
+ fmt_manf_id(fsi.fbram_version, device), 0);
+ log_printf("\n", 0);
+ }
+ }
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+/*
+ * This module does the reading and interpreting of javelin system
+ * kstats. These kstats are created by the environ drivers.
+ */
+void
+read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep)
+{
+ kstat_ctl_t *kc;
+ struct envctrltwo_kstat_data *ecp;
+ kstat_t *ksp;
+
+ if ((kc = kstat_open()) == NULL) {
+ return;
+ }
+#ifdef lint
+ tree = tree;
+ bdp = bdp;
+ ep = ep;
+#endif
+
+ /* read the envctrltwo kstats */
+ ecp = &sys_kstat->envc_data;
+
+ /* Read the power supply kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_PSNAME2);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ecp->ps_kstats, ksp->ks_data,
+ ksp->ks_ndata * sizeof (envctrl_ps2_t));
+ } else {
+ sys_kstat->envctrltwo_kstat_ok = B_FALSE;
+ return;
+ }
+
+ ecp->num_ps_kstats = ksp->ks_ndata;
+
+ /* Read the fan status kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_FANSTAT);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ecp->fan_kstats, ksp->ks_data,
+ ksp->ks_ndata * sizeof (envctrl_fan_t));
+ } else {
+ sys_kstat->envctrltwo_kstat_ok = B_FALSE;
+ return;
+ }
+
+ ecp->num_fan_kstats = ksp->ks_ndata;
+
+ /* Read the enclosure kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_ENCL);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ecp->encl_kstats, ksp->ks_data,
+ ksp->ks_ndata * sizeof (envctrl_encl_t));
+ } else {
+ sys_kstat->envctrltwo_kstat_ok = B_FALSE;
+ return;
+ }
+
+ ecp->num_encl_kstats = ksp->ks_ndata;
+
+ /* Read the temperature kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_TEMPERATURE);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ecp->temp_kstats, ksp->ks_data,
+ ksp->ks_ndata * sizeof (envctrl_temp_t));
+ } else {
+ sys_kstat->envctrltwo_kstat_ok = B_FALSE;
+ return;
+ }
+
+ ecp->num_temp_kstats = ksp->ks_ndata;
+
+ /* Read the disk kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_DISK);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ecp->disk_kstats, ksp->ks_data,
+ ksp->ks_ndata * sizeof (envctrl_disk_t));
+ } else {
+ sys_kstat->envctrltwo_kstat_ok = B_FALSE;
+ return;
+ }
+
+ ecp->num_disk_kstats = ksp->ks_ndata;
+
+ sys_kstat->envctrltwo_kstat_ok = 1;
+ return;
+
+}
+
+/*
+ * Walk the PROM device tree and build the system tree and root tree.
+ * Nodes that have a board number property are placed in the board
+ * structures for easier processing later. Child nodes are placed
+ * under their parents. ffb (Fusion Frame Buffer) nodes are handled
+ * specially, because they do not contain board number properties.
+ * This was requested from OBP, but was not granted. So this code
+ * must parse the MID of the FFB to find the board#.
+ */
+Prom_node *
+walk(Sys_tree *tree, Prom_node *root, int id)
+{
+ register int curnode;
+ Prom_node *pnode;
+ char *name;
+ char *type;
+ char *model;
+ int board_node = 0;
+
+ /* allocate a node for this level */
+ if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
+ NULL) {
+ perror("malloc");
+ exit(2); /* program errors cause exit 2 */
+ }
+
+ /* assign parent Prom_node */
+ pnode->parent = root;
+ pnode->sibling = NULL;
+ pnode->child = NULL;
+
+ /* read properties for this node */
+ dump_node(pnode);
+
+ /*
+ * Place a node in a 'board' if it has 'board'-ness. The definition
+ * is that all nodes that are children of root should have a
+ * board# property. But the PROM tree does not exactly follow
+ * this. This is where we start hacking. The name 'ffb' can
+ * change, so watch out for this.
+ *
+ * The UltraSPARC, sbus, pci and ffb nodes will exit in
+ * the desktops and will not have board# properties. These
+ * cases must be handled here.
+ *
+ * PCI to PCI bridges also have the name "pci", but with different
+ * model property values. They should not be put under 'board'.
+ */
+ name = get_node_name(pnode);
+ type = get_node_type(pnode);
+ model = (char *)get_prop_val(find_prop(pnode, "model"));
+#ifdef DEBUG
+ if (name != NULL)
+ printf("name=%s ", name);
+ if (type != NULL)
+ printf("type=%s ", type);
+ if (model != NULL)
+ printf("model=%s", model);
+ printf("\n");
+
+ if (model == NULL)
+ model = "";
+#endif
+ if (type == NULL)
+ type = "";
+ if (name != NULL) {
+ if (has_board_num(pnode)) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s model=%s\n",
+ name, type, model);
+#endif
+ } else if ((strcmp(name, FFB_NAME) == 0) ||
+ (strcmp(type, "cpu") == 0) ||
+
+ ((strcmp(name, "pci") == 0) && (model != NULL) &&
+ (strcmp(model, "SUNW,psycho") == 0)) ||
+
+ ((strcmp(name, "pci") == 0) && (model != NULL) &&
+ (strcmp(model, "SUNW,sabre") == 0)) ||
+
+ (strcmp(name, "counter-timer") == 0) ||
+ (strcmp(name, "sbus") == 0) ||
+ (strcmp(name, "memory") == 0) ||
+ (strcmp(name, "mc") == 0) ||
+ (strcmp(name, "associations") == 0)) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s model=%s\n",
+ name, type, model);
+#endif
+ }
+#ifdef DEBUG
+ else
+ printf("node not added: name=%s type=%s\n", name, type);
+#endif
+ }
+
+ if (curnode = child(id)) {
+ pnode->child = walk(tree, pnode, curnode);
+ }
+
+ if (curnode = next(id)) {
+ if (board_node) {
+ return (walk(tree, root, curnode));
+ } else {
+ pnode->sibling = walk(tree, root, curnode);
+ }
+ }
+
+ if (board_node) {
+ return (NULL);
+ } else {
+ return (pnode);
+ }
+}
+
+/*
+ * local functions
+ */
+
+/*
+ * disp_envc_status
+ *
+ * This routine displays the environmental status passed up from
+ * device drivers via kstats. The kstat names are defined in
+ * kernel header files included by this module.
+ * This is a Javelin specific environmental information display routine.
+ */
+static int
+disp_envc_status(struct system_kstat_data *sys_kstats)
+{
+ struct envctrltwo_kstat_data *ecp;
+ envctrl_ps2_t ps_ks;
+ envctrl_fan_t fans_ks;
+ envctrl_encl_t encl_ks;
+ envctrl_temp_t temp_ks;
+ envctrl_disk_t disk_ks;
+ char state[48];
+ uchar_t val, fsp_value;
+ uchar_t disk_pr, disk_fl;
+ int i;
+ int exit_code = 0;
+
+ if (sys_kstats->envctrltwo_kstat_ok == 0) {
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Environmental information "
+ "is not available\n"), 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may "
+ "not be installed\n"), 0);
+ log_printf("\n", 0);
+ return (1);
+ }
+
+ ecp = &sys_kstats->envc_data;
+
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ log_printf("System Temperatures (Celsius):\n", 0);
+ log_printf("------------------------------\n", 0);
+
+ for (i = 0; i < ecp->num_temp_kstats; i++) {
+ temp_ks = ecp->temp_kstats[i];
+ log_printf("%10s %d", temp_ks.label, temp_ks.value);
+ if (temp_ks.value >= temp_ks.shutdown_threshold) {
+ log_printf(" CRITICAL\n", 0);
+ exit_code = 1;
+ } else if (temp_ks.value >= temp_ks.warning_threshold) {
+ log_printf(" WARNING\n", 0);
+ exit_code = 1;
+ } else if (temp_ks.value < temp_ks.min) {
+ log_printf(" WARNING\n", 0);
+ exit_code = 1;
+ } else
+ log_printf("\n", 0);
+ }
+
+ log_printf("\n", 0);
+ log_printf("=================================\n", 0);
+ log_printf("\n", 0);
+ encl_ks = ecp->encl_kstats[0];
+ val = encl_ks.value & ENVCTRL_UE250_FSP_KEYMASK;
+ fsp_value = encl_ks.value;
+ switch (val) {
+ case ENVCTRL_UE250_FSP_KEYOFF:
+ (void) sprintf(state, "%s", "Off");
+ break;
+ case ENVCTRL_UE250_FSP_KEYON:
+ (void) sprintf(state, "%s", "On");
+ break;
+ case ENVCTRL_UE250_FSP_KEYDIAG:
+ (void) sprintf(state, "%s", "Diagnostic");
+ break;
+ case ENVCTRL_UE250_FSP_KEYLOCKED:
+ (void) sprintf(state, "%s", "Secure");
+ break;
+ default:
+ (void) sprintf(state, "%s", "Broken!");
+ exit_code = 1;
+ break;
+ }
+ log_printf("Front Status Panel:\n", 0);
+ log_printf("-------------------\n", 0);
+ log_printf("Keyswitch position is in %s mode.\n", state);
+ log_printf("\n", 0);
+ val = fsp_value & (ENVCTRL_UE250_FSP_DISK_ERR |
+ ENVCTRL_UE250_FSP_PS_ERR | ENVCTRL_UE250_FSP_TEMP_ERR |
+ ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_ACTIVE);
+ log_printf("System LED Status: DISK ERROR POWER \n", 0);
+ log_printf(" [%3s] [ ON] \n",
+ val & ENVCTRL_UE250_FSP_DISK_ERR ? "ON" : "OFF");
+ log_printf(" POWER SUPPLY ERROR ACTIVITY \n", 0);
+ log_printf(" [%3s] [%3s] \n",
+ val & ENVCTRL_UE250_FSP_PS_ERR ? "ON" : "OFF",
+ val & ENVCTRL_UE250_FSP_ACTIVE ? "ON" : "OFF");
+ log_printf(" GENERAL ERROR THERMAL ERROR \n", 0);
+ log_printf(" [%3s] [%3s] \n",
+ val & ENVCTRL_UE250_FSP_GEN_ERR ? "ON" : "OFF",
+ val & ENVCTRL_UE250_FSP_TEMP_ERR ? "ON" : "OFF");
+ if (val & (ENVCTRL_UE250_FSP_DISK_ERR | ENVCTRL_UE250_FSP_PS_ERR |
+ ENVCTRL_UE250_FSP_GEN_ERR | ENVCTRL_UE250_FSP_TEMP_ERR)) {
+ exit_code = 1;
+ }
+
+ log_printf("\n", 0);
+ log_printf("=================================\n", 0);
+ log_printf("\n", 0);
+ disk_pr = disk_fl = 0;
+ for (i = 0; i < ecp->num_disk_kstats; i++) {
+ disk_ks = ecp->disk_kstats[i];
+ if (disk_ks.slot == -1)
+ continue;
+ disk_pr |= 1 << disk_ks.slot;
+ if (disk_ks.disk_ok == 0)
+ disk_fl |= 1 << disk_ks.slot;
+ }
+
+ log_printf("Disk LED Status: OK = GREEN ERROR = YELLOW\n", 0);
+ log_printf(" DISK 5: %7s DISK 3: %7s DISK 1: %7s\n",
+ disk_pr & ENVCTRL_DISK_5 ?
+ disk_fl & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]" : "[EMPTY]",
+ disk_pr & ENVCTRL_DISK_3 ?
+ disk_fl & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]" : "[EMPTY]",
+ disk_pr & ENVCTRL_DISK_1 ?
+ disk_fl & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]" : "[EMPTY]");
+ log_printf(" DISK 4: %7s DISK 2: %7s DISK 0: %7s\n",
+ disk_pr & ENVCTRL_DISK_4 ?
+ disk_fl & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]" : "[EMPTY]",
+ disk_pr & ENVCTRL_DISK_2 ?
+ disk_fl & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]" : "[EMPTY]",
+ disk_pr & ENVCTRL_DISK_0 ?
+ disk_fl & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]" : "[EMPTY]");
+
+ log_printf("\n", 0);
+ log_printf("=================================\n", 0);
+ log_printf("\n", 0);
+ log_printf("Fan Bank :\n", 0);
+ log_printf("----------\n", 0);
+ log_printf("\n", 0);
+
+ fans_ks = ecp->fan_kstats[0];
+ log_printf("Bank Speed Status\n", 0);
+ log_printf(" (0-255) \n", 0);
+ log_printf("---- ----- ------\n", 0);
+ if (fans_ks.fans_ok == B_TRUE)
+ log_printf(" SYS %5d OK\n", fans_ks.fanspeed);
+ else if (fans_ks.fans_ok != B_TRUE) {
+ log_printf(" SYS %5d FAILED\n", fans_ks.fanspeed);
+ exit_code = 1;
+ }
+
+ log_printf("\n", 0);
+ log_printf("=================================\n", 0);
+ log_printf("\n", 0);
+ log_printf("Power Supplies:\n", 0);
+ log_printf("---------------\n", 0);
+ log_printf("\n", 0);
+ log_printf("Supply Status\n", 0);
+ log_printf("------ ------\n", 0);
+
+ for (i = 0; i < ecp->num_ps_kstats; i++) {
+ ps_ks = ecp->ps_kstats[i];
+ if (ps_ks.ps_ok == B_TRUE)
+ (void) sprintf(state, "%s", " OK ");
+ else if (ps_ks.ps_ok != B_TRUE) {
+ (void) sprintf(state, "%s", "FAILED: DC "
+ "Power Failure");
+ exit_code = 1;
+ }
+
+ log_printf(" %2d %s\n", ps_ks.slot, state);
+ }
+
+ return (exit_code);
+}
+
+void
+tazjav_disp_asic_revs(Sys_tree *tree)
+{
+ Board_node *bnode;
+ Prom_node *pnode;
+ char *name;
+ int *version;
+ char *model;
+
+ /* Print the header */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(" HW Revisions ", 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ bnode = tree->bd_list;
+
+ log_printf("ASIC Revisions:\n", 0);
+ log_printf("---------------\n", 0);
+
+ /* Find sysio and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
+ pnode = dev_next_node(pnode, "sbus")) {
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ log_printf("SBus: %s Rev %d\n", name, *version, 0);
+ }
+ }
+
+ /* Find Psycho and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
+ pnode = dev_next_node(pnode, "pci")) {
+ Prom_node *parsib = pnode->parent->sibling;
+
+ if (find_prop(pnode, "upa-portid") == NULL) {
+ if ((parsib != NULL) &&
+ (strcmp(get_prop_val(
+ find_prop(parsib, "name")),
+ PCI_NAME) == 0))
+ pnode = parsib;
+ else {
+ pnode = parsib;
+ continue;
+ }
+ }
+
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL))
+ if (get_pci_bus(pnode) == 0)
+ log_printf("STP2223BGA: Rev %d\n", *version, 0);
+ }
+
+ /* Find Cheerio and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
+ pnode = dev_next_node(pnode, "ebus")) {
+ version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL))
+ log_printf("STP2003QFP: Rev %d\n", *version, 0);
+ }
+
+ /* Find System Controller and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL;
+ pnode = dev_next_node(pnode, "sc")) {
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ model = (char *)get_prop_val(find_prop(pnode, "model"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ if ((strcmp(model, "SUNW,sc-marvin") == 0))
+ log_printf("STP2205BGA: Rev %d\n", *version, 0);
+ }
+ }
+
+ /* Find the FEPS and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
+ pnode = dev_next_node(pnode, "SUNW,hme")) {
+ version = (int *)get_prop_val(find_prop(pnode, "hm-rev"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ log_printf("FEPS: %s Rev ", name);
+ if (*version == 0xa0) {
+ log_printf("2.0\n", 0);
+ } else if (*version == 0x20) {
+ log_printf("2.1\n", 0);
+ } else {
+ log_printf("%x\n", *version, 0);
+ }
+ }
+ }
+ log_printf("\n", 0);
+
+ if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) {
+ display_ffb(bnode, 0);
+ }
+}
+
+
+/*
+ * Determine the physical PCI slot based on which Psycho is the parent
+ * of the PCI card.
+ */
+static int
+tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str)
+{
+ int *upa_id = NULL;
+ int *reg = NULL;
+ int offset;
+ char controller[MAXSTRLEN];
+ char *name;
+ Prop *prop;
+ char *devpath_p;
+ char slotx[16] = "";
+ int *slot_names_mask;
+ char *slot_names;
+ int shift = 0;
+ int slot;
+ int slots, start_slot;
+
+ /*
+ * If slotd != NULL, then we must return the physical PCI slot
+ * number based on the information in the slot2dev associations
+ * node. This routine is called from display_pci() with slotd
+ * != NULL. If so, we return without obtaining the slot name.
+ * If slotd == NULL, we look for the slot name through the
+ * slot-names property in the bus node.
+ */
+
+ if (slotd != NULL) {
+ (void) strcpy(str, "");
+ if ((prop = find_prop(parent, "upa-portid")) != NULL)
+ upa_id = (int *)(get_prop_val(prop));
+ if ((prop = find_prop(parent, "reg")) != NULL)
+ reg = (int *)(get_prop_val(prop));
+ if ((prop = find_prop(parent, "name")) != NULL)
+ name = (char *)(get_prop_val(prop));
+ if ((upa_id == NULL) || (reg == NULL)) {
+ return (-1);
+ }
+ offset = reg[1];
+ if (strcmp(name, "pci") == 0) {
+ (void) sprintf(controller, "/pci@%x,%x/*@%x,*",
+ *upa_id, offset, device);
+ slots = 20;
+ } else if (strcmp(name, "SUNW,ffb") == 0) {
+ (void) sprintf(controller, "/*@%x,0", *upa_id);
+ slots = 2;
+ }
+
+ /*
+ * Javelin and future projects will use 0 based
+ * numbering for slots.
+ */
+ start_slot = 0;
+ slots = slots - 1;
+ for (slot = start_slot; slot <= slots; slot++) {
+ if (strcmp(name, "pci") == 0)
+ (void) sprintf(slotx, "pci-slot#%d", slot);
+ else if (strcmp(name, "SUNW,ffb") == 0)
+ (void) sprintf(slotx, "graphics#%d", slot);
+ if ((prop = find_prop(slotd, slotx)) != NULL)
+ if ((devpath_p = (char *)(get_prop_val
+ (prop))) != NULL)
+ if (strcmp(devpath_p, controller) ==
+ NULL)
+ return (slot);
+ }
+ return (-1);
+ }
+
+ /*
+ * Get slot-names property from parent node.
+ * This property consists of a 32 bit mask indicating which
+ * devices are relevant to this bus node. Following are a
+ * number of strings depending on how many bits are set in the
+ * bit mask; the first string gives the label that is printed
+ * on the chassis for the smallest device number, and so on.
+ */
+
+ prop = find_prop(parent, "slot-names");
+ if (prop == NULL) {
+ (void) strcpy(str, "");
+ return (-1);
+ }
+ slot_names_mask = (int *)(get_prop_val(prop));
+ slot_names = (char *)slot_names_mask;
+
+ slot = 1;
+ slot_names += 4; /* Skip the 4 byte bitmask */
+
+ while (shift < 32) {
+ /*
+ * Shift through the bitmask looking to see if the
+ * bit corresponding to "device" is set. If so, copy
+ * the correcsponding string to the provided pointer.
+ */
+ if (*slot_names_mask & slot) {
+ if (shift == device) {
+ (void) strcpy(str, slot_names);
+ return (0);
+ }
+ slot_names += strlen(slot_names)+1;
+ }
+ shift++;
+ slot = slot << 1;
+ }
+ return (-1);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/littleneck/Makefile b/usr/src/lib/libprtdiag_psr/sparc/littleneck/Makefile
new file mode 100644
index 0000000000..2520cbdc32
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/littleneck/Makefile
@@ -0,0 +1,84 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/littleneck/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= littleneck.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+IFLAGS += -I $(SRC)/cmd/picl/plugins/sun4u/psvc/psvcobj
+IFLAGS += -I$(UTSBASE)/sun4u
+
+LDLIBS += -lpicl
+
+LINTFLAGS += $(IFLAGS)
+
+#
+# Workgroup Server platform library should install into
+# SUNW,Ultra-4. All other desktop platforms can
+# link to /usr/platform/SUNW,Ultra-4/lib/libprtdiag_psr.so
+#
+PLATFORM=SUNW,Sun-Fire-280R
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/littleneck; pwd; $(MAKE) $(USR_PSM_LIB_DIR)
+
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+#
+# used for message files
+#
+POFILE= libprtdiag_psr_littleneck.po
+POFILES= littleneck.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/*.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/littleneck/common/littleneck.c b/usr/src/lib/libprtdiag_psr/sparc/littleneck/common/littleneck.c
new file mode 100644
index 0000000000..5eb6c4f1e4
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/littleneck/common/littleneck.c
@@ -0,0 +1,1072 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Littleneck Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_LITTLENECK
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <note.h>
+#include <syslog.h>
+
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+
+#include <pdevinfo.h>
+#include <display.h>
+#include <pdevinfo_sun4u.h>
+#include <display_sun4u.h>
+#include <libprtdiag.h>
+
+#include <picl.h>
+#include "workfile.c"
+
+#define LNECK_MAX_PS 2
+#define LNECK_MAX_DISKS 2
+#define LNECK_MAX_FANS 1
+
+#ifndef SCHIZO_COMPAT_PROP
+#define SCHIZO_COMPAT_PROP "pci108e,8001"
+#endif
+
+/* Count of failed PSU's found */
+int ps_failure = 0;
+
+/*
+ * Ignore first entry into disp_envc_status()
+ * from libprtdiag/common/display_sun4u.c
+ */
+int print_flag = 0;
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (workgroup server systems only)
+ */
+int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_cpu_devices(Sys_tree *tree);
+void display_pci(Board_node *board);
+void display_io_cards(struct io_card *list);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_ffb(Board_node *board, int table);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+
+/* local functions */
+static int disp_envc_status(void);
+static int lneck_env_print_temps(picl_nodehdl_t);
+static int lneck_env_print_keyswitch(picl_nodehdl_t);
+static int lneck_env_print_FSP_LEDS(picl_nodehdl_t);
+static int lneck_env_print_disk(picl_nodehdl_t);
+static int lneck_env_print_fans(picl_nodehdl_t);
+static int lneck_env_print_ps(picl_nodehdl_t);
+
+static void lneck_display_hw_revisions(Prom_node *root,
+ Board_node *bnode);
+static void display_schizo_revisions(Board_node *bdlist);
+
+/*
+ * Defining the error_check function in order to return the
+ * appropriate error code.
+ */
+/*ARGSUSED0*/
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ int exit_code = 0; /* init to all OK */
+ /* silently check for any types of machine errors */
+ print_flag = 0;
+ if (disp_fail_parts(tree) || disp_envc_status())
+ /* set exit_code to show failures */
+ exit_code = 1;
+
+ print_flag = 1;
+
+ return (exit_code);
+}
+
+void
+display_cpu_devices(Sys_tree *tree)
+{
+ Board_node *bnode;
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision of all cpus.
+ */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "========================= CPUs "
+ "==============================================="
+ "\n"
+ "\n"
+ " Run E$ CPU CPU \n"
+ "Brd CPU MHz MB Impl. Mask \n"
+ "--- --- ---- ---- ------- ---- \n"));
+
+ /* Now display all of the cpus on each board */
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ display_cpus(bnode);
+ bnode = bnode->next;
+ }
+
+ log_printf("\n");
+}
+
+
+/*
+ * Display the CPUs present on this board.
+ */
+void
+display_cpus(Board_node *board)
+{
+ Prom_node *cpu;
+ char cpu_name[] = "cpu";
+
+ /*
+ * display the CPUs' operating frequency, cache size, impl. field
+ * and mask revision.
+ */
+
+ for (cpu = dev_find_type(board->nodes, cpu_name); cpu != NULL;
+ cpu = dev_next_type(cpu, cpu_name)) {
+ int freq; /* CPU clock frequency */
+ int ecache_size; /* External cache size */
+ int *mid;
+ int *impl;
+ int *mask;
+
+ mid = (int *)get_prop_val(find_prop(cpu, "portid"));
+ freq = LNECK_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
+ ecache_size = get_ecache_size(cpu);
+ impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
+ mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
+
+ /* Do not display a failed CPU node */
+ if ((freq != 0) && (node_failed(cpu) == 0)) {
+ /* Board number */
+ switch (*mid) {
+ case 1:
+ log_printf(dgettext(TEXT_DOMAIN,
+ " B "));
+ break;
+ case 0:
+ log_printf(dgettext(TEXT_DOMAIN,
+ " A "));
+ break;
+ default:
+ log_printf(dgettext(TEXT_DOMAIN, "X "));
+ }
+
+ /* CPU MID */
+ log_printf("%2d ", *mid);
+
+ /* Module number */
+
+ /* Running frequency */
+ log_printf("%4d ", freq);
+
+ /* Ecache size */
+ if (ecache_size == 0)
+ log_printf("N/A ");
+ else
+ log_printf("%4.1f ",
+ (float)ecache_size / (float)(1<<20));
+
+ /* Implementation */
+ if (impl == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, "%6s "),
+ " N/A");
+ } else {
+ if (IS_CHEETAH(*impl))
+ log_printf("%-7s ", "US-III", 0);
+ else if (IS_CHEETAH_PLUS(*impl))
+ log_printf("%-7s ", "US-III+", 0);
+ else
+ log_printf("%-7x ", *impl, 0);
+ }
+
+ /* CPU Mask */
+ if (mask == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, " N/A "));
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN, " %d.%d "),
+ (*mask >> 4) & 0xf, *mask & 0xf);
+ }
+
+ log_printf("\n");
+ }
+ }
+}
+
+/*ARGSUSED0*/
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode = tree->bd_list;
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "========================= Memory Configuration"
+ " ===============================\n"
+ "\n Logical Logical Logical "
+ "\n MC Bank Bank Bank DIMM "
+ "Interleave Interleaved"
+ "\n Brd ID num size Status Size "
+ "Factor with"
+ "\n---- --- ---- ------ ----------- ------ "
+ "---------- -----------"));
+
+ while (bnode != NULL) {
+ if (get_us3_mem_regs(bnode)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nFailed to get memory information.\n"));
+ return;
+ }
+ bnode = bnode->next;
+ }
+
+ /* Display what we have found */
+ display_us3_banks();
+}
+
+/*ARGSUSED2*/
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is iof the user
+ * told us to do logging, and we found a system failure.
+ */
+
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ (void) disp_envc_status();
+
+ /* Hardware revision function calls */
+ lneck_display_hw_revisions(root, tree->bd_list);
+ log_printf("\n");
+ }
+ return;
+
+}
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+void
+display_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+ Prom_node *pci;
+ Prom_node *card_node;
+
+ char *slot_name_arr[LNECK_MAX_SLOTS_PER_IO_BD] = {NULL};
+ int i;
+
+ if (board == NULL)
+ return;
+
+ memset(&card, 0, sizeof (struct io_card));
+ /* Initialize all the common information */
+ card.display = TRUE;
+ card.board = board->board_num;
+
+ /*
+ * Search for each pci instance, then find/display all nodes under
+ * each instance node found.
+ */
+ for (pci = dev_find_node_by_compat(board->nodes, SCHIZO_COMPAT_PROP);
+ pci != NULL;
+ pci = dev_next_node_by_compat(pci, SCHIZO_COMPAT_PROP)) {
+ (void) snprintf(card.bus_type, MAXSTRLEN,
+ dgettext(TEXT_DOMAIN, "PCI"));
+ /*
+ * Get slot-name properties from parent node and
+ * store them in an array.
+ */
+ value = (char *)get_prop_val(
+ find_prop(pci, "slot-names"));
+
+ if (value != NULL) {
+ /* array starts after first int */
+ slot_name_arr[0] = (char *)value + sizeof (int);
+ for (i = 1; i < LNECK_MAX_SLOTS_PER_IO_BD; i++) {
+ slot_name_arr[i] = (char *)slot_name_arr[i - 1]
+ + strlen(slot_name_arr[i - 1]) +1;
+ }
+ }
+ /*
+ * Search for Children of this node ie. Cards.
+ * Note: any of these cards can be a pci-bridge
+ * that itself has children. If we find a
+ * pci-bridge we need to handle it specially.
+ */
+ card_node = pci->child;
+ /* Generate the list of pci cards on pci instance: pci */
+ fill_pci_card_list(pci, card_node, &card, &card_list,
+ slot_name_arr);
+ } /* end-for */
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+ log_printf("\n");
+}
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL) {
+ return;
+ }
+
+ if (banner == FALSE) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ " Bus Max\n"
+ " IO Port Bus Freq Bus Dev,\n"
+ "Brd Type ID Side Slot MHz Freq Func State "
+ "Name "
+#ifdef DEBUG
+ "Model Notes\n"));
+#else
+ "Model\n"));
+#endif
+ /* ---------Node Brd IO Port Bus Slot Bus Max Dev Stat */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "---- ---- ---- ---- ---- ---- ---- ---- ----- "
+ "-------------------------------- "
+#ifdef DEBUG
+ "---------------------- "
+#endif
+ "----------------------\n"));
+ banner = TRUE;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf(dgettext(TEXT_DOMAIN, "I/O "));
+ log_printf(dgettext(TEXT_DOMAIN, "%-4s "), p->bus_type);
+ log_printf(dgettext(TEXT_DOMAIN, "%-3d "),
+ p->schizo_portid);
+ log_printf(dgettext(TEXT_DOMAIN, "%c "), p->pci_bus);
+ log_printf(dgettext(TEXT_DOMAIN, "%-1s "), p->slot_str);
+ log_printf(dgettext(TEXT_DOMAIN, "%-3d "), p->freq);
+ switch (p->pci_bus) {
+ case 'A':
+ log_printf(dgettext(TEXT_DOMAIN, " 66 "));
+ break;
+ case 'B':
+ log_printf(dgettext(TEXT_DOMAIN, " 33 "));
+ break;
+ default:
+ log_printf(dgettext(TEXT_DOMAIN, " - "));
+ break;
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "%-1d,%-1d "),
+ p->dev_no, p->func_no);
+ log_printf(dgettext(TEXT_DOMAIN, "%-5s "), p->status);
+ log_printf(dgettext(TEXT_DOMAIN, "%-32.32s"), p->name);
+ if (strlen(p->name) > 32)
+ log_printf(dgettext(TEXT_DOMAIN, "+ "));
+ else
+ log_printf(dgettext(TEXT_DOMAIN, " "));
+ log_printf(dgettext(TEXT_DOMAIN, "%-22.22s"), p->model);
+ if (strlen(p->model) > 22)
+ log_printf(dgettext(TEXT_DOMAIN, "+"));
+#ifdef DEBUG
+ log_printf("%s ", p->notes);
+#endif
+ log_printf("\n");
+ }
+}
+
+/*
+ * display_ffb
+ *
+ * There are no FFB's on a Littleneck, however in the generic library,
+ * the display_ffb() function is implemented so we have to define an
+ * empty function here.
+ */
+/*ARGSUSED0*/
+void
+display_ffb(Board_node *board, int table)
+{}
+
+
+/*
+ * local functions
+ */
+
+/*
+ * disp_fail_parts
+ *
+ * Display the failed parts in the system. This function looks for
+ * the status property in all PROM nodes. On systems where
+ * the PROM does not support passing diagnostic information
+ * through the device tree, this routine will be silent.
+ */
+int
+disp_fail_parts(Sys_tree *tree)
+{
+ int exit_code = 0;
+ int system_failed = 0;
+ Board_node *bnode = tree->bd_list;
+ Prom_node *pnode;
+
+ /* go through all of the boards looking for failed units. */
+ while (bnode != NULL) {
+ /* find failed chips */
+ pnode = find_failed_node(bnode->nodes);
+ if ((pnode != NULL) && !system_failed) {
+ system_failed = 1;
+ exit_code = 1;
+ if (print_flag == 0) {
+ return (exit_code);
+ }
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
+ "Replaceable Units (FRU) in System:\n"));
+ log_printf("=========================="
+ "====================\n");
+ }
+ while (pnode != NULL) {
+ void *value;
+ char *name; /* node name string */
+ char *type; /* node type string */
+ char *board_type = NULL;
+
+ value = get_prop_val(find_prop(pnode, "status"));
+ name = get_node_name(pnode);
+
+ /* sanity check of data retrieved from PROM */
+ if ((value == NULL) || (name == NULL)) {
+ pnode = next_failed_node(pnode);
+ continue;
+ }
+
+ /* Find the board type of this board */
+ if (bnode->board_type == CPU_BOARD) {
+ board_type = "CPU";
+ } else {
+ board_type = "IO";
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "%s unavailable "
+ "on %s Board #%d\n"), name, board_type,
+ bnode->board_num);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tPROM fault string: %s\n"), value);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tFailed Field Replaceable Unit is "));
+
+ /*
+ * Determine whether FRU is CPU module, system
+ * board, or SBus card.
+ */
+ if ((name != NULL) && (strstr(name, "sbus"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "SBus Card %d\n"),
+ get_sbus_slot(pnode));
+
+ } else if (((name = get_node_name(pnode->parent)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "PCI Card %d"),
+ get_pci_device(pnode));
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "cpu"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN, "UltraSPARC "
+ "module Board %d Module %d\n"), 0,
+ get_id(pnode));
+
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%s board %d\n"), board_type,
+ bnode->board_num);
+ }
+ pnode = next_failed_node(pnode);
+ }
+ bnode = bnode->next;
+ }
+
+ if (!system_failed) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "No failures found in System\n"));
+ log_printf("===========================\n\n");
+ return (0);
+ } else {
+ return (1);
+ }
+}
+
+
+/*
+ * disp_envc_status
+ *
+ * This routine displays the environmental status passed up from
+ * device drivers via the envlibobj.so library.
+ * This is a Littleneck specific environmental information display routine.
+ */
+static int
+disp_envc_status(void)
+{
+ int err;
+ char *system = "SYSTEM";
+ picl_nodehdl_t system_node, root;
+
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN, "========================="
+ " Environmental Status =========================\n\n"));
+
+ err = picl_initialize();
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Cannot print environmental information\n"
+ "picl_initialize failed\n"
+ "%s\n"), picl_strerror(err));
+ }
+
+ if (err == PICL_SUCCESS) {
+ err = picl_get_root(&root);
+ err = find_child_device(root, system, &system_node);
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Cannot print environmental information\n"
+ "find_child_device for the SYSTEM node "
+ "failed\n"
+ "%s\n"), picl_strerror(err));
+ }
+
+ if ((err = lneck_env_print_temps(system_node)) !=
+ PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Temperature Checking failed: %s\n"),
+ picl_strerror(err));
+ }
+ if ((err = lneck_env_print_keyswitch(system_node)) !=
+ PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Keyswitch information checking failed: %s\n"),
+ picl_strerror(err));
+ }
+ if ((err = lneck_env_print_FSP_LEDS(system_node)) !=
+ PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "FSP LED information checking failed: %s\n"),
+ picl_strerror(err));
+ }
+ if ((err = lneck_env_print_disk(system_node)) !=
+ PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Disk information checking failed: %s\n"),
+ picl_strerror(err));
+ }
+ if ((err = lneck_env_print_fans(system_node)) !=
+ PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Fan information checking failed: %s\n"),
+ picl_strerror(err));
+ }
+ if ((err = lneck_env_print_ps(system_node)) !=
+ PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Power Supply information checking failed: "
+ "%s\n"), picl_strerror(err));
+ } else if (ps_failure != 0)
+ err = PICL_FAILURE;
+ }
+ return (err);
+}
+
+int
+lneck_env_print_ps(picl_nodehdl_t system_node)
+{
+ int i, err = 0;
+ int32_t number;
+ picl_nodehdl_t *ps;
+ picl_nodehdl_t ps_fail[2], ps_type[2];
+ char name[PICL_PROPNAMELEN_MAX];
+ boolean_t type;
+ char fault_state[PICL_PROPNAMELEN_MAX];
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Power Supplies:\n"
+ "---------------\n"
+ "Supply Status PS Type\n"
+ "------ ------ ---------------\n"));
+ err = fill_device_array_from_id(system_node, "PSVC_PS", &number,
+ &ps);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ for (i = 0; i < LNECK_MAX_PS; i++) {
+ err = picl_get_propval_by_name(ps[i], PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, "%6-s"), name);
+ } else continue;
+
+ err = picl_get_propval_by_name(ps[i], "FaultInformation",
+ fault_state, PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ if ((strlen(fault_state) == 0) ||
+ (strcmp(fault_state, "NO_FAULT") == 0)) {
+ strcpy(fault_state, "OK");
+ } else
+ /*
+ * Bump up count if fault_state !OK
+ */
+ ps_failure++;
+
+ log_printf(dgettext(TEXT_DOMAIN, " [%-6s] "),
+ fault_state);
+ } else {
+ return (err);
+ }
+
+ err = fill_device_from_id(ps[i], "PSVC_DEV_FAULT_SENSOR",
+ &ps_fail[i]);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ err = fill_device_from_id(ps[i], "PSVC_DEV_TYPE_SENSOR",
+ &ps_type[i]);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+ err = picl_get_propval_by_name(ps_type[i], "Gpio-value", &type,
+ sizeof (boolean_t));
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, " [%13s]"),
+ type == 0 ? "Quahog/Razor" : "Sun-Fire-280R");
+ if (type == 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "WARNING: PS is of the wrong type\n"));
+ } else log_printf("\n");
+ } else {
+ return (err);
+ }
+
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "================================="
+ "\n"
+ "\n"));
+
+ /*
+ * Do not display an error message just because PS1 is
+ * not present.
+ */
+ if (err == PICL_INVALIDHANDLE) {
+ err = PICL_SUCCESS;
+ }
+
+ return (err);
+}
+
+int
+lneck_env_print_fans(picl_nodehdl_t system_node) {
+ int i, err = 0;
+ int32_t number;
+ picl_nodehdl_t *fans;
+ picl_nodehdl_t fan_fault[1];
+ char fault_state[PICL_PROPNAMELEN_MAX];
+ char name[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_FAN", &number,
+ &fans);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "=================================\n"
+ "\n"
+ "Fan Bank :\n"
+ "----------\n"
+ "\n"
+ "Bank Status\n"
+ "---- -------\n"));
+
+ for (i = 0; i < LNECK_MAX_FANS; i++) {
+ err = picl_get_propval_by_name(fans[i], PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, "%16-s"), name);
+ } else continue;
+
+ err = fill_device_from_id(fans[i], "PSVC_DEV_FAULT_SENSOR",
+ &fan_fault[i]);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(fans[i], "FaultInformation",
+ &fault_state, PICL_PROPNAMELEN_MAX);
+
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, " [%3s]\n"),
+ fault_state);
+ } else {
+ return (err);
+ }
+ }
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "================================="
+ "\n"
+ "\n"));
+
+ return (err);
+}
+
+int
+lneck_env_print_disk(picl_nodehdl_t system_node) {
+ int i, err = 0;
+ int32_t number;
+ picl_nodehdl_t *disks;
+ char fault_state[PICL_PROPNAMELEN_MAX];
+ char name[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_DISK", &number,
+ &disks);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Disk Status:\n"
+ " Presence Fault Value\n"
+ " -------- -----------\n"));
+
+ for (i = 0; i < LNECK_MAX_DISKS; i++) {
+ err = picl_get_propval_by_name(disks[i], PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+ switch (err) {
+ case PICL_SUCCESS:
+ log_printf(dgettext(TEXT_DOMAIN,
+ "DISK %2d: [PRESENT]"), i);
+ break;
+ case PICL_INVALIDHANDLE:
+ log_printf(dgettext(TEXT_DOMAIN,
+ "DISK %2d: [EMPTY ]\n"), i);
+ continue;
+ default:
+ return (err);
+ }
+ err = picl_get_propval_by_name(disks[i], "FaultInformation",
+ &fault_state, PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, " [%3s]"),
+ fault_state);
+ } else {
+ if (err != PICL_INVALIDHANDLE)
+ return (err);
+ }
+ log_printf("\n");
+ }
+
+ if (err == PICL_INVALIDHANDLE) {
+ err = PICL_SUCCESS;
+ }
+
+ return (err);
+}
+
+int
+lneck_env_print_FSP_LEDS(picl_nodehdl_t system_node) {
+ int err;
+ int32_t number;
+ picl_nodehdl_t *fsp_led;
+ char fault_state[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_FSP_LED", &number,
+ &fsp_led);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System LED Status: POWER GEN FAULT\n"
+ " [ ON]"));
+ err = picl_get_propval_by_name(fsp_led[0], "State", &fault_state,
+ PICL_PROPNAMELEN_MAX);
+ if (err == PICL_SUCCESS) {
+ log_printf(" [%3s]", fault_state);
+ } else {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n"
+ "\n"
+ "================================="
+ "\n"
+ "\n"));
+
+ return (err);
+}
+
+int
+lneck_env_print_keyswitch(picl_nodehdl_t system_node) {
+ int err = 0;
+ picl_nodehdl_t *keyswitch;
+ int32_t number;
+ char ks_pos[PICL_PROPNAMELEN_MAX];
+
+ err = fill_device_array_from_id(system_node, "PSVC_KEYSWITCH", &number,
+ &keyswitch);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+ err = picl_get_propval_by_name(keyswitch[0], "State", ks_pos,
+ PICL_PROPNAMELEN_MAX);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Front Status Panel:\n"
+ "-------------------\n"
+ "Keyswitch position: %s\n"), ks_pos);
+ log_printf("\n");
+
+ return (err);
+}
+
+int
+lneck_env_print_temps(picl_nodehdl_t system_node) {
+ int i, err = 0;
+ picl_nodehdl_t *system_ts_nodes;
+ int32_t temp, number;
+
+ err = fill_device_array_from_id(system_node, "PSVC_TS", &number,
+ &system_ts_nodes);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System Temperatures (Celsius):\n"
+ "------------------------------\n"
+ "cpu0 1 \n"
+ "---------\n"));
+
+ for (i = 0; i < 2; i++) {
+ err = picl_get_propval_by_name(system_ts_nodes[i],
+ "Temperature", &temp, sizeof (temp));
+ if (err == PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN, " %02d"), temp);
+ } else {
+ if (err == PICL_INVALIDHANDLE) {
+ err = PICL_SUCCESS;
+ log_printf(dgettext(TEXT_DOMAIN, " xx"));
+ } else {
+ return (err);
+ }
+ }
+ }
+
+ log_printf("\n");
+ log_printf("\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "=================================\n"));
+ log_printf("\n");
+
+ return (err);
+}
+
+static void
+lneck_display_hw_revisions(Prom_node *root, Board_node *bdlist)
+{
+ Prom_node *pnode;
+ char *value;
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n"
+ "========================= HW Revisions "
+ "=======================================\n\n"));
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System PROM revisions:\n"
+ "----------------------\n"));
+
+ pnode = dev_find_node(root, "openprom");
+ if (pnode != NULL) {
+ value = (char *)get_prop_val(find_prop(pnode, "version"));
+ log_printf(value);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n\n"
+ "IO ASIC revisions:\n"
+ "------------------\n"
+ " Port\n"
+ "Model ID Status Version\n"
+ "-------- ---- ------ -------\n"));
+
+ display_schizo_revisions(bdlist);
+}
+
+static void
+display_schizo_revisions(Board_node *bdlist)
+{
+ Prom_node *pnode;
+ int *int_val;
+ int portid;
+ int prev_portid = -1;
+ char *status_a = NULL;
+ char *status_b = NULL;
+ int revision;
+#ifdef DEBUG
+ uint32_t a_notes, b_notes;
+#endif
+ int pci_bus;
+ Board_node *bnode;
+ bnode = bdlist;
+
+ while (bnode != NULL) {
+ /*
+ * search this board node for all Schizos
+ */
+
+ for (pnode = dev_find_node_by_compat(bnode->nodes,
+ SCHIZO_COMPAT_PROP); pnode != NULL;
+ pnode = dev_next_node_by_compat(pnode,
+ SCHIZO_COMPAT_PROP)) {
+
+ /*
+ * get the reg property to determine
+ * whether we are looking at side A or B
+ */
+
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "reg"));
+ if (int_val != NULL) {
+ int_val ++; /* second integer in array */
+ pci_bus = ((*int_val) & 0x7f0000);
+ }
+
+ /* get portid */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "portid"));
+ if (int_val == NULL)
+ continue;
+
+ portid = *int_val;
+
+ /*
+ * If this is a new portid and it is PCI bus B,
+ * we skip onto the PCI bus A.
+ */
+ if ((portid != prev_portid) && (pci_bus == 0x700000)) {
+ prev_portid = portid;
+ /* status */
+ status_b = (char *)get_prop_val
+ (find_prop(pnode, "status"));
+#ifdef DEBUG
+ b_notes = pci_bus;
+#endif
+ continue; /* skip to the next schizo */
+ }
+
+ /*
+ * This must be side A of the same Schizo.
+ * Gather all its props and display them.
+ */
+#ifdef DEBUG
+ a_notes = pci_bus;
+#endif
+
+ prev_portid = portid;
+
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "version#"));
+ if (int_val != NULL)
+ revision = *int_val;
+ else
+ revision = -1;
+
+ status_a = (char *)get_prop_val(find_prop
+ (pnode, "status"));
+
+ log_printf(dgettext(TEXT_DOMAIN, "Schizo "));
+
+ log_printf(dgettext(TEXT_DOMAIN, "%-3d "), portid, 0);
+
+
+ log_printf((status_a == NULL && status_b == NULL) ?
+ dgettext(TEXT_DOMAIN, " ok ") :
+ dgettext(TEXT_DOMAIN, " fail "));
+
+ log_printf(dgettext(TEXT_DOMAIN, " %4d "),
+ revision);
+#ifdef DEBUG
+ log_printf(" 0x%x 0x%x", a_notes, b_notes);
+#endif
+ log_printf("\n");
+ }
+ bnode = bnode->next;
+ }
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/littleneck/common/workfile.c b/usr/src/lib/libprtdiag_psr/sparc/littleneck/common/workfile.c
new file mode 100644
index 0000000000..c27d5ce5c2
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/littleneck/common/workfile.c
@@ -0,0 +1,955 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2000, 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Littleneck Platform specific functions.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libprtdiag.h>
+#include <sys/mc.h>
+
+
+static Prom_node *dev_next_node_by_compat(Prom_node *root, char *model);
+static Prom_node *dev_find_node_by_compat(Prom_node *root, char *model);
+
+static Board_node *littleneck_insert_board(Sys_tree *root, int board);
+static Board_node *littleneck_find_board(Sys_tree *root, int board);
+
+void print_us3_memory_line(int portid,
+ int bank_id,
+ uint64_t bank_size,
+ char *bank_status,
+ uint64_t dimm_size,
+ uint32_t intlv,
+ int seg_id);
+
+void add_node(Sys_tree *root, Prom_node *pnode);
+int do_prominfo(int syserrlog,
+ char *pgname,
+ int log_flag,
+ int prt_flag);
+
+void *get_prop_val(Prop *prop);
+Prop *find_prop(Prom_node *pnode, char *name);
+char *get_node_name(Prom_node *pnode);
+char *get_node_type(Prom_node *pnode);
+
+void fill_pci_card_list(Prom_node *pci_instance,
+ Prom_node *pci_card_node,
+ struct io_card *pci_card,
+ struct io_card **pci_card_list,
+ char **pci_slot_name_arr);
+
+static Prom_node *next_pci_card(Prom_node *curr_card, int *is_bridge,
+ int is_pcidev, Prom_node *curr_bridge,
+ Prom_node * parent_bridge, Prom_node *pci);
+
+
+#define LNECK_MAX_SLOTS_PER_IO_BD 9
+#define LNECK_CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000)
+
+/* This is stuff to get the HW Revisions stuff to work */
+
+#define LNECK_SAFARI_ID_MASK 0x1F /* 5 bits */
+#define LNECK_NODE_MASK 0x1F /* 5 bits */
+#define LNECK_PORTID_NODE_SHIFT 5
+#define LNECK_MIN_CPU_SAFARI_ID 0 /* 0x00 */
+#define LNECK_MAX_CPU_SAFARI_ID 23 /* 0x17 */
+#define LNECK_MIN_IO_SAFARI_ID 24 /* 0x18 */
+#define LNECK_MAX_IO_SAFARI_ID 31 /* 0x1F */
+#define NUM_MBANKS_PER_MC 4
+
+/*
+ * LNECK_PORTID_TO_SAFARI_ID
+ *
+ * Calculates the Safari Agent ID from the portid.
+ */
+#define LNECK_PORTID_TO_SAFARI_ID(portid) ((portid) & LNECK_SAFARI_ID_MASK)
+
+/*
+ * LNECK_PORTID_IS_CPU_TYPE
+ *
+ * If the portid associated with a CPU board is passed in, TRUE is returned,
+ * otherwise FALSE.
+ */
+#define LNECK_PORTID_IS_CPU_TYPE(portid) \
+ (((((portid) & LNECK_SAFARI_ID_MASK) >= LNECK_MIN_CPU_SAFARI_ID) && \
+ (((portid) & LNECK_SAFARI_ID_MASK) <= LNECK_MAX_CPU_SAFARI_ID)) ? \
+ TRUE: FALSE)
+
+/*
+ * LNECK_PORTID_TO_NODEID
+ *
+ * Calculates the SSM NodeID from the portid
+ */
+#define LNECK_PORTID_TO_NODEID(portid) (((portid) >> LNECK_PORTID_NODE_SHIFT) \
+ & LNECK_NODE_MASK)
+
+/*
+ * LNECK_CPU_BD_PORTID_TO_BD_NUM
+ *
+ * If the portid associated with a CPU board is passed in, the board number
+ * associated with this portid is returned, otherwise -1.
+ */
+#define LNECK_CPU_BD_PORTID_TO_BD_NUM(portid) \
+ ((LNECK_PORTID_IS_CPU_TYPE(portid)) ? \
+ (((portid) & LNECK_SAFARI_ID_MASK) / 4) : (-1))
+
+/*
+ * LNECK_PORTID_IS_IO_TYPE
+ *
+ * If the portid associated with an IO board is passed in, TRUE is returned,
+ * otherwise FALSE.
+ */
+#define LNECK_PORTID_IS_IO_TYPE(portid) \
+ (((((portid) & LNECK_SAFARI_ID_MASK) >= LNECK_MIN_IO_SAFARI_ID) && \
+ (((portid) & LNECK_SAFARI_ID_MASK) <= LNECK_MAX_IO_SAFARI_ID)) ? \
+ TRUE: FALSE)
+
+/*
+ * LNECK_IO_BD_PORTID_TO_BD_NUM
+ *
+ * If the portid associated with an IO board is passed in, the board number
+ * associated with this portid is returned, otherwise -1.
+ */
+#define LNECK_IO_BD_PORTID_TO_BD_NUM(portid) \
+ (LNECK_PORTID_IS_IO_TYPE(portid) ? \
+ (((((portid) & LNECK_SAFARI_ID_MASK) - 24) / 2) + 6) : (-1))
+
+/*
+ * LNECK_PORTID_TO_BOARD_NUM
+ *
+ * If a valid portid is passed in, this macro returns the board number
+ * associated with it, otherwise it returns -1.
+ */
+#define LNECK_PORTID_TO_BOARD_NUM(portid) \
+ ((LNECK_PORTID_IS_CPU_TYPE(portid)) ? \
+ (LNECK_CPU_BD_PORTID_TO_BD_NUM(portid)) : \
+ ((LNECK_PORTID_IS_IO_TYPE(portid)) ? \
+ LNECK_IO_BD_PORTID_TO_BD_NUM(portid) : (-1)))
+
+
+/*
+ * Start from the current node and return the next node besides
+ * the current one which has the requested model property.
+ */
+static Prom_node *
+dev_next_node_by_compat(Prom_node *root, char *compat)
+{
+ Prom_node *node;
+
+ if (root == NULL)
+ return (NULL);
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+/*
+ * Do a depth-first walk of a device tree and
+ * return the first node with the matching model.
+ */
+static Prom_node *
+dev_find_node_by_compat(Prom_node *root, char *compat)
+{
+ Prom_node *node;
+ char *compatible;
+ char *name;
+
+ if (root == NULL)
+ return (NULL);
+
+ if (compat == NULL)
+ return (NULL);
+
+ name = get_node_name(root);
+ if (name == NULL)
+ name = "";
+
+ compatible = (char *)get_prop_val(find_prop(root, "compatible"));
+
+ if (compatible == NULL)
+ return (NULL);
+
+ if ((strcmp(name, "pci") == 0) && (compatible != NULL) &&
+ (strcmp(compatible, compat) == 0)) {
+ return (root); /* found a match */
+ }
+
+ /* look at your children first */
+ if ((node = dev_find_node_by_compat(root->child, compat)) != NULL)
+ return (node);
+
+ /* now look at your siblings */
+ if ((node = dev_find_node_by_compat(root->sibling, compat)) != NULL)
+ return (node);
+
+ return (NULL); /* not found */
+}
+
+int32_t
+find_child_device(picl_nodehdl_t parent, char *child_name,
+ picl_nodehdl_t *child)
+{
+ int32_t err;
+ char name[PICL_PROPNAMELEN_MAX];
+
+ err = picl_get_propval_by_name(parent, PICL_PROP_CHILD, &(*child),
+ sizeof (picl_nodehdl_t));
+ switch (err) {
+ case PICL_SUCCESS:
+ break;
+ case PICL_PROPNOTFOUND:
+ err = PICL_INVALIDHANDLE;
+ return (err);
+ default:
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed picl_get_propval_by_name with %s\n"),
+ picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(*child, PICL_PROP_NAME, name,
+ PICL_PROPNAMELEN_MAX);
+
+#ifdef WORKFILE_DEBUG
+ if (err != PICL_SUCCESS) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed the get name for root\n"));
+ log_printf(dgettext(TEXT_DOMAIN, "%s\n"), picl_strerror(err));
+ }
+#endif
+
+ if (strcmp(name, child_name) == 0)
+ return (err);
+
+ while (err != PICL_PROPNOTFOUND) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN, "child name is %s\n"), name);
+#endif
+ err = picl_get_propval_by_name(*child, PICL_PROP_PEER,
+ &(*child), sizeof (picl_nodehdl_t));
+ switch (err) {
+ case PICL_SUCCESS:
+ err = picl_get_propval_by_name(*child, PICL_PROP_NAME,
+ name, PICL_PROPNAMELEN_MAX);
+ if (strcmp(name, child_name) == 0)
+ return (err);
+ break;
+ case PICL_PROPNOTFOUND:
+ break;
+ default:
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed picl_get_propval_by_name with %s\n"),
+ picl_strerror(err));
+#endif
+ return (err);
+ }
+ }
+ err = PICL_INVALIDHANDLE;
+ return (err);
+}
+
+int32_t
+fill_device_from_id(picl_nodehdl_t device_id, char *assoc_id,
+ picl_nodehdl_t *device)
+{
+ int32_t err;
+ picl_prophdl_t tbl_hdl;
+ picl_prophdl_t reference_property;
+
+ err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
+ sizeof (picl_prophdl_t));
+ if (err != PICL_SUCCESS) {
+#ifdef WORKFILE_DEBUG
+ if (err != PICL_INVALIDHANDLE) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in "
+ "picl_get_propval_by_name err is %s\n"),
+ picl_strerror(err));
+ }
+#endif
+ return (err);
+ }
+
+ err = picl_get_next_by_row(tbl_hdl, &reference_property);
+ if (err != PICL_SUCCESS) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in picl_get_next_by_row"
+ " err is %s\n"), picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ /* get node associated with reference property */
+ err = picl_get_propval(reference_property, &(*device),
+ sizeof (picl_nodehdl_t));
+
+#ifdef WORKFILE_DEBUG
+ if (err != 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_from_id failure in picl_get_propval"
+ " err is %s\n"), picl_strerror(err));
+ }
+#endif
+
+ return (err);
+}
+
+int32_t
+fill_device_array_from_id(picl_nodehdl_t device_id, char *assoc_id,
+ int32_t *number_of_devices, picl_nodehdl_t *device_array[])
+{
+ int32_t err;
+ int i;
+ picl_prophdl_t tbl_hdl;
+ picl_prophdl_t entry;
+ int devs = 0;
+
+ err = picl_get_propval_by_name(device_id, assoc_id, &tbl_hdl,
+ sizeof (picl_prophdl_t));
+ if ((err != PICL_SUCCESS) && (err != PICL_INVALIDHANDLE)) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_propval_by_name err is %s\n"), picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ entry = tbl_hdl;
+ while (picl_get_next_by_row(entry, &entry) == 0)
+ ++devs;
+
+ *device_array = calloc((devs), sizeof (picl_nodehdl_t));
+ if (*device_array == NULL) {
+
+#ifdef WORFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure getting memory"
+ " for array\n"));
+#endif
+ return (PICL_FAILURE);
+ }
+
+ entry = tbl_hdl;
+ for (i = 0; i < devs; i++) {
+ err = picl_get_next_by_row(entry, &entry);
+ if (err != 0) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_next_by_row err is %s\n"),
+ picl_strerror(err));
+#endif
+ return (err);
+ }
+
+ /* get node associated with reference property */
+ err = picl_get_propval(entry, &((*device_array)[i]),
+ sizeof (picl_nodehdl_t));
+ if (err != 0) {
+#ifdef WORKFILE_DEBUG
+ log_printf(dgettext(TEXT_DOMAIN,
+ "fill_device_array_from_id failure in "
+ "picl_get_propval err is %s\n"), picl_strerror(err));
+#endif
+
+ return (err);
+ }
+ }
+ *number_of_devices = devs;
+ return (err);
+}
+
+/*
+ * Add a board to the system list in order (sorted by board#).
+ * Initialize all pointer fields to NULL.
+ */
+static Board_node *
+littleneck_insert_board(Sys_tree *root, int board)
+{
+ Board_node *bnode;
+ Board_node *temp = root->bd_list;
+
+ if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ bnode->nodes = NULL;
+ bnode->next = NULL;
+ bnode->board_num = board;
+
+ bnode->board_type = UNKNOWN_BOARD;
+
+ if (temp == NULL)
+ root->bd_list = bnode;
+
+ else if (temp->board_num > board) {
+ bnode->next = temp;
+ root->bd_list = bnode;
+
+ } else {
+ while ((temp->next != NULL) && (board > temp->next->board_num))
+ temp = temp->next;
+
+ bnode->next = temp->next;
+ temp->next = bnode;
+ }
+ root->board_cnt++;
+
+ return (bnode);
+}
+
+/*
+ * Find the requested board struct in the system device tree.
+ *
+ * This function overrides the functionality of the generic find_board()
+ * function in libprtdiag, but since we need to pass another parameter,
+ * we cannot simply overlay the symbol table.
+ */
+static Board_node *
+littleneck_find_board(Sys_tree *root, int board)
+{
+ Board_node *bnode = root->bd_list;
+
+ while ((bnode != NULL) && (board != bnode->board_num)) {
+ bnode = bnode->next;
+ }
+ return (bnode);
+}
+
+/*
+ * add_node
+ *
+ * This function adds a board node to the board structure where that
+ * that node's physical component lives.
+ */
+void
+add_node(Sys_tree *root, Prom_node *pnode)
+{
+ int board = -1;
+ int portid = -1;
+
+ void *value = NULL;
+ Board_node *bnode = NULL;
+ Prom_node *p = NULL;
+
+ /* Get the board number of this board from the portid prop */
+ value = get_prop_val(find_prop(pnode, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+
+ board = LNECK_PORTID_TO_BOARD_NUM(portid);
+
+ /* find the board node with the same board number */
+ if ((bnode = littleneck_find_board(root, board)) == NULL) {
+ bnode = littleneck_insert_board(root, board);
+ }
+
+ /* now attach this prom node to the board list */
+ /* Insert this node at the end of the list */
+ pnode->sibling = NULL;
+ if (bnode->nodes == NULL)
+ bnode->nodes = pnode;
+ else {
+ p = bnode->nodes;
+ while (p->sibling != NULL)
+ p = p->sibling;
+ p->sibling = pnode;
+ }
+}
+
+/*
+ * This function provides formatting of the memory config
+ * information that get_us3_mem_regs() and display_us3_banks() code has
+ * gathered. It overrides the generic print_us3_memory_line() code
+ * which prints an error message.
+ */
+void
+print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
+{
+ int mcid;
+ char board_id[2];
+ board_id[0] = 'A'; /* it will usually be, A, there's only one mc! */
+ board_id[1] = 'B'; /* redundant. */
+ mcid = LNECK_PORTID_TO_SAFARI_ID(portid);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n C%-1c %2d %2d %4lldMB %11-s %4lldMB "
+ " %2d-way %d"),
+ board_id[portid], mcid, (bank_id % 4), bank_size,
+ bank_status, dimm_size, intlv, seg_id, 0);
+}
+
+/*
+ * We call do_devinfo() in order to use the libdevinfo device tree
+ * instead of OBP's device tree.
+ */
+int
+do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+ return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
+}
+
+/*
+ * return the property value for the Prop
+ * passed in. (When using libdevinfo)
+ */
+void *
+get_prop_val(Prop *prop)
+{
+ if (prop == NULL)
+ return (NULL);
+
+ return ((void *)(prop->value.val_ptr));
+}
+
+/*
+ * Search a Prom node and retrieve the property with the correct
+ * name. (When using libdevinfo)
+ */
+Prop *
+find_prop(Prom_node *pnode, char *name)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ if (pnode->props == NULL)
+ return (NULL);
+
+ prop = pnode->props;
+ if (prop == NULL)
+ return (NULL);
+
+ if (prop->name.val_ptr == NULL)
+ return (NULL);
+
+ while ((prop != NULL) && (strcmp((char *)(prop->name.val_ptr), name))) {
+ prop = prop->next;
+ }
+ return (prop);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property.
+ * (When using libdevinfo)
+ */
+char *
+get_node_name(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("name", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the device_type property.
+ * (When using libdevinfo)
+ */
+char *
+get_node_type(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+
+/*
+ * Fills in the i/o card list to be displayed later in display_pci();
+ */
+void
+fill_pci_card_list(Prom_node * pci_instance, Prom_node * pci_card_node,
+ struct io_card *pci_card,
+ struct io_card **pci_card_list, char **slot_name_arr)
+{
+ Prom_node *pci_bridge_node;
+ Prom_node *pci_parent_bridge;
+ int *int_val;
+ int pci_bridge = FALSE;
+ int pci_bridge_dev_no = -1;
+ int portid;
+ int pci_bus;
+ char buf[MAXSTRLEN];
+ char *slot_name = NULL; /* info in "slot-names" prop */
+ char *child_name;
+ char *name;
+ char *type;
+ void *value;
+
+ while (pci_card_node != NULL) {
+ int is_pci = FALSE;
+ type = NULL;
+ name = NULL;
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(pci_card_node, "name"));
+ if (name == NULL) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+ /*
+ * Get the portid of the schizo that this card
+ * lives under.
+ */
+ portid = -1;
+ value = get_prop_val(find_prop(pci_instance, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+ pci_card->schizo_portid = portid;
+ /*
+ * Find out whether this is PCI bus A or B
+ * using the 'reg' property.
+ */
+ int_val = (int *)get_prop_val(find_prop(pci_instance, "reg"));
+
+ if (int_val != NULL) {
+ int_val++; /* skip over first integer */
+ pci_bus = ((*int_val) & 0x7f0000);
+ if (pci_bus == 0x600000)
+ pci_card->pci_bus = 'A';
+ else if (pci_bus == 0x700000)
+ pci_card->pci_bus = 'B';
+ else
+ pci_card->pci_bus = '-';
+ } else {
+ pci_card->pci_bus = '-';
+ }
+ /*
+ * get dev# and func# for this card from the
+ * 'reg' property.
+ */
+ int_val = (int *)get_prop_val(
+ find_prop(pci_card_node, "reg"));
+ if (int_val != NULL) {
+ pci_card->dev_no = (((*int_val) & 0xF800) >> 11);
+ pci_card->func_no = (((*int_val) & 0x700) >> 8);
+ } else {
+ pci_card->dev_no = -1;
+ pci_card->func_no = -1;
+ }
+
+ /* We only have one slot on bus A */
+ if ((pci_card->pci_bus == 'A') && (pci_card->dev_no != 1) &&
+ !pci_bridge) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+ if ((pci_card->pci_bus == 'B') && (pci_card->dev_no > 4)) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+
+ type = (char *)get_prop_val(
+ find_prop(pci_card_node, "device_type"));
+ /*
+ * If this is a pci-bridge, then store its dev#
+ * as its children nodes need this to get their slot#.
+ * We set the pci_bridge flag so that we know we are
+ * looking at a pci-bridge node. This flag gets reset
+ * every time we enter this while loop.
+ */
+
+ /*
+ * Check for a PCI-PCI Bridge for PCI and cPCI
+ * IO Boards using the name and type properties.
+ */
+ if ((type != NULL) && (strncmp(name, "pci", 3) == 0) &&
+ (strcmp(type, "pci") == 0)) {
+ pci_bridge_node = pci_card_node;
+ is_pci = TRUE;
+ if (!pci_bridge) {
+ pci_bridge_dev_no = pci_card->dev_no;
+ pci_parent_bridge = pci_bridge_node;
+ pci_bridge = TRUE;
+ }
+ }
+
+ /*
+ * Get slot-names property from slot_names_arr.
+ * If we are the child of a pci_bridge we use the
+ * dev# of the pci_bridge as an index to get
+ * the slot number. We know that we are a child of
+ * a pci-bridge if our parent is the same as the last
+ * pci_bridge node found above.
+ */
+ if (pci_card->dev_no != -1) {
+ /*
+ * We compare this cards parent node with the
+ * pci_bridge_node to see if it's a child.
+ */
+ if (pci_card_node->parent != pci_instance &&
+ pci_bridge) {
+ /* use dev_no of pci_bridge */
+ slot_name =
+ slot_name_arr[pci_bridge_dev_no -1];
+ } else {
+ slot_name =
+ slot_name_arr[pci_card->dev_no-1];
+ }
+ if (slot_name != NULL &&
+ strlen(slot_name) != 0) {
+ /* Slot num is last char in string */
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "%c", slot_name[strlen(slot_name) - 1]);
+ } else {
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "-");
+ }
+
+ } else {
+ (void) snprintf(pci_card->slot_str, MAXSTRLEN,
+ "%c", '-');
+ }
+
+ /*
+ * Check for failed status.
+ */
+ if (node_failed(pci_card_node))
+ strcpy(pci_card->status, "fail");
+ else
+ strcpy(pci_card->status, "ok");
+
+ /* Get the model of this pci_card */
+ value = get_prop_val(find_prop(pci_card_node, "model"));
+ if (value == NULL)
+ pci_card->model[0] = '\0';
+ else {
+ (void) snprintf(pci_card->model, MAXSTRLEN, "%s",
+ (char *)value);
+ /* Skip sgsbbc nodes, they are not cards */
+ if (strcmp(pci_card->model, "SUNW,sgsbbc") == 0) {
+ pci_card_node = pci_card_node->sibling;
+ continue;
+ }
+ }
+ /*
+ * The card may have a "clock-frequency" but we
+ * are not interested in that. Instead we get the
+ * "clock-frequency" of the PCI Bus that the card
+ * resides on. PCI-A can operate at 33Mhz or 66Mhz
+ * depending on what card is plugged into the Bus.
+ * PCI-B always operates at 33Mhz.
+ */
+ int_val = get_prop_val(find_prop(pci_instance,
+ "clock-frequency"));
+ if (int_val != NULL) {
+ pci_card->freq = LNECK_CLK_FREQ_TO_MHZ(*int_val);
+ } else {
+ pci_card->freq = -1;
+ }
+
+ /*
+ * Figure out how we want to display the name
+ */
+ value = get_prop_val(find_prop(pci_card_node,
+ "compatible"));
+ if (value != NULL) {
+ /* use 'name'-'compatible' */
+ (void) snprintf(buf, MAXSTRLEN, "%s-%s", name,
+ (char *)value);
+ } else {
+ /* just use 'name' */
+ (void) snprintf(buf, MAXSTRLEN, "%s", name);
+ }
+ name = buf;
+
+ /*
+ * If this node has children, add the device_type
+ * of the child to the name value of this pci_card->
+ */
+ child_name = (char *)get_node_name(pci_card_node->child);
+ if ((pci_card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(pci_card_node->child,
+ "device_type"));
+ if (value != NULL) {
+ /* add device_type of child to name */
+ (void) snprintf(pci_card->name, MAXSTRLEN,
+ "%s/%s (%s)",
+ name, child_name,
+ (char *)value);
+ } else {
+ /* just add childs name */
+ (void) snprintf(pci_card->name, MAXSTRLEN,
+ "%s/%s", name,
+ child_name);
+ }
+ } else {
+ (void) snprintf(pci_card->name, MAXSTRLEN,
+ "%s", (char *)name);
+ }
+
+ /*
+ * If this is a pci-bridge, then add the word
+ * 'pci-bridge' to its model. If we can't find
+ * a model, then we just describe what the device
+ * is based on some properties.
+ */
+ if (pci_bridge) {
+ if (strlen(pci_card->model) == 0) {
+ if (pci_card_node->parent == pci_bridge_node)
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "device on pci-bridge");
+ else if (pci_card_node->parent
+ == pci_parent_bridge)
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "pci-bridge/pci-bridge");
+ else
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s", "PCI-BRIDGE");
+ }
+ else
+ (void) snprintf(pci_card->model, MAXSTRLEN,
+ "%s/pci-bridge", pci_card->model);
+ }
+ /* insert this pci_card in the list to be displayed later */
+
+ *pci_card_list = insert_io_card(*pci_card_list, pci_card);
+
+ /*
+ * If we are dealing with a pci-bridge, we need to move
+ * down to the children of this bridge if there are any.
+ *
+ * If we are not, we are either dealing with a regular
+ * card (in which case we move onto the sibling of this
+ * card) or we are dealing with a child of a pci-bridge
+ * (in which case we move onto the child's siblings or
+ * if there are no more siblings for this child, we
+ * move onto the parents siblings).
+ */
+ pci_card_node = next_pci_card(pci_card_node, &pci_bridge,
+ is_pci, pci_bridge_node,
+ pci_parent_bridge, pci_instance);
+ } /* end-while */
+}
+
+/*
+ * Helper function for fill_pci_card_list(). Indicates which
+ * card node to go to next.
+ * Parameters:
+ * -----------
+ * Prom_node * curr_card: pointer to the current card node
+ *
+ * int * is_bridge: indicates whether or not the card (is | is on)
+ * a pci bridge
+ *
+ * int is_pcidev: indicates whether or not the current card
+ * is a pci bridge
+ *
+ * Prom_node * curr_bridge: pointer to the current pci bridge. Eg:
+ * curr_card->parent.
+ *
+ * Prom_node * parent_bridge: pointer to the first pci bridge encountered.
+ * we could have nested pci bridges, this would
+ * be the first one.
+ *
+ * Prom_node * pci: pointer to the pci instance that we are attached to.
+ * This would be parent_bridge->parent, or
+ * curr_node->parent, if curr_node is not on a pci bridge.
+ */
+static Prom_node *
+next_pci_card(Prom_node *curr_card, int *is_bridge, int is_pcidev,
+ Prom_node *curr_bridge, Prom_node *parent_bridge,
+ Prom_node *pci)
+{
+ Prom_node * curr_node = curr_card;
+ if (*is_bridge) {
+ /*
+ * is_pcidev is used to prevent us from following the
+ * children of something like a scsi device.
+ */
+ if (curr_node->child != NULL && is_pcidev) {
+ curr_node = curr_node->child;
+ } else {
+ curr_node = curr_node->sibling;
+ if (curr_node == NULL) {
+ curr_node = curr_bridge->sibling;
+ while (curr_node == NULL &&
+ curr_bridge != parent_bridge &&
+ curr_bridge != NULL) {
+ curr_node =
+ curr_bridge->parent->sibling;
+ curr_bridge = curr_bridge->parent;
+ if (curr_node != NULL &&
+ curr_node->parent == pci)
+ break;
+ }
+ if (curr_bridge == NULL ||
+ curr_node == NULL ||
+ curr_node->parent == pci ||
+ curr_bridge == parent_bridge ||
+ curr_node == parent_bridge) {
+ *is_bridge = FALSE;
+ }
+ }
+ }
+
+ } else {
+ curr_node = curr_node->sibling;
+ }
+ return (curr_node);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/lw8/Makefile b/usr/src/lib/libprtdiag_psr/sparc/lw8/Makefile
new file mode 100644
index 0000000000..b11de316ea
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/lw8/Makefile
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/lw8/Makefile
+
+PRTDIAG_DIRS= picl
+
+all := TARGET= all
+lint := TARGET= lint
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all lint clean clobber install _msg : $(PRTDIAG_DIRS)
+
+$(PRTDIAG_DIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/lw8/common/lw8.c b/usr/src/lib/libprtdiag_psr/sparc/lw8/common/lw8.c
new file mode 100644
index 0000000000..fcf98a9f51
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/lw8/common/lw8.c
@@ -0,0 +1,3607 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+#include <errno.h>
+#include <libintl.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/openpromio.h>
+#include <sys/ddi.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <locale.h>
+#include <picl.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "display_sun4u.h"
+#include "picldefs.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+#define EM_INIT_FAIL dgettext(TEXT_DOMAIN,\
+ "picl_initialize failed: %s\n")
+#define EM_GET_ROOT_FAIL dgettext(TEXT_DOMAIN,\
+ "Getting root node failed: %s\n")
+#define EM_PRTDIAG_FAIL dgettext(TEXT_DOMAIN, "Prtdiag failed!\n")
+
+#define SIGN_ON_MSG dgettext(TEXT_DOMAIN,\
+ "System Configuration: Sun Microsystems ")
+#define SYSCLK_FREQ_MSG dgettext(TEXT_DOMAIN,\
+ "System clock frequency: %d MHZ\n")
+#define MEM_SIZE_MSG dgettext(TEXT_DOMAIN, "Memory size: ")
+#define FFB_DOUBLE_BUF dgettext(TEXT_DOMAIN, "FFB, Double Buffered")
+#define FFB_SINGLE_BUF dgettext(TEXT_DOMAIN, "FFB, Single Buffered")
+
+#define DEFAULT_BOARD_NUM 0
+#define DEFAULT_PORTID 0
+#define CLK_FREQ_66MHZ 66
+#define USB -1
+#define HUB -2
+
+/* bus id */
+#define SBUS_TYPE 0
+#define PCI_TYPE 1
+#define UPA_TYPE 2
+
+#define UPA_NAME "upa"
+
+/*
+ * PICL classes
+ */
+#define PICL_CLASS_OPTIONS "options"
+
+/*
+ * Property names
+ */
+
+#define OBP_PROP_REG "reg"
+#define OBP_PROP_CLOCK_FREQ "clock-frequency"
+#define OBP_PROP_BOARD_NUM "board#"
+#define OBP_PROP_REVISION_ID "revision-id"
+#define OBP_PROP_VERSION_NUM "version#"
+#define OBP_PROP_BOARD_TYPE "board_type"
+#define OBP_PROP_ECACHE_SIZE "ecache-size"
+#define OBP_PROP_L2_CACHE_SIZE "l2-cache-size"
+#define OBP_PROP_L3_CACHE_SIZE "l3-cache-size"
+#define OBP_PROP_IMPLEMENTATION "implementation#"
+#define OBP_PROP_MASK "mask#"
+#define OBP_PROP_COMPATIBLE "compatible"
+#define OBP_PROP_STATUS "status"
+#define OBP_PROP_BANNER_NAME "banner-name"
+#define OBP_PROP_MODEL "model"
+#define OBP_PROP_66MHZ_CAPABLE "66mhz-capable"
+#define OBP_PROP_FBC_REG_ID "fbc_reg_id"
+#define OBP_PROP_VERSION "version"
+
+#define PROP_POWERFAIL_TIME "powerfail-time"
+#define PICL_PROP_LOW_WARNING_THRESHOLD "LowWarningThreshold"
+
+#define DEFAULT_LINE_WIDTH 85
+#define HEADING_SYMBOL "="
+
+#define MAX_IWAYS 32
+
+typedef struct bank_list {
+ picl_nodehdl_t nodeh;
+ uint32_t iway_count;
+ uint32_t iway[MAX_IWAYS];
+ struct bank_list *next;
+} bank_list_t;
+
+typedef struct {
+ uint64_t base;
+ uint64_t size;
+ int ifactor;
+ int bank_count;
+} seg_info_t;
+
+static struct io_card *io_card_list = NULL; /* The head of the IO card list */
+static bank_list_t *mem_banks = NULL;
+static int mem_xfersize;
+static int no_xfer_size = 0;
+
+static char *io_device_table[] = {
+ "block",
+ "disk",
+ "cdrom",
+ "floppy",
+ "tape",
+ "network",
+ "display",
+ "serial",
+ "parallel",
+ "scsi",
+ "scsi-2",
+ "scsi-3",
+ "ide",
+ "fcal",
+ "keyboard",
+ "mouse",
+ "dma"
+};
+
+#define NIODEVICE sizeof (io_device_table) / sizeof (io_device_table[0])
+
+static char *bus_table[] = {
+ "ebus",
+ "isa",
+ "pmu"
+};
+
+#define NBUS sizeof (bus_table) / sizeof (bus_table[0])
+
+/*
+ * check if it is an IO deice
+ */
+static int
+is_io_device(char *device_class)
+{
+ int i;
+
+ for (i = 0; i < NIODEVICE; i++) {
+ if (strcmp(device_class, io_device_table[i]) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * check if it is a bus
+ */
+static int
+is_bus(char *device_class)
+{
+ int i;
+
+ for (i = 0; i < NBUS; i++) {
+ if (strcmp(device_class, bus_table[i]) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * search children to get the node by the nodename
+ */
+static int
+picldiag_get_node_by_name(picl_nodehdl_t rooth, char *name,
+ picl_nodehdl_t *nodeh)
+{
+ picl_nodehdl_t childh;
+ int err;
+ char *nodename;
+
+ nodename = alloca(strlen(name) + 1);
+ if (nodename == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
+ nodename, (strlen(name) + 1));
+ if (err != PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ if (strcmp(nodename, name) == 0) {
+ *nodeh = childh;
+ return (PICL_SUCCESS);
+ }
+
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ return (err);
+}
+
+/*
+ * get the value by the property name of the string prop
+ * Caller must free the outbuf
+ */
+static int
+picldiag_get_string_propval(picl_nodehdl_t modh, char *prop_name, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ char *prop_value;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If it is not a string prop, return NULL
+ */
+ if (pinfo.type != PICL_PTYPE_CHARSTRING)
+ return (PICL_FAILURE);
+
+ prop_value = malloc(pinfo.size);
+ if (prop_value == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, prop_value, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(prop_value);
+ return (err);
+ }
+
+ *outbuf = prop_value;
+ return (PICL_SUCCESS);
+}
+
+
+/*
+ * return the value as a signed integer
+ */
+
+static int64_t
+picldiag_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int8_t int8v;
+ int16_t int16v;
+ int32_t int32v;
+ int64_t int64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int or uint prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ switch (pinfo.size) {
+ case sizeof (int8_t):
+ err = picl_get_propval(proph, &int8v, sizeof (int8v));
+ *ret = err;
+ return (int8v);
+ case sizeof (int16_t):
+ err = picl_get_propval(proph, &int16v, sizeof (int16v));
+ *ret = err;
+ return (int16v);
+ case sizeof (int32_t):
+ err = picl_get_propval(proph, &int32v, sizeof (int32v));
+ *ret = err;
+ return (int32v);
+ case sizeof (int64_t):
+ err = picl_get_propval(proph, &int64v, sizeof (int64v));
+ *ret = err;
+ return (int64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+/*
+ * return the value of the uint prop
+ */
+static uint64_t
+picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ uint8_t uint8v;
+ uint16_t uint16v;
+ uint32_t uint32v;
+ uint64_t uint64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int or uint prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ /* uint prop */
+
+ switch (pinfo.size) {
+ case sizeof (uint8_t):
+ err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
+ *ret = err;
+ return (uint8v);
+ case sizeof (uint16_t):
+ err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
+ *ret = err;
+ return (uint16v);
+ case sizeof (uint32_t):
+ err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
+ *ret = err;
+ return (uint32v);
+ case sizeof (uint64_t):
+ err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
+ *ret = err;
+ return (uint64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+/*
+ * return the value of the float prop
+ */
+static float
+picldiag_get_float_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ float floatv;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return ((float)0);
+ }
+
+ /*
+ * If it is not a float prop, return failure
+ */
+ if (pinfo.type != PICL_PTYPE_FLOAT) {
+ *ret = PICL_FAILURE;
+ return ((float)0);
+ }
+
+ *ret = picl_get_propval(proph, &floatv, sizeof (floatv));
+ return (floatv);
+}
+
+/*
+ * get the clock frequency
+ */
+static int
+picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
+{
+#define ROUND_TO_MHZ(x) (((x) + 500000)/ 1000000)
+ int err;
+ uint64_t clk_freq;
+
+ clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ *freq = ROUND_TO_MHZ(clk_freq);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * get the clock frequency from parent
+ */
+static int
+picldiag_get_clock_from_parent(picl_nodehdl_t nodeh, uint32_t *clk)
+{
+ picl_nodehdl_t parenth;
+ int err;
+
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &parenth, sizeof (parenth));
+
+ while (err == PICL_SUCCESS) {
+ err = picldiag_get_clock_freq(parenth, clk);
+ if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
+ &parenth, sizeof (parenth));
+ }
+
+ return (err);
+}
+
+/*
+ * get _fru_parent prop
+ * If not found, then travese superiors (parent nodes) until
+ * a _fru_parent property is found.
+ * If not found, no fru parent
+ */
+static int
+picldiag_get_fru_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruparenth)
+{
+ picl_nodehdl_t fruh;
+ int err;
+
+ /* find fru parent */
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
+ &fruh, sizeof (fruh));
+
+ if (err != PICL_SUCCESS)
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_LOC_PARENT,
+ &fruh, sizeof (fruh));
+
+ while (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
+ &fruh, sizeof (fruh));
+ if (err != PICL_SUCCESS)
+ err = picl_get_propval_by_name(nodeh,
+ PICL_REFPROP_LOC_PARENT, &fruh, sizeof (fruh));
+ }
+
+ if (err == PICL_SUCCESS)
+ *fruparenth = fruh;
+
+ return (err);
+}
+
+/*
+ * get label
+ *
+ * To get the label, use the following algorithm:
+ * Lookup "Label" property in the fru node itself. If no
+ * Label found, then traverse superiors (parent nodes) until
+ * a Label property is found.
+ * if not found, then no label
+ */
+static int
+picldiag_get_label(picl_nodehdl_t nodeh, char **label)
+{
+ int err;
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, label);
+
+ while (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL,
+ label);
+ }
+
+ return (err);
+}
+
+/*
+ * get combined label
+ *
+ * like picldiag_get_label, except concatenates the labels of parent locations
+ * eg SB0/P3 for processor P3 on system board SB0
+ *
+ * if caller specifies non-zero label length, label will be cut to specified
+ * length.
+ * negative length is left justified, non-negative length is right justified
+ */
+static int
+picldiag_get_combined_label(picl_nodehdl_t nodeh, char **label, int lablen)
+{
+ int err;
+ char *ptr;
+ char *ptr1 = NULL;
+ char *ptr2;
+ int len;
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr1);
+ if (err != PICL_PROPNOTFOUND && err != PICL_SUCCESS)
+ return (err);
+
+ for (;;) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err == PICL_PROPNOTFOUND)
+ break;
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr);
+ if (err == PICL_SUCCESS) {
+ if (ptr1 == NULL) {
+ ptr1 = ptr;
+ } else {
+ ptr2 = malloc(strlen(ptr1) + strlen(ptr) + 2);
+ if (ptr2 == NULL)
+ return (PICL_FAILURE);
+ (void) strcpy(ptr2, ptr);
+ (void) strcat(ptr2, "/");
+ (void) strcat(ptr2, ptr1);
+ (void) free(ptr);
+ (void) free(ptr1);
+ ptr1 = ptr2;
+ }
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ }
+
+ if (ptr1 == NULL)
+ return (PICL_PROPNOTFOUND);
+
+ len = strlen(ptr1);
+ /* if no string truncation is desired or required */
+ if ((lablen == 0) || (len <= abs(lablen))) {
+ *label = ptr1;
+ return (PICL_SUCCESS);
+ }
+
+ /* string truncation is required; alloc space for (lablen + \0) */
+ ptr = malloc(abs(lablen) + 1);
+ if (ptr == 0)
+ return (PICL_FAILURE);
+ if (lablen > 0) {
+ /* right justification; label = "+<string>\0" */
+ strcpy(ptr, "+");
+ strncat(ptr, ptr1 + len - lablen + 1, lablen + 1);
+ } else {
+ /* left justification; label = "<string>+\0" */
+ strncpy(ptr, ptr1, abs(lablen) - 1);
+ strcat(ptr, "+");
+ }
+
+ *label = ptr;
+ return (PICL_SUCCESS);
+}
+
+/*
+ * return the first compatible value
+ */
+static int
+picldiag_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ char *pval;
+
+ err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE)
+ return (PICL_FAILURE);
+
+ /* get first string from table */
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print the header in the center
+ */
+static void
+logprintf_header(char *header, size_t line_width)
+{
+ size_t start_pos;
+ size_t i;
+
+ log_printf("\n");
+ start_pos = (line_width - strlen(header) - 2) / 2;
+
+ for (i = 0; i < start_pos; i++)
+ log_printf("%s", HEADING_SYMBOL);
+
+ log_printf(" %s ", header);
+
+ for (i = 0; i < start_pos; i++)
+ log_printf("%s", HEADING_SYMBOL);
+
+ log_printf("\n");
+}
+
+/*
+ * print the size
+ */
+static void
+logprintf_size(uint64_t size)
+{
+#define SIZE_FIELD 11
+
+ uint64_t kbyte = 1024;
+ uint64_t mbyte = 1024 * 1024;
+ uint64_t gbyte = 1024 * 1024 * 1024;
+ uint64_t residue;
+ char buf[SIZE_FIELD];
+
+ if (size >= gbyte) {
+ residue = size % gbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dGB",
+ (int)(size / gbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fGB",
+ (float)size / gbyte);
+ } else if (size >= mbyte) {
+ residue = size % mbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dMB",
+ (int)(size / mbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fMB",
+ (float)size / mbyte);
+ } else {
+ residue = size % kbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dKB",
+ (int)(size / kbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fKB",
+ (float)size / kbyte);
+ }
+
+ log_printf("%-10s ", buf);
+}
+
+/*
+ * display platform banner
+ */
+static int
+display_platform_banner(picl_nodehdl_t plafh)
+{
+ char *platform;
+ char *banner_name;
+ int err;
+
+ /*
+ * get PICL_PROP_MACHINE and PICL_PROP_BANNER_NAME
+ */
+ log_printf(SIGN_ON_MSG);
+ err = picldiag_get_string_propval(plafh, PICL_PROP_MACHINE,
+ &platform);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", platform);
+ free(platform);
+
+ err = picldiag_get_string_propval(plafh, OBP_PROP_BANNER_NAME,
+ &banner_name);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", banner_name);
+ free(banner_name);
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+/*
+ * display the clock frequency
+ */
+static int
+display_system_clock(picl_nodehdl_t plafh)
+{
+ uint32_t system_clk;
+ int err;
+
+ err = picldiag_get_clock_freq(plafh, &system_clk);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf(SYSCLK_FREQ_MSG, system_clk);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback function to display the memory size
+ */
+/*ARGSUSED*/
+static int
+memory_callback(picl_nodehdl_t memh, void *args)
+{
+ uint64_t mem_size;
+ int err;
+
+ log_printf(MEM_SIZE_MSG);
+ mem_size = picldiag_get_uint_propval(memh, PICL_PROP_SIZE, &err);
+ if (err == PICL_SUCCESS)
+ logprintf_size(mem_size);
+ log_printf("\n");
+ no_xfer_size = 0;
+ mem_xfersize = picldiag_get_uint_propval(memh, PICL_PROP_TRANSFER_SIZE,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ no_xfer_size = 1;
+ return (PICL_WALK_TERMINATE);
+}
+
+/*
+ * callback function to print cpu information
+ */
+/*ARGSUSED*/
+static int
+cpu_callback(picl_nodehdl_t nodeh, void *args)
+{
+ int err;
+ int id0, id1;
+ uint64_t uintval;
+ uint64_t decoded_mask;
+ uint32_t freq;
+ char *impl_name;
+ char *status;
+ picl_prophdl_t parenth;
+ picl_prophdl_t peerh;
+ char *label;
+ int is_cmp = 0;
+ int is_cheetah = 0;
+
+ /*
+ * first check the implementation. If it's a CMP
+ * we need to combine info from both cores.
+ */
+
+ impl_name = NULL;
+ uintval = picldiag_get_uint_propval(nodeh,
+ OBP_PROP_IMPLEMENTATION, &err);
+ if (err == PICL_SUCCESS) {
+ if (CPU_IMPL_IS_CMP(uintval)) {
+ is_cmp = 1;
+ err = picldiag_get_first_compatible_value(nodeh,
+ &impl_name);
+ if (err != PICL_SUCCESS)
+ impl_name = NULL;
+ } else if (IS_CHEETAH(uintval) || IS_CHEETAH_PLUS(uintval)) {
+ is_cheetah = 1;
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_NAME,
+ &impl_name);
+ if (err != PICL_SUCCESS)
+ impl_name = NULL;
+ }
+ } else {
+ err = picldiag_get_string_propval(nodeh,
+ PICL_PROP_NAME, &impl_name);
+ if (err != PICL_SUCCESS)
+ impl_name = NULL;
+ }
+
+ /*
+ * In the CMP case, combine info from both cores. If we
+ * are being called with the first core handle, we display
+ * info on the sibling core handle too. If we are being
+ * called with the second core hanlde as an argument, simply
+ * return.
+ */
+
+ if (is_cmp) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &peerh, sizeof (picl_nodehdl_t));
+ if (err != PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ id1 = picldiag_get_uint_propval(peerh, PICL_PROP_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ /*
+ * If no ID is found, return
+ */
+ id0 = picldiag_get_uint_propval(nodeh, PICL_PROP_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ if (is_cmp) {
+ log_printf("%3d,%3d ", id0, id1);
+ } else {
+ log_printf("%7d ", id0);
+ }
+
+ /*
+ * If no freq is found, return
+ */
+ err = picldiag_get_clock_freq(nodeh, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%4d MHz ", freq);
+
+ /* Ecache size */
+
+ if (is_cmp) {
+ uintval = picldiag_get_uint_propval(nodeh,
+ OBP_PROP_L3_CACHE_SIZE, &err);
+ if (err == PICL_SUCCESS) {
+ /*
+ * Panther L3 is logically shared, so the total E$
+ * size is equal to the core size.
+ */
+ logprintf_size(uintval);
+ } else {
+ uintval = picldiag_get_uint_propval(nodeh,
+ OBP_PROP_L2_CACHE_SIZE, &err);
+ if (err == PICL_SUCCESS) {
+ /*
+ * Jaguar has a split E$, so the total size
+ * is the sum of both cores.
+ */
+ logprintf_size(uintval * 2);
+ } else
+ log_printf(" - ");
+ }
+ } else {
+ uintval = picldiag_get_uint_propval(nodeh,
+ OBP_PROP_ECACHE_SIZE, &err);
+ if (err == PICL_SUCCESS)
+ logprintf_size(uintval);
+ else
+ log_printf(" - ");
+ }
+
+ /* Implementation */
+ if (impl_name != NULL)
+ log_printf(" %-20s ", impl_name);
+ else
+ log_printf(" <unknown> ");
+
+ /* CPU Mask */
+ uintval = picldiag_get_uint_propval(nodeh, OBP_PROP_MASK, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS) {
+ if (is_cheetah) {
+ decoded_mask = REMAP_CHEETAH_MASK(uintval);
+ } else {
+ decoded_mask = uintval;
+ }
+ log_printf("%2lld.%-2lld ", (decoded_mask >> 4) & 0xf,
+ decoded_mask & 0xf);
+ } else
+ return (err);
+
+ /*
+ * Status - if the node has a status property then display that
+ * otherwise display the State property
+ */
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err !=
+ PICL_PROPVALUNAVAILABLE && err != PICL_ENDOFLIST) {
+ return (err);
+ } else {
+ err = picldiag_get_string_propval(nodeh,
+ PICL_PROP_STATE, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err !=
+ PICL_PROPVALUNAVAILABLE && err !=
+ PICL_ENDOFLIST) {
+ return (err);
+ } else {
+ log_printf("unknown ");
+ }
+ }
+
+ /*
+ * Location: use label of fru parent
+ */
+ err = picldiag_get_fru_parent(nodeh, &parenth);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf(" - ");
+ } else if (err == PICL_SUCCESS) {
+ err = picldiag_get_combined_label(parenth, &label, 12);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS) {
+ log_printf("%s", label);
+ free(label);
+ } else
+ return (err);
+ } else
+ return (err);
+
+ log_printf("\n");
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * display cpu information
+ */
+static int
+display_cpu_info(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision on all the boards.
+ */
+ logprintf_header(dgettext(TEXT_DOMAIN, "CPUs"), DEFAULT_LINE_WIDTH);
+ log_printf(" E$ CPU "
+ "CPU\n");
+ log_printf("CPU Freq Size Implementation "
+ "Mask Status Location\n");
+ log_printf("------- -------- ---------- ------------------- "
+ "----- ------ --------\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
+ cpu_callback);
+ return (err);
+}
+
+/*
+ * Inserts an io_card structure into the list.
+ */
+static void
+add_io_card(uint32_t board, uint32_t bus_id, uint32_t slot, char *label,
+ uint32_t freq, char *name, char *model, char *status, char *devfs_path)
+{
+ struct io_card card;
+
+ card.display = 1;
+ card.board = board;
+ switch (bus_id) {
+ case SBUS_TYPE:
+ strlcpy(card.bus_type, SBUS_NAME, MAXSTRLEN);
+ break;
+ case PCI_TYPE:
+ strlcpy(card.bus_type, PCI_NAME, MAXSTRLEN);
+ break;
+ case UPA_TYPE:
+ strlcpy(card.bus_type, UPA_NAME, MAXSTRLEN);
+ break;
+ default: /* won't reach here */
+ strlcpy(card.bus_type, "", MAXSTRLEN);
+ break;
+ }
+ if (label == NULL)
+ card.slot = slot;
+ else {
+ card.slot = PCI_SLOT_IS_STRING;
+ (void) strlcpy(card.slot_str, label, MAXSTRLEN);
+ }
+ card.freq = freq;
+ card.status[0] = '\0';
+ card.name[0] = '\0';
+ card.model[0] = '\0';
+ card.notes[0] = '\0';
+ if (status != NULL)
+ strlcpy(card.status, status, MAXSTRLEN);
+ if (name != NULL)
+ strlcpy(card.name, name, MAXSTRLEN);
+ if (model != NULL)
+ strlcpy(card.model, model, MAXSTRLEN);
+ if (status != NULL)
+ strlcpy(card.status, status, MAXSTRLEN);
+ if (devfs_path != NULL)
+ strlcpy(card.notes, devfs_path, MAXSTRLEN);
+
+ io_card_list = insert_io_card(io_card_list, &card);
+}
+
+static void
+append_to_bank_list(bank_list_t *newptr)
+{
+ bank_list_t *ptr;
+
+ if (mem_banks == NULL) {
+ mem_banks = newptr;
+ return;
+ }
+ ptr = mem_banks;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = newptr;
+}
+
+static void
+free_bank_list(void)
+{
+ bank_list_t *ptr;
+ bank_list_t *tmp;
+
+ for (ptr = mem_banks; ptr != NULL; ptr = tmp) {
+ tmp = ptr->next;
+ free(ptr);
+ }
+ mem_banks = NULL;
+}
+
+
+/*
+ * print label for memory module
+ */
+static int
+logprintf_memory_module_label(picl_nodehdl_t moduleh)
+{
+ picl_nodehdl_t fruparenth;
+ int err;
+ char *label;
+
+ err = picldiag_get_fru_parent(moduleh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-");
+ return (PICL_SUCCESS);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruparenth, &label, 30);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("-");
+ else if (err == PICL_SUCCESS) {
+ log_printf("%-15s", label);
+ free(label);
+ } else
+ return (err);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print the bank id and add the bank handle in the bank list
+ * return the head of the bank list
+ */
+static int
+membank_callback(picl_nodehdl_t bankh, void *args)
+{
+ int err;
+ int64_t id;
+ uint64_t match;
+ uint64_t mask;
+ int i;
+ bank_list_t *newptr;
+ seg_info_t *segp = args;
+
+ /*
+ * print the bank id in the segment table contains column
+ */
+ id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
+ if (segp->bank_count > 0)
+ log_printf(",");
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("-");
+ else if (err == PICL_SUCCESS)
+ log_printf("%-lld", id);
+ else
+ return (err);
+ segp->bank_count++;
+
+ /*
+ * Save the bank information for later (print_bank_table)
+ */
+ newptr = malloc(sizeof (*newptr));
+ if (newptr == NULL)
+ return (PICL_FAILURE);
+
+ newptr->nodeh = bankh;
+ newptr->iway_count = 0;
+ newptr->next = NULL;
+ append_to_bank_list(newptr);
+
+ /*
+ * Compute the way numbers for the bank
+ */
+ if (no_xfer_size)
+ return (PICL_WALK_CONTINUE);
+
+ match = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMATCH, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ mask = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMASK, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ i = 0;
+ while ((i < segp->ifactor) && (newptr->iway_count < MAX_IWAYS)) {
+ if (((segp->base + i * mem_xfersize) & mask) == match)
+ newptr->iway[newptr->iway_count++] = i;
+ ++i;
+ }
+ return (PICL_WALK_CONTINUE);
+}
+
+
+/*
+ * find the memory bank and add the bank handle in the bank list
+ * return the head of the bank list
+ */
+static int
+logprintf_bankinfo(picl_nodehdl_t segh, seg_info_t *segp)
+{
+ int err;
+
+ log_printf("BankIDs ");
+ /*
+ * find memory-bank
+ */
+ segp->bank_count = 0;
+ err = picl_walk_tree_by_class(segh, PICL_CLASS_MEMORY_BANK, segp,
+ membank_callback);
+ log_printf("\n");
+ return (err);
+}
+
+/*
+ * print the label of memory module or the memory module bank ids
+ */
+static int
+logprintf_seg_contains_col(picl_nodehdl_t nodeh, seg_info_t *segp)
+{
+ picl_nodehdl_t moduleh;
+ int err;
+
+ /*
+ * find memory-module if referenced directly from the memory-segment
+ * (ie no memory banks)
+ */
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_MEMORY_MODULE,
+ &moduleh, sizeof (moduleh));
+ if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
+ return (err);
+ if (err == PICL_SUCCESS) {
+ err = logprintf_memory_module_label(moduleh);
+ log_printf("\n");
+ return (err);
+ }
+
+ /*
+ * memory-module not referenced directly from the memory segment
+ * so list memory banks instead
+ */
+ err = logprintf_bankinfo(nodeh, segp);
+ return (err);
+}
+
+/*
+ * find all memory modules under the given memory module group
+ * and print its label
+ */
+static int
+logprintf_memory_module_group_info(picl_nodehdl_t memgrph, uint64_t mcid)
+{
+ int err;
+ int64_t id;
+ picl_nodehdl_t moduleh;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ picl_nodehdl_t fruparenth;
+ char *status;
+
+ id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ id = -1;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(memgrph, PICL_PROP_CHILD, &moduleh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ /* controller id */
+ log_printf("%-8lld ", mcid);
+
+ /* group id */
+ if (id == -1) {
+ log_printf("- ");
+ } else {
+ log_printf("%-8lld ", id);
+ }
+
+ err = picl_get_propval_by_name(moduleh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE) == 0) {
+ err = logprintf_memory_module_label(moduleh);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ err = picldiag_get_fru_parent(moduleh, &fruparenth);
+ if (err == PICL_SUCCESS) {
+ err = picldiag_get_string_propval(fruparenth,
+ PICL_PROP_OPERATIONAL_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picl_get_propval_by_name(moduleh, PICL_PROP_PEER,
+ &moduleh, sizeof (picl_nodehdl_t));
+
+ log_printf("\n");
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * search children to find memory module group under memory-controller
+ */
+static int
+find_memory_module_group(picl_nodehdl_t mch, int *print_header)
+{
+ picl_nodehdl_t memgrph;
+ uint64_t mcid;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+
+ mcid = picldiag_get_uint_propval(mch, OBP_PROP_PORTID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ mcid = DEFAULT_PORTID;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(mch, PICL_PROP_CHILD,
+ &memgrph, sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(memgrph,
+ PICL_PROP_CLASSNAME, piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE_GROUP) == 0) {
+ if (*print_header == 1) {
+ log_printf(
+ dgettext(TEXT_DOMAIN,
+ "\nMemory Module Groups:\n"));
+ log_printf("--------------------------");
+ log_printf("------------------------\n");
+ log_printf("ControllerID GroupID Labels");
+ log_printf(" Status\n");
+ log_printf("--------------------------");
+ log_printf("------------------------\n");
+ *print_header = 0;
+ }
+ err = logprintf_memory_module_group_info(memgrph, mcid);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(memgrph, PICL_PROP_PEER,
+ &memgrph, sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * print memory module group table per memory-controller
+ */
+static int
+print_memory_module_group_table(picl_nodehdl_t plafh)
+{
+ picl_nodehdl_t mch;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ int print_header;
+
+ print_header = 1;
+
+ /*
+ * find memory-controller
+ */
+ err = picl_get_propval_by_name(plafh, PICL_PROP_CHILD, &mch,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(mch, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_CONTROLLER) != 0) {
+ err = print_memory_module_group_table(mch);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
+ &mch, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ err = find_memory_module_group(mch, &print_header);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
+ &mch, sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+
+ return (err);
+}
+
+/*
+ * print bank table
+ */
+static int
+print_bank_table(void)
+{
+ bank_list_t *ptr;
+ picl_nodehdl_t bankh;
+ picl_nodehdl_t memgrph;
+ picl_nodehdl_t mch;
+ int err;
+ int32_t i;
+ uint64_t size;
+ int id;
+
+ log_printf(dgettext(TEXT_DOMAIN, "\nBank Table:\n"));
+ log_printf("---------------------------------------");
+ log_printf("--------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, " Physical Location\n"));
+ log_printf(dgettext(TEXT_DOMAIN, "ID ControllerID GroupID "));
+ log_printf(dgettext(TEXT_DOMAIN, "Size Interleave Way\n"));
+ log_printf("---------------------------------------");
+ log_printf("--------------------\n");
+
+ for (ptr = mem_banks; ptr != NULL; ptr = ptr->next) {
+ bankh = ptr->nodeh;
+ id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
+ if (err != PICL_SUCCESS)
+ log_printf("%-8s ", "-");
+ else
+ log_printf("%-8d ", id);
+
+ /* find memory-module-group */
+ err = picl_get_propval_by_name(bankh,
+ PICL_REFPROP_MEMORY_MODULE_GROUP, &memgrph,
+ sizeof (memgrph));
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("%-8s ", "-");
+ log_printf("%-8s ", "-");
+ } else if (err != PICL_SUCCESS)
+ return (err);
+ else {
+ /*
+ * get controller id
+ */
+ err = picl_get_propval_by_name(memgrph,
+ PICL_PROP_PARENT, &mch, sizeof (picl_nodehdl_t));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ id = picldiag_get_uint_propval(mch, OBP_PROP_PORTID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ id = DEFAULT_PORTID; /* use default */
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-8d ", id);
+
+ /* get group id */
+ id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("- ");
+ else if (err == PICL_SUCCESS)
+ log_printf("%-8d ", id);
+ else
+ return (err);
+ }
+
+ size = picldiag_get_uint_propval(bankh, PICL_PROP_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("- ");
+ else if (err == PICL_SUCCESS)
+ logprintf_size(size);
+ else
+ return (err);
+
+ log_printf(" ");
+ for (i = 0; i < ptr->iway_count; i++) {
+ if (i != 0)
+ log_printf(",");
+ log_printf("%d", ptr->iway[i]);
+ }
+
+ log_printf("\n");
+ }
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback function to print segment, add the bank in the list and
+ * return the bank list
+ */
+/* ARGSUSED */
+static int
+memseg_callback(picl_nodehdl_t segh, void *args)
+{
+ seg_info_t seginfo;
+ int err;
+
+ /* get base address */
+ seginfo.base = picldiag_get_uint_propval(segh, PICL_PROP_BASEADDRESS,
+ &err);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ log_printf("0x%-16llx ", seginfo.base);
+ else
+ return (err);
+
+ /* get size */
+ seginfo.size = picldiag_get_uint_propval(segh, PICL_PROP_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ logprintf_size(seginfo.size);
+ else
+ return (err);
+
+ /* get interleave factor */
+ seginfo.ifactor = picldiag_get_uint_propval(segh,
+ PICL_PROP_INTERLEAVE_FACTOR, &err);
+
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf(" -\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ log_printf(" %-2d ", seginfo.ifactor);
+ else
+ return (err);
+
+ seginfo.bank_count = 0;
+ err = logprintf_seg_contains_col(segh, &seginfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * search children to find memory-segment and set up the bank list
+ */
+static int
+find_segments(picl_nodehdl_t plafh)
+{
+ int err;
+
+ log_printf(dgettext(TEXT_DOMAIN, "Segment Table:\n"));
+ log_printf("------------------------------");
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Base Address Size "));
+ log_printf(dgettext(TEXT_DOMAIN, "Interleave Factor Contains\n"));
+ log_printf("------------------------------");
+ log_printf("-----------------------------------------\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
+ NULL, memseg_callback);
+ return (err);
+}
+
+/*
+ * display memory configuration
+ */
+static int
+display_memory_config(picl_nodehdl_t plafh)
+{
+ int err;
+
+ logprintf_header(dgettext(TEXT_DOMAIN, "Memory Configuration"),
+ DEFAULT_LINE_WIDTH);
+
+ mem_banks = NULL;
+ err = find_segments(plafh);
+
+ if ((err == PICL_SUCCESS) && (mem_banks != NULL))
+ print_bank_table();
+
+ free_bank_list();
+
+ return (print_memory_module_group_table(plafh));
+}
+
+/*
+ * print the hub device
+ */
+static int
+logprintf_hub_devices(picl_nodehdl_t hubh)
+{
+ char *name;
+ int portnum;
+ int err;
+
+ err = picldiag_get_string_propval(hubh, PICL_PROP_NAME, &name);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-12.12s ", name);
+ free(name);
+
+ err = picl_get_propval_by_name(hubh, OBP_PROP_REG,
+ &portnum, sizeof (portnum));
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("-\n");
+ else if (err == PICL_SUCCESS)
+ log_printf("%3d\n", portnum);
+ else
+ return (err);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback functions to display hub devices
+ */
+/* ARGSUSED */
+static int
+print_usb_devices(picl_nodehdl_t hubh, void *arg)
+{
+ picl_nodehdl_t chdh;
+ char *rootname;
+ int type = *(int *)arg;
+ int hubnum;
+ int err;
+
+ err = picl_get_propval_by_name(hubh, PICL_PROP_CHILD, &chdh,
+ sizeof (picl_nodehdl_t));
+
+ /* print header */
+ if (err == PICL_SUCCESS) {
+ err = picldiag_get_string_propval(hubh, PICL_PROP_NAME,
+ &rootname);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (type == USB) {
+ log_printf("\n===============================");
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s Devices "), rootname);
+ } else {
+ /* Get its hub number */
+ err = picl_get_propval_by_name(hubh,
+ OBP_PROP_REG, &hubnum, sizeof (hubnum));
+ if ((err != PICL_SUCCESS) &&
+ (err != PICL_PROPNOTFOUND)) {
+ free(rootname);
+ return (err);
+ }
+
+ log_printf("\n===============================");
+ if (err == PICL_SUCCESS)
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s#%d Devices "),
+ rootname, hubnum);
+ else
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s Devices "), rootname);
+ }
+
+ log_printf("===============================\n\n");
+ log_printf("Name Port#\n");
+ log_printf("------------ -----\n");
+ free(rootname);
+
+ do {
+ logprintf_hub_devices(chdh);
+
+ err = picl_get_propval_by_name(chdh, PICL_PROP_PEER,
+ &chdh, sizeof (picl_nodehdl_t));
+ } while (err == PICL_SUCCESS);
+ }
+
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback functions to display usb devices
+ */
+/* ARGSUSED */
+static int
+usb_callback(picl_nodehdl_t usbh, void *args)
+{
+ int err;
+ int type;
+
+ type = USB;
+ err = print_usb_devices(usbh, &type);
+ if (err != PICL_WALK_CONTINUE)
+ return (err);
+ type = HUB;
+ err = picl_walk_tree_by_class(usbh, NULL, &type, print_usb_devices);
+ if (err == PICL_SUCCESS)
+ err = PICL_WALK_CONTINUE;
+ return (err);
+}
+
+
+/*
+ * find usb devices and print its information
+ */
+static int
+display_usb_devices(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * get the usb node
+ */
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_USB, NULL,
+ usb_callback);
+ return (err);
+}
+
+
+
+/*
+ * If nodeh is the io device, add it into the io list and return
+ * If it is not an io device and it has the subtree, traverse the subtree
+ * and add all leaf io devices
+ */
+static int
+add_io_leaves(picl_nodehdl_t nodeh, char *parentname, uint32_t board,
+ uint32_t bus_id, uint64_t slot, uint32_t freq, char *model, char *status)
+{
+ picl_nodehdl_t childh;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int err;
+ char *nameval;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char nodename[MAXSTRLEN];
+ char name[MAXSTRLEN];
+ char *devfs_path;
+ char *compatible;
+ picl_nodehdl_t fruparenth;
+ char *label;
+ char binding_name[MAXSTRLEN];
+
+ err = picl_get_propinfo_by_name(nodeh, PICL_PROP_NAME, &pinfo,
+ &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ nameval = alloca(pinfo.size);
+ if (nameval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, nameval, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ (void) strlcpy(nodename, nameval, MAXSTRLEN);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /* if binding_name is found, name will be <nodename>-<binding_name> */
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+ binding_name, sizeof (binding_name));
+ if (err == PICL_PROPNOTFOUND) {
+ /*
+ * if compatible prop is found, name will be
+ * <nodename>-<compatible>
+ */
+ err = picldiag_get_first_compatible_value(nodeh, &compatible);
+ if (err == PICL_SUCCESS) {
+ strlcat(nodename, "-", MAXSTRLEN);
+ strlcat(nodename, compatible, MAXSTRLEN);
+ free(compatible);
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else if (strcmp(nodename, binding_name) != 0) {
+ if (strcmp(nodename, piclclass) == 0) {
+ /*
+ * nodename same as binding name -
+ * no need to display twice
+ */
+ strlcpy(nodename, binding_name, MAXSTRLEN);
+ } else {
+ strlcat(nodename, "-", MAXSTRLEN);
+ strlcat(nodename, binding_name, MAXSTRLEN);
+ }
+ }
+
+ /*
+ * If it is an immediate child under pci/sbus/upa and not
+ * a bus node, add it to the io list.
+ * If it is a child under sub-bus and it is in an io
+ * device, add it to the io list.
+ */
+ if (((parentname == NULL) && (!is_bus(piclclass))) ||
+ ((parentname != NULL) && (is_io_device(piclclass)))) {
+ if (parentname == NULL)
+ (void) snprintf(name, MAXSTRLEN, "%s", nodename);
+ else
+ (void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
+ nodename);
+
+ /*
+ * append the class if its class is not a generic
+ * obp-device class
+ */
+ if (strcmp(piclclass, PICL_CLASS_OBP_DEVICE))
+ (void) snprintf(name, MAXSTRLEN, "%s (%s)", name,
+ piclclass);
+
+ err = picldiag_get_fru_parent(nodeh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ label = NULL;
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ err = picldiag_get_combined_label(fruparenth, &label,
+ 15);
+ if (err == PICL_PROPNOTFOUND)
+ label = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+ }
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH,
+ &devfs_path);
+ if (err == PICL_PROPNOTFOUND)
+ devfs_path = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ add_io_card(board, bus_id, slot, label, freq, name,
+ model, status, devfs_path);
+ if (label != NULL)
+ free(label);
+ if (devfs_path != NULL)
+ free(devfs_path);
+ return (PICL_SUCCESS);
+ }
+
+ /*
+ * If there is any child, Go through each child.
+ */
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
+ &childh, sizeof (picl_nodehdl_t));
+
+ /* there is a child */
+ while (err == PICL_SUCCESS) {
+ if (parentname == NULL)
+ (void) strlcpy(name, nodename, MAXSTRLEN);
+ else
+ (void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
+ nodename);
+
+ err = add_io_leaves(childh, name, board, bus_id, slot, freq,
+ model, status);
+ if (err != PICL_SUCCESS)
+ return (err);
+ /*
+ * get next child
+ */
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * callback function to add all io devices under sbus in io list
+ */
+/*ARGSUSED*/
+static int
+sbus_callback(picl_nodehdl_t sbush, void *args)
+{
+ picl_nodehdl_t nodeh;
+ int err;
+ uint32_t boardnum;
+ uint32_t bus_id;
+ uint32_t slot;
+ uint32_t freq;
+ char *model;
+ char *status;
+
+ /* Fill in common infomation */
+ bus_id = SBUS_TYPE;
+
+ err = picldiag_get_clock_freq(sbush, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ /*
+ * If no board# is found, set boardnum to 0
+ */
+ boardnum = picldiag_get_uint_propval(sbush, OBP_PROP_BOARD_NUM, &err);
+ if (err == PICL_PROPNOTFOUND)
+ boardnum = DEFAULT_BOARD_NUM;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(sbush, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ slot = picldiag_get_uint_propval(nodeh,
+ PICL_PROP_SLOT, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_STATUS,
+ &status);
+ if (err == PICL_PROPNOTFOUND) {
+ status = malloc(5);
+ strncpy(status, "okay", 5);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = add_io_leaves(nodeh, NULL, boardnum, bus_id, slot, freq,
+ model, status);
+ if (model != NULL)
+ free(model);
+ if (status != NULL)
+ free(status);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * add all io devices under pci in io list
+ */
+/* ARGSUSED */
+static int
+pci_callback(picl_nodehdl_t pcih, void *args)
+{
+ picl_nodehdl_t nodeh;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ uint32_t boardnum;
+ uint32_t bus_id;
+ uint32_t slot;
+ uint32_t freq;
+ char *model;
+ char *status;
+
+ /* Fill in common infomation */
+ bus_id = PCI_TYPE;
+
+ /*
+ * Check if it has the freq, if not,
+ * If not, use its parent's freq
+ * if its parent's freq is not found, return
+ */
+ err = picldiag_get_clock_freq(pcih, &freq);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picldiag_get_clock_from_parent(pcih, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If no board# is found, set boardnum to 0
+ */
+ boardnum = picldiag_get_uint_propval(pcih, OBP_PROP_BOARD_NUM, &err);
+ if (err == PICL_PROPNOTFOUND)
+ boardnum = DEFAULT_BOARD_NUM;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Walk through the children */
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Skip PCI bridge and USB devices because they will be
+ * processed later
+ */
+ if ((strcmp(piclclass, PICL_CLASS_PCI) == 0) ||
+ (strcmp(piclclass, PICL_CLASS_USB) == 0)) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ /* Get the device id for pci card */
+ slot = picldiag_get_uint_propval(nodeh,
+ PICL_PROP_DEVICE_ID, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Get the model of this card */
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_STATUS,
+ &status);
+ if (err == PICL_PROPNOTFOUND) {
+ status = malloc(5);
+ strncpy(status, "okay", 5);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = add_io_leaves(nodeh, NULL, boardnum, bus_id, slot,
+ freq, model, status);
+
+ if (model != NULL)
+ free(model);
+
+ if (status != NULL)
+ free(status);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+
+ return (err);
+}
+
+/*
+ * add io devices in io list
+ * Its slot number is drived from upa-portid
+ */
+static int
+add_io_devices(picl_nodehdl_t nodeh)
+{
+ int err;
+ uint64_t board_type;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char name[MAXSTRLEN];
+ char *devfs_path;
+ char *nameval;
+ uint32_t boardnum;
+ uint32_t bus_id;
+ uint32_t slot;
+ uint32_t freq;
+ char *model;
+ char *status;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_nodehdl_t fruparenth;
+ char *label;
+
+
+ bus_id = UPA_TYPE;
+
+ /*
+ * If clock frequency can't be found from its parent, don't add
+ */
+ err = picldiag_get_clock_from_parent(nodeh, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If no board# is found, set boardnum to 0
+ */
+ boardnum = picldiag_get_uint_propval(nodeh, OBP_PROP_BOARD_NUM, &err);
+ if (err == PICL_PROPNOTFOUND)
+ boardnum = DEFAULT_BOARD_NUM;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * get upa portid as slot number
+ * If upa portid is not found, don't add the card.
+ */
+ slot = picldiag_get_uint_propval(nodeh, OBP_PROP_UPA_PORTID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Get the model of this card */
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL, &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * check if it is a ffb device
+ * If it's a ffb device, append its board type to name
+ * otherwise, use its nodename
+ */
+ err = picl_get_prop_by_name(nodeh, PICL_PROP_FFB_BOARD_REV, &proph);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propinfo_by_name(nodeh, PICL_PROP_NAME,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ nameval = alloca(pinfo.size);
+ if (nameval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, nameval, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ (void) strlcpy(name, nameval, MAXSTRLEN);
+ } else if (err == PICL_SUCCESS) {
+ /* Find out if it's single or double buffered */
+ board_type = picldiag_get_uint_propval(nodeh,
+ OBP_PROP_BOARD_TYPE, &err);
+ if (err == PICL_PROPNOTFOUND)
+ (void) strlcpy(name, FFB_NAME, sizeof (name));
+ if (err == PICL_SUCCESS) {
+ if (board_type & FFB_B_BUFF)
+ (void) strlcpy(name, FFB_DOUBLE_BUF,
+ sizeof (name));
+ else
+ (void) strlcpy(name, FFB_SINGLE_BUF,
+ sizeof (name));
+ } else
+ return (err);
+ } else
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ (void) snprintf(name, sizeof (name), "%s (%s)", name, piclclass);
+
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND) {
+ status = malloc(5);
+ strncpy(status, "okay", 5);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_fru_parent(nodeh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ label = NULL;
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ err = picldiag_get_combined_label(fruparenth, &label, 15);
+ if (err == PICL_PROPNOTFOUND)
+ label = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+ }
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH,
+ &devfs_path);
+ if (err == PICL_PROPNOTFOUND)
+ devfs_path = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ add_io_card(boardnum, bus_id, slot, label, freq, name, model, status,
+ devfs_path);
+ if (label != NULL)
+ free(label);
+ if (model != NULL)
+ free(model);
+ if (status != NULL)
+ free(status);
+ if (devfs_path != NULL)
+ free(devfs_path);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * loop through all children and add io devices in io list
+ */
+static int
+process_io_leaves(picl_nodehdl_t rooth)
+{
+ picl_nodehdl_t nodeh;
+ char classval[PICL_CLASSNAMELEN_MAX];
+ int err;
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ classval, sizeof (classval));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (is_io_device(classval))
+ err = add_io_devices(nodeh);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+
+ return (err);
+}
+
+/*
+ * callback function to add all io devices under upa in io list
+ */
+/*ARGSUSED*/
+static int
+upa_callback(picl_nodehdl_t upah, void *args)
+{
+ int err;
+
+ err = process_io_leaves(upah);
+
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * display ffb hardware configuration
+ */
+/* ARGSUSED */
+static int
+ffbconfig_callback(picl_nodehdl_t ffbh, void *arg)
+{
+ int err;
+ uint64_t board_rev;
+ uint64_t fbc_ver;
+ char *dac_ver;
+ char *fbram_ver;
+
+ /*
+ * If it has PICL_PROP_FFB_BOARD_REV, it is a ffb device
+ * Otherwise, return.
+ */
+ board_rev = picldiag_get_uint_propval(ffbh, PICL_PROP_FFB_BOARD_REV,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("FFB Hardware Configuration:\n");
+ log_printf("-----------------------------------\n");
+ log_printf("Board rev: %lld\n", board_rev);
+
+ fbc_ver = picldiag_get_uint_propval(ffbh, OBP_PROP_FBC_REG_ID,
+ &err);
+ if (err == PICL_SUCCESS)
+ log_printf("FBC version: 0x%llx\n", fbc_ver);
+ else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picldiag_get_string_propval(ffbh, PICL_PROP_FFB_DAC_VER,
+ &dac_ver);
+ if (err == PICL_SUCCESS) {
+ log_printf("DAC: %s\n", dac_ver);
+ free(dac_ver);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picldiag_get_string_propval(ffbh, PICL_PROP_FFB_FBRAM_VER,
+ &fbram_ver);
+ if (err == PICL_SUCCESS) {
+ log_printf("3DRAM: %s\n", fbram_ver);
+ free(fbram_ver);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ log_printf("\n");
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * find all io devices and add them in the io list
+ */
+static int
+gather_io_cards(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * look for io devices under the immediate children of platform
+ */
+ err = process_io_leaves(plafh);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_SBUS,
+ PICL_CLASS_SBUS, sbus_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
+ PICL_CLASS_PCI, pci_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_UPA,
+ PICL_CLASS_UPA, upa_callback);
+ return (err);
+}
+
+static void
+picldiag_display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == 0) {
+ log_printf("Bus Freq Slot + Name +\n", 0);
+ log_printf("Type MHz Status "
+ "Path "
+ "Model", 0);
+ log_printf("\n", 0);
+ log_printf("---- ---- ---------- "
+ "---------------------------- "
+ "--------------------", 0);
+ log_printf("\n", 0);
+ banner = 1;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf("%-4s ", p->bus_type, 0);
+ log_printf("%3d ", p->freq, 0);
+ /*
+ * We check to see if it's an int or
+ * a char string to display for slot.
+ */
+ if (p->slot == PCI_SLOT_IS_STRING)
+ log_printf("%10s ", p->slot_str, 0);
+ else
+ log_printf("%10d ", p->slot, 0);
+
+ log_printf("%-28.28s", p->name, 0);
+ if (strlen(p->name) > 28)
+ log_printf("+ ", 0);
+ else
+ log_printf(" ", 0);
+ log_printf("%-19.19s", p->model, 0);
+ if (strlen(p->model) > 19)
+ log_printf("+", 0);
+ log_printf("\n", 0);
+ log_printf(" %10s ", p->status, 0);
+ if (strlen(p->notes) > 0)
+ log_printf("%s", p->notes, 0);
+ log_printf("\n\n", 0);
+ }
+}
+
+/*
+ * display all io devices
+ */
+static int
+display_io_device_info(picl_nodehdl_t plafh)
+{
+ int err;
+
+ err = gather_io_cards(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ logprintf_header(dgettext(TEXT_DOMAIN, "IO Devices"),
+ DEFAULT_LINE_WIDTH);
+
+ picldiag_display_io_cards(io_card_list);
+
+ free_io_cards(io_card_list);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print fan device information
+ */
+static int
+logprintf_fan_info(picl_nodehdl_t fanh)
+{
+ int err;
+ char *label;
+ char *unit;
+ int64_t speed;
+ int64_t min_speed;
+ picl_nodehdl_t fruph;
+
+ err = picldiag_get_fru_parent(fanh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 14);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-14s ", label);
+ free(label);
+
+ err = picldiag_get_label(fanh, &label);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-14s ", label);
+ free(label);
+ } else if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" - ");
+ } else
+ return (err);
+
+ speed = picldiag_get_uint_propval(fanh, PICL_PROP_FAN_SPEED, &err);
+ if (err == PICL_SUCCESS) {
+ min_speed = picldiag_get_uint_propval(fanh,
+ PICL_PROP_LOW_WARNING_THRESHOLD, &err);
+ if (err != PICL_SUCCESS)
+ min_speed = 1;
+ if (speed < min_speed) {
+ log_printf("failed (%lld", speed);
+ err = picldiag_get_string_propval(fanh,
+ PICL_PROP_FAN_SPEED_UNIT, &unit);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", unit);
+ free(unit);
+ }
+ log_printf(")");
+ } else {
+ log_printf("okay");
+ }
+ } else {
+ err = picldiag_get_string_propval(fanh,
+ PICL_PROP_FAN_SPEED_UNIT, &unit);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s ", unit);
+ free(unit);
+ }
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+fan_callback(picl_nodehdl_t fanh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+ log_printf(dgettext(TEXT_DOMAIN, "Fan Status:\n"));
+ log_printf("---------------------------------------\n");
+ log_printf("Location Sensor Status \n");
+ log_printf("---------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_fan_info(fanh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find fan device and print its speed
+ */
+static int
+display_fan_speed(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_FAN,
+ &print_header, fan_callback);
+ return (err);
+}
+
+/*
+ * print temperature sensor information
+ */
+static int
+logprintf_temp_info(picl_nodehdl_t temph)
+{
+ int err;
+ char *label;
+ int64_t temperature;
+ int64_t threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_temp = 0;
+
+ err = picldiag_get_fru_parent(temph, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 14);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-14s ", label);
+ free(label);
+
+ err = picldiag_get_label(temph, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-14s ", label);
+ free(label);
+
+ temperature = picldiag_get_int_propval(temph, PICL_PROP_TEMPERATURE,
+ &err);
+ if (err == PICL_SUCCESS) {
+ got_temp = 1;
+ status = "okay";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(temph, PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ if (strcmp(status, "failed") == 0 ||
+ strcmp(status, "warning") == 0)
+ log_printf("(%.2lldC)", temperature);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+temp_callback(picl_nodehdl_t temph, void *arg)
+{
+ int err;
+ int *countp = arg;
+
+ if (*countp == 0) {
+ log_printf("\n");
+ log_printf("---------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Temperature sensors:\n"));
+ log_printf("------------------------------------\n");
+ log_printf("Location Sensor Status\n");
+ log_printf("------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_temp_info(temph);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find temp sensors and print the temp
+ */
+/* ARGSUSED */
+static int
+display_temp(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_SENSOR,
+ &print_header, temp_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_INDICATOR,
+ &print_header, temp_callback);
+ return (err);
+}
+
+/*
+ * print current sensor information
+ */
+static int
+logprintf_current_info(picl_nodehdl_t currenth)
+{
+ int err;
+ char *label;
+ float current;
+ float threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_current = 0;
+
+ err = picldiag_get_fru_parent(currenth, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-10s ", label);
+ free(label);
+
+ err = picldiag_get_label(currenth, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-10s ", label);
+ free(label);
+
+ current = picldiag_get_float_propval(currenth, PICL_PROP_CURRENT, &err);
+ if (err == PICL_SUCCESS) {
+ status = "okay";
+ got_current = 1;
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth,
+ PICL_PROP_HIGH_SHUTDOWN, &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(currenth,
+ PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf(" %s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ if (strcmp(status, "failed") == 0 ||
+ strcmp(status, "warning") == 0)
+ log_printf("(%.2fA)", current);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+current_callback(picl_nodehdl_t currh, void *arg)
+{
+ int err;
+ int *countp = arg;
+
+ if (*countp == 0) {
+ log_printf("------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Current sensors:\n"));
+ log_printf("------------------------------\n");
+ log_printf("Location Sensor Status\n");
+ log_printf("------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_current_info(currh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find curr sensors and print the curr
+ */
+/* ARGSUSED */
+static int
+display_current(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_SENSOR,
+ &print_header, current_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_INDICATOR,
+ &print_header, current_callback);
+ return (err);
+}
+
+/*
+ * print voltage sensor information
+ */
+static int
+logprintf_voltage_info(picl_nodehdl_t voltageh)
+{
+ int err;
+ char *label;
+ float voltage;
+ float threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_voltage = 0;
+
+ err = picldiag_get_fru_parent(voltageh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-10s ", label);
+ free(label);
+
+ err = picldiag_get_label(voltageh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-12s ", label);
+ free(label);
+
+ voltage = picldiag_get_float_propval(voltageh, PICL_PROP_VOLTAGE, &err);
+ if (err == PICL_SUCCESS) {
+ status = "okay";
+ got_voltage = 1;
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh,
+ PICL_PROP_HIGH_SHUTDOWN, &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(voltageh,
+ PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ if (strcmp(status, "warning") == 0 ||
+ strcmp(status, "failed") == 0)
+ log_printf("(%.2fV)", voltage);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+voltage_callback(picl_nodehdl_t voltageh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+ log_printf("--------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Voltage sensors:\n"));
+ log_printf("-------------------------------\n");
+ log_printf("Location Sensor Status\n");
+ log_printf("-------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_voltage_info(voltageh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find voltage sensors and print voltage
+ */
+/* ARGSUSED */
+static int
+display_voltage(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_SENSOR,
+ &print_header, voltage_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_INDICATOR,
+ &print_header, voltage_callback);
+ return (err);
+}
+
+/*
+ * print led device information
+ */
+static int
+logprintf_led_info(picl_nodehdl_t ledh)
+{
+ int err;
+ char *label;
+ char *state;
+ char *color;
+ picl_nodehdl_t fruph;
+
+ err = picldiag_get_fru_parent(ledh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS) {
+ log_printf(" - ", label);
+ } else {
+ log_printf("%-10s ", label);
+ free(label);
+ }
+
+ err = picldiag_get_label(ledh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-20s ", label);
+ free(label);
+
+ err = picldiag_get_string_propval(ledh, PICL_PROP_STATE, &state);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" - ");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%-10s ", state);
+ free(state);
+ }
+
+ err = picldiag_get_string_propval(ledh, PICL_PROP_COLOR, &color);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf("\n");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%-16s\n", color);
+ free(color);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+static int
+led_callback(picl_nodehdl_t ledh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+
+ log_printf("--------------------------------------"
+ "------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Led State:\n"));
+ log_printf("--------------------------------------"
+ "------------\n");
+ log_printf("Location Led State"
+ " Color\n");
+ log_printf("--------------------------------------"
+ "------------\n");
+ }
+ *countp += 1;
+ err = logprintf_led_info(ledh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find led devices and print status
+ */
+/* ARGSUSED */
+static int
+display_led_status(picl_nodehdl_t plafh)
+{
+ int print_header;
+
+ print_header = 0;
+ picl_walk_tree_by_class(plafh, PICL_CLASS_LED,
+ &print_header, led_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print keyswitch device information
+ */
+static int
+logprintf_keyswitch_info(picl_nodehdl_t keyswitchh, picl_nodehdl_t fruph)
+{
+ int err;
+ char *label;
+ char *state;
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS) {
+ log_printf("%-14s", " -");
+ } else {
+ log_printf("%-14s ", label);
+ free(label);
+ }
+
+ err = picldiag_get_label(keyswitchh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-11s ", label);
+ free(label);
+
+ err = picldiag_get_string_propval(keyswitchh, PICL_PROP_STATE, &state);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" -\n");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%s\n", state);
+ free(state);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+static int
+keyswitch_callback(picl_nodehdl_t keyswitchh, void *arg)
+{
+ int *countp = arg;
+ int err;
+ picl_nodehdl_t fruph;
+
+ /*
+ * Tamale simulates a key-switch on ENxS. So the presence of a
+ * node of class keyswitch is not sufficient. If it has a fru parent
+ * or location parent, then believe it.
+ */
+ err = picl_get_propval_by_name(keyswitchh, PICL_REFPROP_FRU_PARENT,
+ &fruph, sizeof (fruph));
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(keyswitchh,
+ PICL_REFPROP_LOC_PARENT, &fruph, sizeof (fruph));
+ }
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE)
+ return (PICL_WALK_CONTINUE);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (*countp == 0) {
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Keyswitch:\n"));
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Keyswitch State\n"));
+ log_printf("-----------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_keyswitch_info(keyswitchh, fruph);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * search children to find keyswitch device(s) and print status
+ */
+/* ARGSUSED */
+static int
+display_keyswitch(picl_nodehdl_t plafh)
+{
+ int print_header = 0;
+
+ picl_walk_tree_by_class(plafh, PICL_CLASS_KEYSWITCH,
+ &print_header, keyswitch_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * display environment status
+ */
+static int
+display_envctrl_status(picl_nodehdl_t plafh)
+{
+ logprintf_header(dgettext(TEXT_DOMAIN, "Environmental Status"),
+ DEFAULT_LINE_WIDTH);
+
+ display_fan_speed(plafh);
+ display_temp(plafh);
+ display_current(plafh);
+ display_voltage(plafh);
+ display_keyswitch(plafh);
+ display_led_status(plafh);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print fru operational status
+ */
+static int
+logprintf_fru_oper_status(picl_nodehdl_t fruh, int *countp)
+{
+ int err;
+ char *label;
+ char *status;
+
+ err = picldiag_get_combined_label(fruh, &label, 15);
+ if (err != PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+
+ err = picldiag_get_string_propval(fruh,
+ PICL_PROP_OPERATIONAL_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ if (*countp == 0) {
+ logprintf_header(dgettext(TEXT_DOMAIN,
+ "FRU Operational Status"),
+ DEFAULT_LINE_WIDTH);
+ log_printf("-------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Fru Operational Status:\n"));
+ log_printf("-------------------------\n");
+ log_printf("Location Status \n");
+ log_printf("-------------------------\n");
+ }
+ *countp += 1;
+ log_printf("%-15s ", label);
+ free(label);
+ log_printf("%s\n", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ free(label);
+ return (err);
+ } else {
+ free(label);
+ }
+ return (PICL_WALK_CONTINUE);
+}
+
+static int
+fru_oper_status_callback(picl_nodehdl_t fruh, void *arg)
+{
+ int err;
+
+ err = logprintf_fru_oper_status(fruh, (int *)arg);
+ return (err);
+}
+
+/*
+ * display fru operational status
+ */
+static int
+display_fru_oper_status(picl_nodehdl_t frutreeh)
+{
+ int print_header;
+
+ print_header = 0;
+ picl_walk_tree_by_class(frutreeh, PICL_CLASS_FRU,
+ &print_header, fru_oper_status_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * check if the node having the version prop
+ * If yes, print its nodename and version
+ */
+/* ARGSUSED */
+static int
+asicrev_callback(picl_nodehdl_t nodeh, void *arg)
+{
+ uint32_t version;
+ char *name;
+ char *model;
+ char *status;
+ int err;
+
+ version = picldiag_get_uint_propval(nodeh, OBP_PROP_VERSION_NUM,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH, &name);
+ if (err == PICL_PROPNOTFOUND)
+ name = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* model */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_BINDING_NAME,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* status */
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND)
+ status = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Display the data
+ */
+
+ /* name */
+ if (name != NULL) {
+ log_printf("%-22s ", name);
+ free(name);
+ } else
+ log_printf("%-22s ", "unknown");
+ /* model */
+ if (model != NULL) {
+ log_printf("%-15s ", model);
+ free(model);
+ } else
+ log_printf("%-15s ", "unknown");
+ /* status */
+ if (status == NULL)
+ log_printf("%-15s ", "okay");
+ else {
+ log_printf("%-15s ", status);
+ free(status);
+ }
+ /* revision */
+ log_printf(" %-4d\n", version);
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * traverse the tree to display asic revision id for ebus
+ */
+/* ARGSUSED */
+static int
+ebus_callback(picl_nodehdl_t ebush, void *arg)
+{
+ uint32_t id;
+ char *name;
+ int err;
+ char *model;
+ char *status;
+
+ id = picldiag_get_uint_propval(ebush, OBP_PROP_REVISION_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* devfs-path */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_DEVFS_PATH, &name);
+ if (err == PICL_PROPNOTFOUND)
+ name = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* model */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_BINDING_NAME,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* status */
+ err = picldiag_get_string_propval(ebush, OBP_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND)
+ status = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Display the data
+ */
+
+ /* name */
+ if (name != NULL) {
+ log_printf("%-22s ", name);
+ free(name);
+ } else
+ log_printf("%-22s ", "unknown");
+ /* model */
+ if (model != NULL) {
+ log_printf("%-15s ", model);
+ free(model);
+ } else
+ log_printf("%-15s ", "unknown");
+ /* status */
+ if (status == NULL)
+ log_printf("%-15s ", "okay");
+ else {
+ log_printf("%-15s ", status);
+ free(status);
+ }
+ /* revision */
+ log_printf(" %-4d\n", id);
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * display asic revision id
+ */
+static int
+display_hw_revisions(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /* Print the header */
+ logprintf_header(dgettext(TEXT_DOMAIN, "HW Revisions"),
+ DEFAULT_LINE_WIDTH);
+
+ log_printf("ASIC Revisions:\n");
+ log_printf("-----------------------------");
+ log_printf("--------------------------------------\n");
+ log_printf("Path Device");
+ log_printf(" Status Revision\n");
+ log_printf("-----------------------------");
+ log_printf("--------------------------------------\n");
+
+ err = picl_walk_tree_by_class(plafh, NULL, NULL, asicrev_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_EBUS,
+ NULL, ebus_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_DISPLAY,
+ NULL, ffbconfig_callback);
+ return (err);
+}
+
+/*
+ * find the options node and its powerfail_time prop
+ * If found, display the list of latest powerfail.
+ */
+/* ARGSUSED */
+static int
+options_callback(picl_nodehdl_t nodeh, void *arg)
+{
+ time_t value;
+ char *failtime;
+ int err;
+
+ err = picldiag_get_string_propval(nodeh, PROP_POWERFAIL_TIME,
+ &failtime);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_TERMINATE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ value = (time_t)atoi(failtime);
+ free(failtime);
+ if (value == 0)
+ return (PICL_WALK_TERMINATE);
+
+ log_printf(dgettext(TEXT_DOMAIN, "Most recent AC Power Failure:\n"));
+ log_printf("=============================\n");
+ log_printf("%s", ctime(&value));
+ log_printf("\n");
+ return (PICL_WALK_TERMINATE);
+}
+
+/*
+ * display the OBP and POST prom revisions
+ */
+/* ARGSUSED */
+static int
+flashprom_callback(picl_nodehdl_t flashpromh, void *arg)
+{
+ picl_prophdl_t proph;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ picl_propinfo_t pinfo;
+ char *prom_version = NULL;
+ char *obp_version = NULL;
+ int err;
+
+ err = picl_get_propinfo_by_name(flashpromh, OBP_PROP_VERSION,
+ &pinfo, &proph);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_TERMINATE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf(dgettext(TEXT_DOMAIN, "System PROM revisions:\n"));
+ log_printf("----------------------\n");
+
+ /*
+ * If it's a table prop, the first element is OBP revision
+ * The second one is POST revision.
+ * If it's a charstring prop, the value will be only OBP revision
+ */
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ prom_version = alloca(pinfo.size);
+ if (prom_version == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, prom_version, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", prom_version);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE) /* not supported type */
+ return (PICL_WALK_TERMINATE);
+
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err == PICL_SUCCESS) {
+ /* get first row */
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ prom_version = alloca(pinfo.size);
+ if (prom_version == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, prom_version, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", prom_version);
+
+ /* get second row */
+ err = picl_get_next_by_col(rowproph, &rowproph);
+ if (err == PICL_SUCCESS) {
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ obp_version = alloca(pinfo.size);
+ if (obp_version == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(rowproph, obp_version,
+ pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", obp_version);
+ }
+ }
+
+ return (PICL_WALK_TERMINATE);
+}
+
+static int
+display_system_info(int serrlog, int log_flag, picl_nodehdl_t rooth)
+{
+ int err;
+ picl_nodehdl_t plafh;
+ picl_nodehdl_t frutreeh;
+
+ err = picldiag_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (!log_flag) {
+ err = display_platform_banner(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_system_clock(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY,
+ PICL_CLASS_MEMORY, memory_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_cpu_info(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_io_device_info(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_memory_config(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_usb_devices(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ if (serrlog) {
+ err = picl_walk_tree_by_class(rooth, PICL_CLASS_OPTIONS,
+ NULL, options_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_envctrl_status(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_node_by_name(rooth, PICL_NODE_FRUTREE,
+ &frutreeh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_fru_oper_status(frutreeh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_hw_revisions(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_FLASHPROM,
+ NULL, flashprom_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+/* ARGSUSED */
+int
+do_prominfo(int serrlog, char *pgname, int log_flag, int prt_flag)
+{
+ int err;
+ char *errstr;
+ int done;
+ picl_nodehdl_t rooth;
+
+ err = picl_initialize();
+ if (err != PICL_SUCCESS) {
+ fprintf(stderr, EM_INIT_FAIL, picl_strerror(err));
+ exit(1);
+ }
+
+ do {
+ done = 1;
+ err = picl_get_root(&rooth);
+ if (err != PICL_SUCCESS) {
+ fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err));
+ exit(1);
+ }
+
+ err = display_system_info(serrlog, log_flag, rooth);
+
+ if ((err == PICL_STALEHANDLE) || (err == PICL_INVALIDHANDLE))
+ done = 0;
+ } while (!done);
+
+ if (err != PICL_SUCCESS) {
+ errstr = picl_strerror(err);
+ fprintf(stderr, EM_PRTDIAG_FAIL);
+ fprintf(stderr, "%s\n", errstr? errstr : " ");
+ }
+
+ (void) picl_shutdown();
+
+ return (0);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/lw8/picl/Makefile b/usr/src/lib/libprtdiag_psr/sparc/lw8/picl/Makefile
new file mode 100644
index 0000000000..4ea8b5565c
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/lw8/picl/Makefile
@@ -0,0 +1,87 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/desktop/picl/Makefile
+
+UTSBASE = $(SRC)/uts
+
+PLATFORM_OBJECTS= lw8.o
+
+objs/%.o pics/%.o: ../common/%.c
+ $(COMPILE.c) $(IFLAGS) -o $@ $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/lib/libprtdiag_psr/sparc/Makefile.com
+
+SRCS= $(OBJECTS:%.o=../common/%.c)
+
+LDLIBS += -lpicl
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../../libprtdiag/inc
+IFLAGS += -I$(SRC)/cmd/picl/plugins/inc
+LINTFLAGS += $(IFLAGS)
+
+PLATFORM= SUNW,Netra-T12
+
+.KEEP_STATE:
+
+PLATLIBS= $(PLATFORM:%=$(USR_PLAT_DIR)/%/lib/)
+
+install: all $(PLATLIBS) $(USR_PSM_LIBS)
+
+#
+# install rules for SUNW,Sun-Blade-100/lib/libprtdiag_psr.so.1
+#
+$(PLATLIBS):
+ $(INS.dir)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(USR_PSM_LIB_DIR):
+ $(INS.dir)
+
+#
+# Rules for making message files
+#
+POFILE= libprtdiag_psr_lw8_picl.po
+POFILES= lw8.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext ../common/lw8.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/montecarlo/Makefile b/usr/src/lib/libprtdiag_psr/sparc/montecarlo/Makefile
new file mode 100644
index 0000000000..b5e733ffb2
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/montecarlo/Makefile
@@ -0,0 +1,104 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/montecarlo/Makefile
+
+LIBBASE = ../../../../../src/lib
+UTSBASE = ../../../../uts
+PLATFORM_OBJECTS= montecarlo.o
+
+include ../Makefile.com
+
+IFLAGS = -I$(USR_PLAT_DIR)/sun4u/include -I../../../libprtdiag/inc -I$(LIBBASE)/libdevinfo
+IFLAGS += -I$(UTSBASE)/sun4u/sys
+IFLAGS += -I$(UTSBASE)/sun4u/montecarlo/sys
+LINTFLAGS += $(IFLAGS)
+LDLIBS += -L$(LIBBASE)/libdevinfo -ldevinfo -L$(LIBBASE)/libcfgadm -lcfgadm \
+ -lkstat
+#
+# links in /usr/platform
+#
+LINKED_PLATFORMS = SUNW,UltraSPARC-IIe-NetraCT-40
+
+LINKED_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%)
+LINKED_LIB_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib)
+LINKED_PRTDIAG_DIRS = \
+ $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/libprtdiag_psr.so.1)
+
+#
+# SUNW,UltraSPARC-IIi-Netract and SUNW,UltraSPARC-IIe-NetraCT-40 platform
+# should install into SUNW,UltraSPARC-IIi-Netract.
+# SUNW,UltraSPARC-IIe-NetraCT-40 platform can link to
+# /usr/platform/SUNW,UltraSPARC-IIi-Netract/lib/libprtdiag_psr.so
+#
+PLATFORM=SUNW,UltraSPARC-IIi-Netract
+
+.KEEP_STATE:
+
+PLATLIBS= $(PLATFORM:%=$(USR_PLAT_DIR)/%/lib/)
+
+install: all $(PLATLIBS) $(USR_PSM_LIBS) \
+ $(LINKED_PRTDIAG_DIRS)
+
+#
+# install rules for SUNW,UltraSPARC-IIi-Netract/lib/libprtdiag_psr.so
+#
+$(PLATLIBS):
+ $(INS.dir)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/montecarlo; $(MAKE) $(USR_PSM_LIB_DIR)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(LINKED_DIRS): $(USR_PLAT_DIR)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIB_DIRS): $(LINKED_DIRS)
+ -$(INS.dir.root.sys)
+
+$(LINKED_PRTDIAG_DIRS): $(LINKED_LIB_DIRS)
+ -$(INS.slink6)
+
+
+# New additions to generate msg file
+POFILE = libprtdiag_psr_montecarlo.po
+POFILES = montecarlo.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/montecarlo.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/montecarlo/common/montecarlo.c b/usr/src/lib/libprtdiag_psr/sparc/montecarlo/common/montecarlo.c
new file mode 100644
index 0000000000..317235c2c6
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/montecarlo/common/montecarlo.c
@@ -0,0 +1,2454 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Netract Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_MONTECARLO
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* includes */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stropts.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <kstat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <sys/sunddi.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/devinfo_impl.h>
+#include <sys/ioccom.h>
+#include <sys/systeminfo.h>
+#include <libintl.h>
+#include <config_admin.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+#include "libdevinfo.h"
+
+/* MC specific header, might just include from MC space */
+#include "mct_topology.h"
+#include "envctrl_gen.h"
+#include "pcf8574_nct.h"
+#include "netract_gen.h"
+#include "hscimpl.h"
+#include "scsbioctl.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/* globals */
+#define MAXNAMESZ 128
+#define MAX_NODE_NAME_SZ 32
+
+/* this values equates to Max Tree depth for now */
+#define MAXIMUM_DEVS 64
+
+typedef char device_info_t[MAX_NODE_NAME_SZ];
+
+typedef struct {
+ cfga_list_data_t *ldatap;
+ int req; /* If set, this list_data was requested by user */
+} ap_out_t;
+
+
+typedef struct {
+ uint_t slot_addr;
+ uint_t slot_stat;
+ uint_t slot_cond;
+ device_info_t devs_info[MAXIMUM_DEVS];
+ uint_t number_devs;
+} mc_slot_info_t;
+
+typedef struct {
+ mc_slot_info_t mc_slot_info[MC_MAX_SLOTS];
+} slot_data_t;
+
+
+extern char *progname;
+extern int print_flag;
+
+/* These are used to store all force loads of the drivers */
+static int ps_fd[MC_MAX_PS];
+static int oprom_fd;
+static int slot_index = 0;
+static int idx_minuscpu = 0;
+static int num_devs = 0;
+static int sd_instances[MC_MAX_SLOTS*15];
+static int gpio_instances[MC_MAX_PS+MC_MAX_FAN];
+static int sd_count = 0;
+static int st_instance;
+static int gpio_count = 0;
+static int slot_table_not_found = 0;
+
+/* default not present */
+static int alarm_card_present = 0;
+static int cpu_ftm_present = 0;
+
+/*
+ * We will store all kstat in globals so that
+ * we can browse thru them later
+ */
+static int fail_syssoft_prop = 0;
+static int fail_drv_prop = 0;
+di_node_t rootnode; /* root nexus */
+slot_data_t mc_slots_data;
+
+/* scsb driver kstats */
+scsb_ks_leddata_t scsb_ks_leddata;
+scsb_ks_state_t scsb_ks_state;
+mct_topology_t scsb_ks_topo;
+
+/* pcf8574(gpio) driver kstats */
+envctrl_cpuvoltage_t pcf8574_ks_cpuv;
+envctrl_pwrsupp_t pcf8574_ks_ps1;
+envctrl_fantray_t pcf8574_ks_fant1;
+envctrl_pwrsupp_t pcf8574_ks_ps2;
+envctrl_fantray_t pcf8574_ks_fant2;
+
+/* pcf8591(adc-dac) driver kstats */
+envctrl_temp_t pcf8591_ks_temp;
+
+hsc_slot_table_t hotswap_slot_table[MC_MAX_SLOTS];
+hsc_prom_slot_table_t prom_slot_table[MC_MAX_SLOTS];
+
+static char *hotswap_mode = NULL;
+static char *slot_auto_config[MC_MAX_SLOTS];
+static int slot_table_size;
+
+/*
+ * use this to ascertain what's the system,
+ * default is tonga, we can add more for future variations
+ * 0=tonga, 1=montecarlo
+ * we need also to figure out what the system version is
+ * 0 = 1.5, 1 = 1.0, 0.6 etc.
+ */
+int montecarlo = 0;
+int version_p15_and_p20 = 0;
+
+#define MAX_PRTDIAG_INFO_LENGTH 1024
+#define MAX_PRTDIAG_FRUS 22
+#define BIT_TEST(X, N) ((X) & (1 << (N)))
+#define SLOT1_OK_BIT 0
+#define SLOT2_OK_BIT 1
+#define SLOT3_OK_BIT 2
+#define SLOT4_OK_BIT 3
+#define SLOT5_OK_BIT 4
+#define SLOT6_OK_BIT 5
+#define SLOT7_OK_BIT 6
+#define SLOT8_OK_BIT 7
+#define PDU1_OK_BIT SLOT2_OK_BIT
+#define PDU2_OK_BIT SLOT4_OK_BIT
+#define FTM_OK_BIT SLOT5_OK_BIT
+#define SCB_OK_BIT SLOT6_OK_BIT
+#define FAN1_OK_BIT SLOT1_OK_BIT
+#define FAN2_OK_BIT SLOT2_OK_BIT
+#define DISK1_OK_BIT SLOT4_OK_BIT
+#define DISK2_OK_BIT SLOT5_OK_BIT
+#define DISK3_OK_BIT SLOT6_OK_BIT
+#define PS1_OK_BIT SLOT7_OK_BIT
+#define PS2_OK_BIT SLOT8_OK_BIT
+#define S_FREE(x) (((x) != NULL) ? (free(x), (x) = NULL) : (void *)0)
+#define ENVC_DEBUG_MODE 0x03
+#define OPENPROMDEV "/dev/openprom"
+#define I2C_PCF8591_NAME "adc-dac"
+#define I2C_KSTAT_CPUTEMP "adc_temp"
+#define SCSB_DEV "scsb"
+#define SDERR "sderr"
+#define STERR "sterr"
+#define OK "ok"
+#define NOK "Not ok"
+#define ON "on"
+#define OFF "off"
+#define BLINK "blink"
+#define NA "Not Available"
+#define UK "Unknown "
+#define YES "Yes"
+#define NO "No "
+#define LO "low"
+#define HI "high"
+#define BLANK " "
+#define SYSSOFT_PROP "System software"
+#define DRV_PROP "Driver"
+#define HSC_PROP_NAME "hsc-slot-map"
+#define HSC_MODE "hotswap-mode"
+#define PCI_ROOT_AP "pci"
+#define PROPS "Properties:"
+#define BOARDTYPE "Board Type:"
+#define DEVS "Devices:"
+#define CPCI_IO "CompactPCI IO Slot"
+#define AC_CARD "Alarm Card"
+#define CPU_FTM "Front Transition Module"
+#define SCTRL_PROM_P06 0x00
+#define SCTRL_PROM_P10 0x01
+#define SCTRL_PROM_P15 0x02
+#define SCTRL_PROM_P20 0x03
+
+#define RMM_NUMBER 3
+
+#define MONTECARLO_PLATFORM "SUNW,UltraSPARC-IIi-Netract"
+#define MAKAHA_PLATFORM "SUNW,UltraSPARC-IIe-NetraCT-40"
+
+/*
+ * The follow table is indexed with the enum's defined by mct_slot_occupant_t
+ * OC_UNKN OC_CPU OC_AC OC_BHS OC_FHS OC_HAHS
+ * OC_QFE OC_FRCH OC_COMBO OC_PMC OC_ATM
+ *
+ * But "scsb" can currently identify only CPU and Alarm Cards by known
+ * slot numbers.
+ */
+char *slot_occupants[] = {
+ CPCI_IO,
+ "CPU board ",
+ CPCI_IO,
+ "Basic HotSwap Board",
+ "Full HotSwap Board",
+ "HA Board",
+ "QFE Board",
+ "Fresh Choice Board",
+ "SUN Combo Board",
+ "PMC Board",
+ "ATM Board"
+ };
+
+static char *prtdiag_fru_types[] = {
+ "I/O ", /* 0 */
+ "CPU ",
+ "PSU ",
+ "HDD ",
+ "FAN ",
+ "Alarm Card ",
+ "SCB ",
+ "SSB ",
+ "CFTM ",
+ "CRTM ",
+ "PRTM ",
+ "Midplane " /* 11 */
+ };
+
+char prtdiag_fru_info[MAX_PRTDIAG_FRUS][MAX_PRTDIAG_INFO_LENGTH];
+
+#define SCB_REG_READ 1
+#define SCB_REG_WRITE 2
+
+/* Standard Device nodes - hardwired for now */
+/* will include fan tray later, cpu voltage not impl */
+static char *scsb_node = NULL;
+static char **ps_node = NULL;
+static char *temp_node = NULL;
+
+static char *mc_scsb_node =
+"/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/sysctrl@0,80:scsb";
+
+static char *ot_scsb_node =
+"/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/sysctrl@0,80:scsb";
+
+static char *mc_ps_node[] = {
+"/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/gpio@0,7c:pwrsuppply",
+"/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/gpio@0,7e:pwrsuppply"
+};
+
+static char *ot_ps_node[] = {
+"/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/gpio@0,7c:pwrsuppply",
+"/devices/pci@1f,0/pci@1,1/ebus@3/sysmgmt@14,600000/gpio@0,7e:pwrsuppply"
+};
+
+static char *mc_temp_node =
+"/devices/pci@1f,0/pci@1,1/ebus@1/i2c@14,600000/adc-dac@0,9e:cputemp";
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (netract systems only)
+ * display functions
+ */
+int display(Sys_tree *, Prom_node *, struct system_kstat_data *, int);
+/* local functions */
+/*
+ * prom function
+ */
+static void gather_diaginfo(int flag);
+static int extract_slot_table_from_obp();
+static int mc_next(int id);
+static void mc_walk(int id);
+static int mc_child(int id);
+static void mc_dump_node(int id);
+static int mc_getpropval(struct openpromio *opp);
+
+#ifdef REDUNDANT_INFO
+static int mc_get_cpu_freq(Prom_node *node);
+static int mc_get_ecache_size(Prom_node *node);
+static void mc_display_cpus(Board_node *board);
+static void mc_display_cpu_devices(Sys_tree *tree);
+#endif /* REDUNDANT_INFO */
+
+static void netract_disp_prom_version();
+
+/*
+ * Since we do not have a system wide kstat for MC/Tg
+ * here we have to do specific kstats to drivers that
+ * post this information - MC/Tg specific drivers
+ * that post kstat here are : scsb, pcf8574(gpio) and pcf8591
+ */
+static int analyze_nodes(di_node_t, void*);
+static void analyze_pcipci_siblings(di_node_t);
+static void display_mc_prtdiag_info();
+static int dump_devs(di_node_t, void *);
+static void prtdiag_devinfo(void);
+static void force_load_drivers();
+static int dump_prop_list(char *name,
+ di_node_t node, di_prop_t (*nxtprop)());
+static void *config_calloc_check(size_t nelem, size_t elsize);
+static void explore_slot_occupants();
+static void do_scsb_kstat();
+static void do_pcf8574_kstat();
+static void do_pcf8591_kstat();
+static void do_promversion();
+static int mc_promopen(int oflag);
+static int scsi_disk_status(int disk_number);
+static void alarm_card_occupant();
+static int scsb_mode(int fd, scsb_op_t sop, uint8_t *new_mode);
+static int scsb_ioc_reg_read(int fd, uchar_t index,
+ scsb_ioc_rdwr_t *ioc_rd, int num);
+
+static int check_platform();
+
+int
+display(Sys_tree *tree,
+ Prom_node *root,
+ struct system_kstat_data *kstats,
+ int syserrlog)
+{
+ int exit_code = 0; /* init to all OK */
+ void *value; /* used for opaque PROM data */
+ struct mem_total memory_total; /* Total memory in system */
+ struct grp_info grps; /* Info on all groups in system */
+#ifdef lint
+ syserrlog = syserrlog;
+#endif
+ sys_clk = -1; /* System clock freq. (in MHz) */
+ /*
+ * Now display the machine's configuration. We do this if we
+ * are not logging or exit_code is set (machine is broke).
+ */
+ if (!logging || exit_code) {
+ struct utsname uts_buf;
+
+ /*
+ * Display system banner
+ */
+ (void) uname(&uts_buf);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System Configuration: Sun Microsystems"
+ " %s %s\n"), uts_buf.machine,
+ get_prop_val(find_prop(root, "banner-name")), 0);
+
+ /* display system clock frequency */
+ value = get_prop_val(find_prop(root, "clock-frequency"));
+ if (value != NULL) {
+ sys_clk = ((*((int *)value)) + 500000) / 1000000;
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System clock frequency: "
+ "%d MHz\n"), sys_clk, 0);
+ }
+
+ /* Display the Memory Size */
+ display_memorysize(tree, kstats, &grps, &memory_total);
+ /* Lets make sure we have all the needed drivers loaded */
+ /* display Montecarlo/Tonga FRU information */
+ if (!extract_slot_table_from_obp())
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\r\nslot-table not available\r\n"), 0);
+ do_scsb_kstat();
+ force_load_drivers();
+ gather_diaginfo(print_flag && !logging);
+ /* figure out if ac is present */
+ alarm_card_occupant();
+ /* platform specific display mod */
+ display_mc_prtdiag_info();
+ di_fini(rootnode);
+ netract_disp_prom_version();
+ } /* if (!logging || exit_code) */
+
+ return (exit_code);
+
+} /* display(....) */
+
+static int
+check_platform()
+{
+ char si_platform[SYS_NMLN];
+
+ /*
+ * Check for the platform: Montecarlo or Makaha/CP2040 based
+ */
+ if (sysinfo(SI_PLATFORM, si_platform, sizeof (si_platform)) == -1) {
+ return (-1);
+ }
+
+ if ((strncmp(si_platform, MONTECARLO_PLATFORM,
+ strlen(MONTECARLO_PLATFORM))) == 0) {
+ scsb_node = mc_scsb_node;
+ ps_node = mc_ps_node;
+ temp_node = mc_temp_node;
+ } else if ((strncmp(si_platform, MAKAHA_PLATFORM,
+ strlen(MAKAHA_PLATFORM))) == 0) {
+ scsb_node = ot_scsb_node;
+ ps_node = ot_ps_node;
+ temp_node = NULL;
+ } else {
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+force_load_drivers()
+{
+ int i;
+
+ if (NULL == scsb_node || NULL == ps_node) {
+ if (check_platform() == -1) {
+ return;
+ }
+ }
+
+ /* check scb/ssb presence */
+ if (scsb_ks_state.scb_present || scsb_ks_state.ssb_present) {
+ if (open(scsb_node, O_RDONLY) < 0)
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nscsb open FAILED!"), 0);
+ }
+
+ /* check the num of PS we have */
+ for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) {
+ if (scsb_ks_topo.mct_ps[i].fru_status == FRU_PRESENT) {
+ if ((ps_fd[i] = open(ps_node[i], O_RDONLY)) < 0)
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\npowersupply%d open failed"),
+ i, 0);
+ }
+ } /* for */
+
+ /* open the cpu temp driver */
+ if (temp_node) {
+ if (open(temp_node, O_RDONLY) < 0)
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\ncputemp open FAILED!"), 0);
+ }
+}
+
+
+void
+explore_slot_occupants()
+{
+ char *cp = NULL;
+ int index;
+ int ret = CFGA_ERROR;
+ char *estrp = NULL;
+ cfga_list_data_t *list_array = NULL;
+ ap_out_t *out_array = NULL;
+ int nlist = 0;
+ char *prefilt_optp = NULL;
+ int dyn_exp = 1;
+ char *plat_opts = NULL;
+
+ ret = config_list_ext(0, NULL, &list_array,
+ &nlist, plat_opts, prefilt_optp, &estrp,
+ dyn_exp ? CFGA_FLAG_LIST_ALL : 0);
+ if (ret != CFGA_OK) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\ncannot explore configuration"), 0);
+ return;
+ }
+ assert(nlist != 0);
+ out_array = config_calloc_check(nlist, sizeof (*out_array));
+ if (out_array == NULL) {
+ ret = CFGA_LIB_ERROR;
+ goto bail;
+ }
+ /* create a list of output stat data */
+ for (index = 0; index < nlist; index++) {
+ out_array[index].ldatap = &list_array[index];
+ out_array[index].req = 0;
+ }
+
+ for (index = 0; index < nlist; index++) {
+ if ((cp = strstr(out_array[index].ldatap->ap_phys_id,
+ "cpci_slot")) != NULL) {
+ mc_slots_data.mc_slot_info[idx_minuscpu].slot_stat
+ = out_array[index].ldatap->ap_o_state;
+ mc_slots_data.mc_slot_info[idx_minuscpu].slot_cond
+ = out_array[index].ldatap->ap_cond;
+ idx_minuscpu++;
+ }
+ }
+bail:
+ S_FREE(list_array);
+ S_FREE(out_array);
+}
+
+
+/*
+ * config_calloc_check - perform allocation, check result and
+ * set error indicator
+ */
+void *
+config_calloc_check(
+ size_t nelem,
+ size_t elsize)
+{
+ void *p;
+ static char alloc_fail[] =
+ "%s: memory allocation failed (%d*%d bytes)\n";
+
+ p = calloc(nelem, elsize);
+ if (p == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, alloc_fail), nelem, elsize, 0);
+ }
+ return (p);
+}
+
+
+void
+do_scsb_kstat()
+{
+ kstat_ctl_t *kc;
+ kstat_t *ksp_leddata;
+ kstat_t *ksp_state;
+ kstat_t *ksp_topo;
+ scsb_ks_leddata_t *pks_leddata;
+ scsb_ks_state_t *pks_state;
+ mct_topology_t *pks_topo;
+ int i;
+
+#ifdef DEBUG_TEMP1
+ int index;
+#endif
+ if (!(kc = kstat_open())) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_open failed", 0);
+#endif
+ return;
+ }
+#ifdef lint
+ kc = kc;
+#endif
+ /* get kstat on scsb led data */
+ if ((ksp_leddata = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_LEDDATA))
+ == NULL) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_lookup for scsb_leddata failed", 0);
+#endif
+ return;
+ }
+ if (kstat_read(kc, ksp_leddata, NULL) == -1) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_read for scsb_leddata failed", 0);
+#endif
+ return;
+ }
+ pks_leddata = (scsb_ks_leddata_t *)ksp_leddata->ks_data;
+ scsb_ks_leddata = *pks_leddata; /* set the globals for future */
+#ifdef DEBUG_LEDS
+ /* dump the kstat leddata */
+ printf("\nDumping LED regs: ");
+ for (i = 0; i < SCSB_LEDDATA_REGISTERS; ++i) {
+ log_printf("0x%x ", pks_leddata->scb_led_regs[i] & 0xff, 0);
+ }
+ log_printf("\n", 0);
+#endif
+ /* get kstat on scsb states */
+ if ((ksp_state = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_STATE))
+ == NULL) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_lookup for scsb_state failed", 0);
+#endif
+ return;
+ }
+ if (kstat_read(kc, ksp_state, NULL) == -1) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_read for scsb_state failed", 0);
+#endif
+ return;
+ }
+ pks_state = (scsb_ks_state_t *)ksp_state->ks_data;
+ scsb_ks_state = *pks_state; /* set the global for future */
+#ifdef DEBUG_TEMP1
+ /* dump the kstat state */
+ log_printf("\tSCB is%spresent\n",
+ pks_state->scb_present ? " " : " not ", 0);
+ log_printf("\tSSB is%spresent\n",
+ pks_state->ssb_present ? " " : " not ", 0);
+ log_printf("\tscsb is%sfrozen\n",
+ pks_state->scsb_frozen ? " " : " not ", 0);
+ log_printf("\tscsb mode: ", 0);
+ switch (pks_state->scsb_mode) {
+ case ENVC_DEBUG_MODE:
+ log_printf("DEBUG MODE\n", 0);
+ break;
+ case ENVCTRL_DIAG_MODE:
+ log_printf("DIAGNOSTIC MODE\n", 0);
+ break;
+ case ENVCTRL_NORMAL_MODE:
+ log_printf("NORMAL MODE\n", 0);
+ break;
+ }
+ log_printf("\tscsb event code: 0x%x\n", pks_state->event_code, 0);
+#endif /* DEBUG_TEMP1 */
+
+ if ((ksp_topo = kstat_lookup(kc, SCSB_DEV, 0, SCSB_KS_TOPOLOGY))
+ == NULL) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_lookup for scsb_topo failed", 0);
+#endif
+ return;
+ }
+ if (kstat_read(kc, ksp_topo, NULL) == -1) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_read for scsb_topo failed", 0);
+#endif
+ return;
+ }
+ pks_topo = (mct_topology_t *)ksp_topo->ks_data;
+ scsb_ks_topo = *pks_topo; /* set the global for future */
+ /*
+ * we need to set this so that we can get status info
+ * for the 2 powersupplies in MC as we need to get
+ * kstat from both driver instances for environment
+ */
+ if (pks_topo->mid_plane.fru_id == SCTRL_MPID_HALF)
+ montecarlo = 1; /* Monte Carlo */
+ /*
+ * HW version 0.6 and 1.0 had different led maps
+ * its assumed that HW 2.0 would not change this
+ * need to modify if it does
+ */
+ if ((pks_topo->mct_scb[0].fru_version == SCTRL_PROM_P15) ||
+ (pks_topo->mct_scb[0].fru_version == SCTRL_PROM_P20)) {
+ version_p15_and_p20 = 1;
+ }
+
+ /* set flag to note that CFTM is present */
+ for (i = 0; i < pks_topo->max_units[CFTM]; ++i) {
+ if (pks_topo->mct_cftm[i].fru_status == FRU_PRESENT)
+ cpu_ftm_present = 1;
+ }
+
+#ifdef DEBUG_TEMP1
+ /*
+ * Midplane
+ */
+ log_printf("Midplane type: ", 0);
+ if (pks_topo->mid_plane.fru_id == SCTRL_MPID_HALF)
+ log_printf("Netra ct800 server\n", 0);
+ else
+ log_printf("Netra ct400 server%s\n",
+ pks_topo->mid_plane.fru_id ==
+ SCTRL_MPID_QUARTER_NODSK ? ", no disk" : " with disk", 0);
+ log_printf("Midplane version: %d\n",
+ pks_topo->mid_plane.fru_version, 0);
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_scb[0].fru_type,
+ pks_topo->mct_scb[0].fru_unit,
+ pks_topo->mct_scb[0].fru_id,
+ pks_topo->mct_scb[0].fru_version, 0);
+ /*
+ * Slots
+ */
+ log_printf("Slots present out of maximum %d\n",
+ pks_topo->max_units[SLOT], 0);
+ for (i = 0; i < pks_topo->max_units[SLOT]; ++i) {
+ if (pks_topo->mct_slots[i].fru_status != FRU_PRESENT)
+ continue;
+ index = (int)pks_topo->mct_slots[i].fru_type;
+ log_printf("\tSlot %d occupant: %s;",
+ pks_topo->mct_slots[i].fru_unit, slot_occupants[index], 0);
+ log_printf(" ID 0x%x; VER 0x%x ; ",
+ pks_topo->mct_slots[i].fru_id,
+ pks_topo->mct_slots[i].fru_version, 0);
+ log_printf(" Slot health %d\n",
+ pks_topo->mct_slots[i].fru_health, 0);
+ /* pks_topo->mct_slots[i].fru_health */
+ }
+
+ /*
+ * PDU
+ */
+ log_printf("PDUs present out of maximum %d\n",
+ pks_topo->max_units[PDU], 0);
+ for (i = 0; i < pks_topo->max_units[PDU]; ++i) {
+ if (pks_topo->mct_pdu[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_pdu[i].fru_type,
+ pks_topo->mct_pdu[i].fru_unit,
+ pks_topo->mct_pdu[i].fru_id,
+ pks_topo->mct_pdu[i].fru_version, 0);
+ /* pks_topo->mct_pdu[i].fru_health */
+ }
+
+ /*
+ * Power Supplies
+ */
+ log_printf("Power Supplies present out of maximum %d\n",
+ pks_topo->max_units[PS], 0);
+ for (i = 0; i < pks_topo->max_units[PS]; ++i) {
+ if (pks_topo->mct_ps[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_ps[i].fru_type,
+ pks_topo->mct_ps[i].fru_unit,
+ pks_topo->mct_ps[i].fru_id,
+ pks_topo->mct_ps[i].fru_version, 0);
+ }
+
+ /*
+ * Disks
+ */
+ log_printf("Disks present out of maximum %d\n",
+ pks_topo->max_units[DISK], 0);
+ for (i = 0; i < pks_topo->max_units[DISK]; ++i) {
+ if (pks_topo->mct_disk[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_disk[i].fru_type,
+ pks_topo->mct_disk[i].fru_unit,
+ pks_topo->mct_disk[i].fru_id,
+ pks_topo->mct_disk[i].fru_version, 0);
+ }
+
+ /*
+ * Fans
+ */
+ log_printf("Fans present out of maximum %d\n",
+ pks_topo->max_units[FAN], 0);
+ for (i = 0; i < pks_topo->max_units[FAN]; ++i) {
+ if (pks_topo->mct_fan[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_fan[i].fru_type,
+ pks_topo->mct_fan[i].fru_unit,
+ pks_topo->mct_fan[i].fru_id,
+ pks_topo->mct_fan[i].fru_version, 0);
+ }
+
+ /*
+ * SCBs
+ */
+ log_printf("SCBs present out of maximum %d\n",
+ pks_topo->max_units[SCB], 0);
+ for (i = 0; i < pks_topo->max_units[SCB]; ++i) {
+ if (pks_topo->mct_scb[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_scb[i].fru_type,
+ pks_topo->mct_scb[i].fru_unit,
+ pks_topo->mct_scb[i].fru_id,
+ pks_topo->mct_scb[i].fru_version, 0);
+ }
+
+ /*
+ * SSBs
+ */
+ log_printf("SSBs present out of maximum %d\n",
+ pks_topo->max_units[SSB], 0);
+ for (i = 0; i < pks_topo->max_units[SSB]; ++i) {
+ if (pks_topo->mct_ssb[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_ssb[i].fru_type,
+ pks_topo->mct_ssb[i].fru_unit,
+ pks_topo->mct_ssb[i].fru_id,
+ pks_topo->mct_ssb[i].fru_version, 0);
+ }
+
+ /*
+ * Alarms Cards
+ */
+ log_printf("Alarm Cards present out of maximum %d\n",
+ pks_topo->max_units[ALARM], 0);
+ for (i = 0; i < pks_topo->max_units[ALARM]; ++i) {
+ if (pks_topo->mct_alarm[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d; unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_alarm[i].fru_type,
+ pks_topo->mct_alarm[i].fru_unit,
+ pks_topo->mct_alarm[i].fru_id,
+ pks_topo->mct_alarm[i].fru_version, 0);
+ }
+
+ /*
+ * CFTMs
+ */
+ log_printf("CFTMs present out of maximum %d\n",
+ pks_topo->max_units[CFTM], 0);
+ for (i = 0; i < pks_topo->max_units[CFTM]; ++i) {
+ if (pks_topo->mct_cftm[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_cftm[i].fru_type,
+ pks_topo->mct_cftm[i].fru_unit,
+ pks_topo->mct_cftm[i].fru_id,
+ pks_topo->mct_cftm[i].fru_version, 0);
+ }
+
+ /*
+ * CRTMs
+ */
+ log_printf("CRTMs present out of maximum %d\n",
+ pks_topo->max_units[CRTM], 0);
+ for (i = 0; i < pks_topo->max_units[CRTM]; ++i) {
+ if (pks_topo->mct_crtm[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_crtm[i].fru_type,
+ pks_topo->mct_crtm[i].fru_unit,
+ pks_topo->mct_crtm[i].fru_id,
+ pks_topo->mct_crtm[i].fru_version, 0);
+ }
+
+ /*
+ * PRTMs
+ */
+ log_printf("PRTMs present out of maximum %d\n",
+ pks_topo->max_units[PRTM], 0);
+ for (i = 0; i < pks_topo->max_units[PRTM]; ++i) {
+ if (pks_topo->mct_prtm[i].fru_status != FRU_PRESENT)
+ continue;
+ log_printf("\ttype %d unit %d; id 0x%x; VER 0x%x\n",
+ pks_topo->mct_prtm[i].fru_type,
+ pks_topo->mct_prtm[i].fru_unit,
+ pks_topo->mct_prtm[i].fru_id,
+ pks_topo->mct_prtm[i].fru_version, 0);
+ }
+#endif /* DEBUG_TEMP1 */
+
+} /* do_scsb_kstat(...) */
+
+
+void
+do_pcf8574_kstat()
+{
+ kstat_ctl_t *kc;
+ kstat_t *ksp_ps;
+ kstat_t *ksp_fan;
+ envctrl_pwrsupp_t *pks_ps;
+ envctrl_fantray_t *pks_fan;
+ int i;
+ char *kstat_name = NULL;
+
+ if (!(kc = kstat_open())) {
+#ifdef DEBUG_TEMP
+ log_printf("\nkstat_open for pcf8574 failed", 0);
+#endif
+ return;
+ }
+
+#ifdef lint
+ kc = kc;
+#endif
+ /* get kstat on gpio powersupply and fan states */
+ for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) {
+ if (i == 1) {
+ kstat_name = I2C_KSTAT_PWRSUPPLY;
+ strncat(kstat_name, "1", 1);
+ } else {
+ kstat_name = I2C_KSTAT_PWRSUPPLY;
+ strncat(kstat_name, "2", 1);
+ }
+ if ((ksp_ps = kstat_lookup(kc, I2C_PCF8574_NAME, 0, kstat_name))
+ == NULL) {
+#ifdef DEBUG_TEMP
+ log_printf("\nks lookup for pwrsupply%d failed",
+ i+1, 0);
+#endif
+ return;
+ }
+ if (kstat_read(kc, ksp_ps, NULL) == -1) {
+#ifdef DEBUG_TEMP
+ log_printf("\nks read for pwrsupply%d failed", i+1, 0);
+#endif
+ return;
+ }
+ pks_ps = (envctrl_pwrsupp_t *)ksp_ps->ks_data;
+ if (i == 1)
+ pcf8574_ks_ps1 = *pks_ps; /* ps 1 */
+ else
+ pcf8574_ks_ps2 = *pks_ps; /* ps 2 */
+ } /* for */
+ for (i = 0; i < scsb_ks_topo.max_units[FAN]; ++i) {
+ if (i == 1) {
+ kstat_name = I2C_KSTAT_FANTRAY;
+ strncat(kstat_name, "1", 1);
+ } else {
+ kstat_name = I2C_KSTAT_FANTRAY;
+ strncat(kstat_name, "2", 1);
+ }
+ if ((ksp_fan = kstat_lookup(kc, I2C_PCF8574_NAME,
+ 0, kstat_name)) == NULL) {
+#ifdef DEBUG_TEMP
+ log_printf("\nks lookup for fantray%d failed",
+ i+1, 0);
+#endif
+ return;
+ }
+ if (kstat_read(kc, ksp_fan, NULL) == -1) {
+#ifdef DEBUG_TEMP
+ log_printf("\nks read for fantray%d failed", i+1, 0);
+#endif
+ return;
+ }
+ pks_fan = (envctrl_fantray_t *)ksp_fan->ks_data;
+ if (i == 1)
+ pcf8574_ks_fant1 = *pks_fan; /* fan 1 */
+ else
+ pcf8574_ks_fant2 = *pks_fan; /* fan 2 */
+ } /* for */
+ kstat_close(kc);
+
+} /* do_pcf8574_kstat(...) */
+
+void
+do_pcf8591_kstat()
+{
+ kstat_ctl_t *kc;
+ kstat_t *ksp_temp;
+
+ envctrl_temp_t *pks_temp;
+
+ if (!(kc = kstat_open())) {
+#ifdef DEBUG_TEMP
+ log_printf("ks open for pcf8591 failed", 0);
+#endif
+ return;
+ }
+#ifdef lint
+ kc = kc;
+#endif
+ /* get kstat on adc driver's CPU temperature data */
+ if ((ksp_temp = kstat_lookup(kc, I2C_PCF8591_NAME,
+ -1, I2C_KSTAT_CPUTEMP))
+ == NULL) {
+#ifdef DEBUG_TEMP
+ log_printf("ks lookup for adc_temp failed", 0);
+#endif
+ return;
+ }
+ if (kstat_read(kc, ksp_temp, NULL) == -1) {
+#ifdef DEBUG_TEMP
+ log_printf("ks read for adc_temp failed", 0);
+#endif
+ return;
+ }
+ pks_temp = (envctrl_temp_t *)ksp_temp->ks_data;
+ pcf8591_ks_temp = *pks_temp;
+ kstat_close(kc);
+} /* do_pcf8591_kstat(.) */
+
+
+void
+gather_diaginfo(int flag)
+{
+ if (flag) {
+ /* gather system environmental conditions. */
+ /* obtain kstat info from gpio & temp. driver */
+ do_pcf8574_kstat();
+ do_pcf8591_kstat();
+ explore_slot_occupants(); /* fill in some occupant info */
+ prtdiag_devinfo();
+ analyze_pcipci_siblings(rootnode);
+ }
+
+} /* display_diaginfo(...) */
+
+void
+netract_disp_prom_version()
+{
+ /* Display Prom revision header */
+ log_printf(dgettext(TEXT_DOMAIN, "System Board PROM revision:\n"), 0);
+ log_printf("---------------------------\n", 0);
+ do_promversion();
+
+} /* netract_disp_prom_version(.) */
+
+
+/*
+ * Get and print the PROM version.
+ */
+void
+do_promversion(void)
+{
+ Oppbuf oppbuf;
+ struct openpromio *opp = &(oppbuf.opp);
+
+ if (mc_promopen(O_RDONLY)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nCannot open openprom device"), 0);
+ return;
+ }
+
+ opp->oprom_size = MAXVALSIZE;
+ if (ioctl(oprom_fd, OPROMGETVERSION, opp) < 0) {
+ perror("\nOPROMGETVERSION ioctl failed");
+ return;
+ }
+ log_printf("%s\n", opp->oprom_array, 0);
+
+ if (close(oprom_fd) < 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nclose error on %s"), OPENPROMDEV, 0);
+ return;
+ }
+} /* do_promversion() */
+
+int
+mc_promopen(int oflag)
+{
+ for (;;) {
+ if ((oprom_fd = open(OPENPROMDEV, oflag)) < 0) {
+ if (errno == EAGAIN) {
+ (void) sleep(5);
+ continue;
+ }
+ if (errno == ENXIO)
+ return (-1);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\ncannot open %s"), OPENPROMDEV, 0);
+ return (1);
+ } else
+ return (0);
+ }
+}
+
+
+/*
+ * This will return -1 for status unknown, 0 for OK, and 1 for failed (scsi
+ * hard errors)
+ * swiped from envmon policies
+ */
+int
+scsi_disk_status(int disk_number)
+{
+ kstat_ctl_t *kc;
+ kstat_t *ksp_disk;
+ kstat_named_t *disk_data;
+
+ int i;
+ int nlist = 0;
+ cfga_list_data_t *list_array = NULL;
+ char *ap_ids[] = {"c0"};
+
+ if ((kc = kstat_open()) == NULL) {
+ log_printf(dgettext(TEXT_DOMAIN, "\nks open failed"), 0);
+ return (-1);
+ }
+
+ if (disk_number == RMM_NUMBER) { /* RMM */
+ if (config_list_ext(1, ap_ids, &list_array, &nlist,
+ NULL, NULL, NULL, CFGA_FLAG_LIST_ALL) != CFGA_OK) {
+ kstat_close(kc);
+ return (-1);
+ }
+ for (i = 0; i < nlist; i++) {
+ if (strstr(list_array[i].ap_phys_id, "rmt/0") != NULL) {
+ /* Tape drive */
+ if (list_array[i].ap_o_state ==
+ CFGA_STAT_UNCONFIGURED) {
+ kstat_close(kc);
+ return (-1);
+ }
+ if ((ksp_disk = kstat_lookup(kc, STERR,
+ st_instance, NULL)) == NULL) {
+ kstat_close(kc);
+ return (-1);
+ }
+ break;
+ } else if (strstr(list_array[i].ap_phys_id,
+ "dsk/c0t6d0") != NULL) {
+ /* CD_ROM */
+ if (list_array[i].ap_o_state ==
+ CFGA_STAT_UNCONFIGURED) {
+ kstat_close(kc);
+ return (-1);
+ }
+ if ((ksp_disk = kstat_lookup(kc, SDERR,
+ sd_instances[disk_number-1], NULL)) ==
+ NULL) {
+ kstat_close(kc);
+ return (-1);
+ }
+ break;
+ }
+ }
+ } else { /* Hard disk */
+ if ((ksp_disk = kstat_lookup(kc, SDERR,
+ sd_instances[disk_number-1], NULL)) == NULL) {
+ kstat_close(kc);
+ return (-1);
+ }
+ }
+
+ if (kstat_read(kc, ksp_disk, NULL) == -1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nks read error for disk%d, drv inst%d"),
+ disk_number, sd_instances[disk_number-1], 0);
+ kstat_close(kc);
+ return (-1);
+ }
+ disk_data = KSTAT_NAMED_PTR(ksp_disk);
+ /*
+ * if disk_data[].value is >0, we have a problem
+ */
+ if (disk_data[1].value.ui32 == 0) {
+ kstat_close(kc);
+ return (0);
+ } else {
+ kstat_close(kc);
+ return (1);
+ }
+}
+
+
+void
+prtdiag_devinfo(void)
+{
+ uint_t flag;
+ /* lets get everything we can from kernel */
+ flag = DINFOSUBTREE|DINFOPROP;
+ rootnode = di_init("/", flag);
+ if (rootnode == DI_NODE_NIL) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nprtdiag_devinfo: di_init() failed"), 0);
+ return;
+ }
+ (void) di_walk_node(rootnode, DI_WALK_CLDFIRST, NULL,
+ dump_devs);
+}
+
+
+/*
+ * gather information about this node, returns appropriate code.
+ * specific information we seek are driver names, instances
+ * we will initialize some globals depending on what we find
+ * from the kernel device tree info and may be private data
+ * if required
+ */
+/*ARGSUSED1*/
+int
+dump_devs(di_node_t node, void *arg)
+{
+ char *driver_name;
+
+ driver_name = di_driver_name(node);
+ /* we will initialize our globals here */
+ if ((di_instance(node) >= 0) &&
+ (driver_name != NULL) &&
+ (!(di_state(node) & DI_DRIVER_DETACHED))) {
+ if (strcmp(driver_name, "pcf8574") == 0) {
+ gpio_instances[gpio_count] = di_instance(node);
+ gpio_count++;
+ } else if (strcmp(driver_name, "sd") == 0) {
+ sd_instances[sd_count] = di_instance(node);
+ sd_count++;
+ } else if (strcmp(driver_name, "st") == 0) {
+ st_instance = di_instance(node);
+ }
+ }
+
+ if (strcmp(di_node_name(node), "pseudo") == 0)
+ return (DI_WALK_PRUNECHILD);
+ else
+ return (DI_WALK_CONTINUE);
+}
+
+
+
+/*
+ * Returns 0 if error , 1 otherwise
+ */
+int
+dump_prop_list(char *name, di_node_t node, di_prop_t (*nxtprop)())
+{
+ int prop_len, i, k, max_slots_minus_cpu, n;
+ uchar_t *prop_data;
+ char *p;
+ char *temp_s;
+ di_prop_t prop, next;
+ int ret_value = 0;
+
+ max_slots_minus_cpu = scsb_ks_topo.max_units[SLOT]-1;
+
+ if ((next = nxtprop(node, DI_PROP_NIL)) == DI_PROP_NIL)
+ return (0);
+ while (next != DI_PROP_NIL) {
+ int maybe_str = 1, npossible_strs = 0;
+ prop = next;
+ next = nxtprop(node, prop);
+ /*
+ * get prop length and value:
+ * private interface--always success
+ */
+ prop_len = di_prop_rawdata(prop, &prop_data);
+ if (di_prop_type(prop) == DDI_PROP_UNDEF_IT) {
+ continue;
+ }
+
+ if (prop_len == 0) {
+ continue;
+ }
+ if (prop_data[prop_len - 1] != '\0') {
+ maybe_str = 0;
+ } else {
+ /*
+ * Every character must be a string character or a \0,
+ * and there must not be two \0's in a row.
+ */
+ for (i = 0; i < prop_len; i++) {
+ if (prop_data[i] == '\0') {
+ npossible_strs++;
+ } else if (!isascii(prop_data[i]) ||
+ iscntrl(prop_data[i])) {
+ maybe_str = 0;
+ break;
+ }
+
+ if ((i > 0) && (prop_data[i] == '\0') &&
+ (prop_data[i - 1] == '\0')) {
+ maybe_str = 0;
+ break;
+ }
+ }
+ }
+
+ if (maybe_str) {
+ p = (char *)prop_data;
+ for (i = 0; i < npossible_strs - 1; i++) {
+ if ((strcmp(name, SYSSOFT_PROP) == 0) &&
+ (strcmp(di_prop_name(prop),
+ HSC_PROP_NAME) == 0)) {
+ temp_s = p;
+ temp_s += strlen(temp_s) + 1;
+ }
+ p += strlen(p) + 1;
+ }
+
+ if ((strcmp(name, SYSSOFT_PROP) == 0) &&
+ (strcmp(di_prop_name(prop), HSC_PROP_NAME) == 0)) {
+ temp_s = temp_s - prop_len+2;
+ for (k = 0, n = 0; k < prop_len; k++) {
+ if (temp_s[k] == 0) {
+ n++;
+ }
+ }
+ if (n % 4) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nbad slot-table(%d)\n"), n);
+ slot_table_not_found = 0;
+ return (ret_value);
+ }
+ slot_table_size = n / 4;
+ /*
+ * NOTE : We save slot table info in order
+ */
+ for (k = 0; k < slot_table_size; k++) {
+ char *nexus, *pcidev, *phys_slotname;
+ char *ga;
+ /*
+ * Pick off pointer to nexus
+ * path or PROM handle
+ */
+ nexus = temp_s;
+ while (*temp_s != NULL)
+ temp_s++;
+ temp_s++;
+
+ /*
+ * Pick off pointer to the
+ * pci device number
+ */
+ pcidev = temp_s;
+ while (*temp_s != NULL)
+ temp_s++;
+ temp_s++;
+
+ /* Pick off physical slot no */
+ phys_slotname = temp_s;
+ while (*temp_s != NULL)
+ temp_s++;
+ temp_s++;
+
+ /*
+ * Pick off GA bits which
+ * we dont use for now.
+ */
+ ga = temp_s;
+ while (*temp_s != NULL)
+ temp_s++;
+ temp_s++;
+
+ hotswap_slot_table[k].pslotnum
+ = atoi(phys_slotname);
+ hotswap_slot_table[k].ga = atoi(ga);
+ hotswap_slot_table[k].pci_devno
+ = atoi(pcidev);
+ strcpy(hotswap_slot_table[k].nexus,
+ nexus);
+ } /* for (k = 0; k < slot_table_size; k++) */
+
+ ret_value = 1;
+ } else /* (strcmp(name, SYSSOFT_PROP) */
+ slot_table_not_found = 1;
+
+ /*
+ * now we want to save off the info
+ * we would use later
+ */
+ if ((strcmp(name, DRV_PROP) == 0) &&
+ (strcmp(di_prop_name(prop), HSC_MODE) == 0)) {
+ hotswap_mode = p;
+ ret_value = 1;
+ } else if ((strcmp(name, DRV_PROP) == 0) &&
+ (strcmp(di_prop_name(prop), HSC_MODE) != 0)) {
+ /* save it in order in the right index */
+ slot_auto_config[max_slots_minus_cpu] = p;
+ max_slots_minus_cpu--;
+ ret_value = 1;
+ }
+
+ } else {
+ for (i = 0; i < prop_len; ++i) {
+#if 0
+ unsigned char byte;
+ byte = (unsigned char)prop_data[i];
+ log_printf("%2.2x", byte, 0);
+#endif
+ }
+ }
+ }
+ return (ret_value);
+}
+
+
+void
+display_mc_prtdiag_info()
+{
+ int i, index;
+ int s_index, i1;
+ int tg_cpu_index = 0;
+ char *mcfru_type, *status, *mc_ok_led, *mc_nok_led;
+ char *misc_info, *health, *board_type;
+
+ log_printf("===============================", 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ " FRU Information ================================\n"), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "FRU FRU FRU Green Amber"), 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Miscellaneous\n"), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Type Unit# Present LED LED"), 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Information\n"), 0);
+
+ log_printf("---------- ----- ------- ----- -----", 0);
+ log_printf(" ----------------------------------\n", 0);
+
+ if (scsb_ks_topo.mid_plane.fru_id == SCTRL_MPID_HALF)
+ misc_info = "Netra ct800";
+ else {
+ misc_info = "Netra ct400";
+ }
+ mcfru_type = prtdiag_fru_types[MIDPLANE];
+ switch (scsb_ks_topo.mid_plane.fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA; break;
+ default:
+ status = NA; break;
+ }
+ mc_ok_led = " ";
+ mc_nok_led = " ";
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s %-5s %s\n"),
+ mcfru_type, scsb_ks_topo.mid_plane.fru_unit,
+ status, mc_ok_led, mc_nok_led,
+ misc_info, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%49sVersion=%d\n"), BLANK,
+ scsb_ks_topo.mid_plane.fru_version, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%49sMaximum Slots=%d\n"), BLANK,
+ scsb_ks_topo.max_units[SLOT], 0);
+
+ /* SCB & SSB */
+ mcfru_type = prtdiag_fru_types[SCB];
+ for (i = 0; i < scsb_ks_topo.max_units[SCB]; ++i) {
+ misc_info = "System Controller Board";
+ if (version_p15_and_p20) {
+ mc_ok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[1]
+ & 0xff), SCB_OK_BIT) ? BLINK :
+ (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[1]
+ & 0xff), SCB_OK_BIT) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[1]
+ & 0xff), SCB_OK_BIT) ? ON:OFF;
+ } else {
+ /*
+ * support for 1.0 systems -
+ * Hack! - should use tables ?
+ */
+ mc_ok_led =
+ (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2]
+ & 0xff), 0) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2]
+ & 0xff), 0) ? ON:OFF;
+ }
+ switch (scsb_ks_topo.mct_scb[i].fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA;
+ break;
+ default:
+ status = NA;
+ break;
+ }
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s %-5s %s\n"),
+ mcfru_type, scsb_ks_topo.mct_scb[i].fru_unit,
+ status, mc_ok_led, mc_nok_led, misc_info, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%46s%s\n"), BLANK, PROPS, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%49sVersion=%d\n"), BLANK,
+ scsb_ks_topo.mct_scb[0].fru_version, 0);
+ if (fail_drv_prop == 1)
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49s%s=%s\n"), BLANK, HSC_MODE,
+ hotswap_mode, 0);
+ } /* for */
+
+ mcfru_type = prtdiag_fru_types[SSB];
+ for (i = 0; i < scsb_ks_topo.max_units[SSB]; ++i) {
+ misc_info = "System Status Panel";
+ switch (scsb_ks_topo.mct_ssb[i].fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA;
+ break;
+ default:
+ status = NA;
+ break;
+ }
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s %-5s %s\n"),
+ mcfru_type, scsb_ks_topo.mct_ssb[i].fru_unit,
+ status, BLANK, BLANK, misc_info, 0);
+ } /* for */
+
+ /* Slots */
+ for (i = 0; i < scsb_ks_topo.max_units[SLOT]; ++i) {
+ if (montecarlo) {
+ if (scsb_ks_topo.mct_slots[i].fru_unit == 1)
+ mcfru_type = prtdiag_fru_types[1];
+ else
+ mcfru_type = prtdiag_fru_types[SLOT];
+ /*
+ * Another way this could have been done is,
+ * to read the sub system id
+ * it is 0x6722 for Alarm Card
+ * but this id is only valid for the new ACs
+ * older ACs still have the same susbsystem
+ * id as most other Sun PCI cards
+ * We cannot completely rely on this.
+ * Also,it turns out that Sun OpenBoot does not
+ * always follow IEEE 1275 std, hence in a few
+ * systems, the "subsystem-id" published by the
+ * PROM could not be found
+ * We know the AC slot# if present on both MC&Tg
+ * Hence we check on both - now we are sure
+ * that we have found an AC
+ */
+ if ((scsb_ks_topo.mct_slots[i].fru_unit == 8) &&
+ (alarm_card_present == 1))
+ board_type = AC_CARD;
+ else
+ board_type = UK;
+ } else {
+ if (scsb_ks_topo.mct_slots[i].fru_unit == 3)
+ mcfru_type = prtdiag_fru_types[1];
+ else
+ mcfru_type = prtdiag_fru_types[SLOT];
+ /*
+ * Another way this could have been done is,
+ * to read the sub system id
+ * it is 0x6722 for Alarm Card
+ * but this id is only valid for the new ACs
+ * older ACs still have the same susbsystem
+ * id as most other Sun PCI cards
+ * We cannot completely rely on this.
+ * Also,it turns out that Sun OpenBoot does not
+ * always follow IEEE 1275 std, hence in a few
+ * systems, the "subsystem-id" published by the
+ * PROM could not be found
+ * We know the AC slot# if present on both MC&Tg
+ * Hence we check on both - now we are sure
+ * that we have found an AC
+ */
+ if ((scsb_ks_topo.mct_slots[i].fru_unit == 1) &&
+ (alarm_card_present == 1))
+ board_type = AC_CARD;
+ else
+ board_type = UK;
+ }
+ if (version_p15_and_p20) {
+ mc_ok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[0]
+ & 0xff), i) ? BLINK :
+ (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[0]
+ & 0xff), i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[0]
+ & 0xff), i) ? ON:OFF;
+ } else {
+ /*
+ * support for 1.0 systems -
+ * Hack! - should use tables ?
+ */
+ if (scsb_ks_topo.mct_slots[i].fru_unit == 7) {
+ mc_ok_led =
+ BIT_TEST(
+ (scsb_ks_leddata.leds.p10.blink_leds[1]
+ & 0xff), 0) ? BLINK :
+ (BIT_TEST(
+ (scsb_ks_leddata.leds.p10.ok_leds[1]
+ & 0xff), 0) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST(
+ (scsb_ks_leddata.leds.p10.nok_leds[1]
+ & 0xff), 0) ? ON:OFF;
+ } else if (scsb_ks_topo.mct_slots[i].fru_unit == 8) {
+ mc_ok_led =
+ BIT_TEST(
+ (scsb_ks_leddata.leds.p10.blink_leds[1]
+ & 0xff), 1) ? BLINK :
+ (BIT_TEST(
+ (scsb_ks_leddata.leds.p10.ok_leds[1]
+ & 0xff), 1) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST(
+ (scsb_ks_leddata.leds.p10.nok_leds[1]
+ & 0xff), 1) ? ON:OFF;
+ } else {
+ /*
+ * for all other slots offset,
+ * index are the same
+ */
+ mc_ok_led =
+ BIT_TEST(
+ (scsb_ks_leddata.leds.p10.blink_leds[0]
+ & 0xff), i) ? BLINK :
+ (BIT_TEST(
+ (scsb_ks_leddata.leds.p10.ok_leds[0]
+ & 0xff), i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST(
+ (scsb_ks_leddata.leds.p10.nok_leds[0]
+ & 0xff), i) ? ON:OFF;
+ }
+
+ } /* else if (!version_p15_and_p20) */
+
+ switch (scsb_ks_topo.mct_slots[i].fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA;
+ break;
+ default:
+ status = NA;
+ break;
+ }
+
+ index = (int)scsb_ks_topo.mct_slots[i].fru_type;
+ if (montecarlo) {
+ if (scsb_ks_topo.mct_slots[i].fru_unit == 1) {
+ /* cpu slot */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s "),
+ mcfru_type,
+ scsb_ks_topo.mct_slots[i].fru_unit,
+ status, mc_ok_led, mc_nok_led, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"),
+ mc_nok_led,
+ slot_occupants[index], 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49stemperature(celsius):%d\n"),
+ BLANK,
+ pcf8591_ks_temp.value, 0);
+#ifdef NEVER
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sminimum temperature:%d\n"),
+ BLANK,
+ pcf8591_ks_temp.min, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49swarning temp. threshold:%d\n"),
+ BLANK,
+ pcf8591_ks_temp.warning_threshold, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sshutdown temp.threshold:%d\n"),
+ BLANK,
+ pcf8591_ks_temp.shutdown_threshold, 0);
+#endif /* NEVER */
+ } else if ((scsb_ks_topo.mct_slots[i].fru_unit == 2) &&
+ (cpu_ftm_present == 1)) {
+ /* CFTM slot */
+ /*
+ * The CFTM can only be present in Slot 2
+ * for Netract-800, for Netract-400 the FTM
+ * is not sitted in a Slot. Hence, this is
+ * another special case and we need to handle
+ * this differently than other slots
+ */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s "),
+ mcfru_type,
+ scsb_ks_topo.mct_slots[i].fru_unit,
+ status, mc_ok_led, mc_nok_led, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"),
+ mc_nok_led,
+ CPU_FTM, 0);
+ } else {
+ if (fail_drv_prop == 1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s "),
+ mcfru_type,
+ scsb_ks_topo.mct_slots[i].fru_unit,
+ status, mc_ok_led, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%-5s %s\n"),
+ mc_nok_led,
+ slot_occupants[index], 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%46s%s\n"), BLANK,
+ PROPS, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sauto-config=%s\n"),
+ BLANK,
+ slot_auto_config[i], 0);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s "),
+ mcfru_type,
+ scsb_ks_topo.mct_slots[i].fru_unit,
+ status, mc_ok_led, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"),
+ mc_nok_led,
+ slot_occupants[index], 0);
+ }
+ }
+ } else { /* tonga */
+ if (scsb_ks_topo.mct_slots[i].fru_unit == 3) {
+ /* cpu slot */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s "),
+ mcfru_type,
+ scsb_ks_topo.mct_slots[i].fru_unit,
+ status, mc_ok_led, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"),
+ mc_nok_led,
+ slot_occupants[index], 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49stemperature(celsius):%d\n"),
+ BLANK,
+ pcf8591_ks_temp.value, 0);
+#ifdef NEVER
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sminimum temperature:%d\n"),
+ BLANK,
+ pcf8591_ks_temp.min, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49swarning temp. threshold:%d\n"),
+ BLANK,
+ pcf8591_ks_temp.warning_threshold, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sshutdown temp. threshold:%d\n"),
+ BLANK,
+ pcf8591_ks_temp.shutdown_threshold, 0);
+#endif /* NEVER */
+ } else {
+ if (fail_drv_prop == 1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s "),
+ mcfru_type,
+ scsb_ks_topo.mct_slots[i].fru_unit,
+ status, mc_ok_led, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%-5s %s\n"),
+ mc_nok_led,
+ slot_occupants[index], 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%46s%s\n"), BLANK, PROPS, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sauto-config=%s\n"),
+ BLANK,
+ slot_auto_config[tg_cpu_index+1],
+ 0);
+ if (scsb_ks_topo.mct_slots[i].fru_unit
+ != 3)
+ tg_cpu_index++;
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s "),
+ mcfru_type,
+ scsb_ks_topo.mct_slots[i].fru_unit,
+ status, mc_ok_led, 0);
+ log_printf(dgettext(TEXT_DOMAIN, "%-5s %s\n"),
+ mc_nok_led,
+ slot_occupants[index], 0);
+ }
+ }
+ }
+ /* we first match the correct slot numbers */
+ for (s_index = 0; s_index < slot_table_size; s_index++) {
+ if (slot_table_not_found == 1) {
+ /* use prom table */
+ if (scsb_ks_topo.mct_slots[i].fru_unit ==
+ prom_slot_table[s_index].pslotnum) {
+ /*
+ * search for the addr/pci num
+ * in all slot info structs
+ */
+ for (i1 = 0; i1 < slot_index;
+ i1++) {
+ if (prom_slot_table[s_index].pci_devno ==
+ mc_slots_data.mc_slot_info[i1].slot_addr) {
+ int nd;
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%46s%s%s\n"), BLANK,
+ BOARDTYPE, board_type, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%46s%s\n"), BLANK, DEVS, 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49s%s\n"), BLANK,
+ PCI_ROOT_AP, 0);
+ for (nd = 0;
+ nd < mc_slots_data.mc_slot_info[i1].number_devs;
+ nd++) {
+ log_printf(dgettext(TEXT_DOMAIN, "%52s%s\n"), BLANK,
+ mc_slots_data.mc_slot_info[i1].devs_info[nd],
+ 0);
+ } /* for */
+
+ } /* if */
+
+ } /* for(i1) */
+
+ } /* if */
+
+ } else {
+ /* use solaris lot table */
+ if (fail_syssoft_prop == 1) {
+ if (scsb_ks_topo.mct_slots[i].fru_unit ==
+ hotswap_slot_table[s_index].pslotnum) {
+ /*
+ * search for the addr/pci
+ * num in all slot info structs
+ */
+ for (i1 = 0; i1 < slot_index; i1++) {
+ if (hotswap_slot_table[s_index].pci_devno ==
+ mc_slots_data.mc_slot_info[i1].slot_addr) {
+ int nd;
+ for (nd = 0;
+ nd < mc_slots_data.mc_slot_info[i1].number_devs;
+ nd++) {
+ log_printf(dgettext(TEXT_DOMAIN, "%49s%s\n"), BLANK,
+ mc_slots_data.mc_slot_info[i1].devs_info[nd],
+ 0);
+ }
+ } /* if */
+
+ } /* for(i1) */
+
+ } /* if */
+
+ } /* (fail_syssoft_prop == 1) */
+
+ } /* (slot_table_not_found == 1) */
+
+ } /* for(s_index) */
+
+ } /* for */
+ mcfru_type = "PDU";
+ misc_info = "Power Distribution Unit";
+ for (i = 0; i < scsb_ks_topo.max_units[PDU]; ++i) {
+ if (version_p15_and_p20) {
+ mc_ok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[1]
+ & 0xff), PDU1_OK_BIT+i*2) ? BLINK :
+ (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[1]
+ & 0xff), PDU1_OK_BIT+i*2) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[1]
+ & 0xff), PDU1_OK_BIT+i*2) ? ON:OFF;
+ }
+ switch (scsb_ks_topo.mct_pdu[i].fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA;
+ break;
+ default:
+ status = NA;
+ break;
+ }
+ if (version_p15_and_p20) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%-10s %-5d %-7s %-5s %-5s %s\n"),
+ mcfru_type, scsb_ks_topo.mct_pdu[i].fru_unit,
+ status, mc_ok_led, mc_nok_led, misc_info, 0);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%-10s %-5d %-7s%18s%s\n"),
+ mcfru_type, scsb_ks_topo.mct_pdu[i].fru_unit,
+ status, BLANK, misc_info, 0);
+ }
+ } /* for */
+
+ /* PS */
+ mcfru_type = prtdiag_fru_types[PS];
+ misc_info = "Power Supply Unit";
+ for (i = 0; i < scsb_ks_topo.max_units[PS]; ++i) {
+ if (version_p15_and_p20) {
+ mc_ok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[2]
+ & 0xff), PS1_OK_BIT+i) ? BLINK :
+ (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2]
+ & 0xff), PS1_OK_BIT+i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2]
+ & 0xff), PS1_OK_BIT+i) ? ON:OFF;
+ } else {
+ /*
+ * support for 1.0 systems -
+ * Hack! - should use tables ?
+ */
+ mc_ok_led =
+ (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2]
+ & 0xff), 1+i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2]
+ & 0xff), 1+i) ? ON:OFF;
+ }
+ switch (scsb_ks_topo.mct_ps[i].fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA;
+ break;
+ default:
+ status = NA;
+ break;
+ }
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s %-5s %s\n"),
+ mcfru_type, scsb_ks_topo.mct_ps[i].fru_unit,
+ status, mc_ok_led, mc_nok_led,
+ misc_info, 0);
+ if (scsb_ks_topo.mct_ps[i].fru_status == FRU_PRESENT) {
+ if (scsb_ks_topo.mct_ps[i].fru_unit == 1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49scondition:%s\n"), BLANK,
+ ((pcf8574_ks_ps1.ps_ok)? NOK:OK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49stemperature:%s\n"), BLANK,
+ ((pcf8574_ks_ps1.temp_ok)? NOK:OK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sps fan:%s\n"), BLANK,
+ ((pcf8574_ks_ps1.psfan_ok)? NOK:OK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49ssupply:%s\n"), BLANK,
+ ((pcf8574_ks_ps1.on_state)? OFF:ON), 0);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49scondition:%s\n"), BLANK,
+ ((pcf8574_ks_ps2.ps_ok)? NOK:OK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49stemperature:%s\n"), BLANK,
+ ((pcf8574_ks_ps2.temp_ok)? NOK:OK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sps fan:%s\n"), BLANK,
+ ((pcf8574_ks_ps2.psfan_ok)? NOK:OK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49ssupply:%s\n"), BLANK,
+ ((pcf8574_ks_ps2.on_state)? OFF:ON), 0);
+ } /* if */
+ }
+
+ } /* for */
+
+ /* Fan tray */
+ mcfru_type = prtdiag_fru_types[FAN];
+ misc_info = "Fan Tray";
+ for (i = 0; i < scsb_ks_topo.max_units[FAN]; ++i) {
+ if (version_p15_and_p20) {
+ mc_ok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.blink_leds[2]
+ & 0xff), FAN1_OK_BIT+i) ? BLINK :
+ (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2]
+ & 0xff), FAN1_OK_BIT+i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2]
+ & 0xff), FAN1_OK_BIT+i) ? ON:OFF;
+ } else {
+ /*
+ * support for 1.0 systems -
+ * Hack! - should use tables ?
+ */
+ mc_ok_led =
+ (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[3]
+ & 0xff), 3+i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[3]
+ & 0xff), 3+i) ? ON:OFF;
+ }
+ switch (scsb_ks_topo.mct_fan[i].fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA;
+ break;
+ default:
+ status = NA;
+ break;
+ }
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s %-5s %s\n"),
+ mcfru_type, scsb_ks_topo.mct_fan[i].fru_unit,
+ status, mc_ok_led, mc_nok_led,
+ misc_info, 0);
+ if (scsb_ks_topo.mct_fan[i].fru_status == FRU_PRESENT) {
+ if (scsb_ks_topo.mct_fan[i].fru_unit == 1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49scondition:%s\n"), BLANK,
+ ((pcf8574_ks_fant1.fan_ok)? OK:NOK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sfan speed:%s\n"), BLANK,
+ ((pcf8574_ks_fant1.fanspeed)? HI:LO), 0);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49scondition:%s\n"), BLANK,
+ ((pcf8574_ks_fant2.fan_ok)? OK:NOK), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49sfan speed:%s\n"), BLANK,
+ ((pcf8574_ks_fant2.fanspeed)? HI:LO), 0);
+ }
+ }
+
+ } /* for */
+
+ /* DISKS */
+ for (i = 0; i < scsb_ks_topo.max_units[DISK]; ++i) {
+ if (scsb_ks_topo.mct_disk[i].fru_unit != RMM_NUMBER)
+ mcfru_type = prtdiag_fru_types[DISK];
+ else
+ mcfru_type = "RMM ";
+ switch (scsb_ks_topo.mct_disk[i].fru_status) {
+ case FRU_PRESENT:
+ status = YES;
+ break;
+ case FRU_NOT_PRESENT:
+ status = NO;
+ break;
+ case FRU_NOT_AVAILABLE:
+ status = NA;
+ break;
+ default:
+ status = NA;
+ break;
+ }
+ if (version_p15_and_p20) {
+ mc_ok_led =
+ BIT_TEST((scsb_ks_leddata.scb_led_regs[8]
+ & 0xff), DISK1_OK_BIT+i) ? BLINK :
+ (BIT_TEST((scsb_ks_leddata.leds.p15.ok_leds[2]
+ & 0xff), DISK1_OK_BIT+i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p15.nok_leds[2]
+ & 0xff), DISK1_OK_BIT+i) ? ON:OFF;
+ } else {
+ /*
+ * support for 1.0 systems -
+ * Hack! - should use tables ?
+ */
+ mc_ok_led =
+ (BIT_TEST((scsb_ks_leddata.leds.p10.ok_leds[2]
+ & 0xff), DISK1_OK_BIT+i) ? ON:OFF);
+ mc_nok_led =
+ BIT_TEST((scsb_ks_leddata.leds.p10.nok_leds[2]
+ & 0xff), DISK1_OK_BIT+i) ? ON:OFF;
+ }
+ /* print everything except condition */
+ if (scsb_ks_topo.mct_disk[i].fru_unit != RMM_NUMBER) {
+ misc_info = "Hard Disk Drive";
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %-5d %-7s %-5s %-5s %s\n"),
+ mcfru_type, scsb_ks_topo.mct_disk[i].fru_unit-1,
+ status, mc_ok_led, mc_nok_led, misc_info, 0);
+ } else {
+ misc_info = "Removable Media Module";
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%10s %5s %-7s %-5s %-5s %s\n"),
+ mcfru_type, BLANK,
+ status, mc_ok_led, mc_nok_led, misc_info, 0);
+ }
+
+ /* find out fru health from the SCSI drivers */
+ if (scsb_ks_topo.mct_disk[i].fru_status == FRU_PRESENT) {
+ switch (
+ scsi_disk_status(
+ scsb_ks_topo.mct_disk[i].fru_unit)) {
+ case 0:
+ health = OK;
+ break;
+ case 1:
+ health = NOK;
+ break;
+ case -1:
+ health = UK;
+ break;
+ default:
+ health = NA;
+ break;
+ }
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%49scondition:%s\n"), BLANK, health, 0);
+ }
+
+ } /* for */
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n"), 0);
+
+} /* display_mc_prtdiag_info() */
+
+
+void
+analyze_pcipci_siblings(di_node_t node)
+{
+ di_node_t lc_node;
+ /* we will find all the dev info for slots first */
+ lc_node = di_drv_first_node("pci_pci", node);
+ lc_node = di_child_node(lc_node);
+ /* we are at "pci" node now */
+ do {
+ if (di_walk_node(lc_node, DI_WALK_CLDFIRST,
+ NULL, analyze_nodes) != 0) {
+ return;
+ }
+ } while ((lc_node = di_sibling_node(lc_node)) != DI_NODE_NIL);
+
+ /* now we wll gather info on sysctrl */
+ lc_node = di_drv_first_node(SCSB_DEV, node);
+ if (lc_node != DI_NODE_NIL)
+ analyze_nodes(lc_node, "sysctrl");
+} /* analyze_pcipci_siblings(.) */
+
+
+int
+analyze_nodes(di_node_t l_node, void *arg)
+{
+ char *temp;
+ char *name, *pname;
+ di_node_t parent;
+ /*
+ * we will figure out whether the parent node is "pci" type
+ * we will save info only in this case as we only want to
+ * print out the nodes under AP and not others
+ */
+ parent = di_parent_node(l_node);
+ pname = di_node_name(parent);
+ name = di_node_name(l_node);
+ /*
+ * if this is PCI bridge, we know that this is the AP for slots
+ * hence, we will save off the address(to convert to slot mapping)
+ * later, and also we will start saving off slot info struct for
+ * reporting later
+ * we will save the immediate childs of this bridge only
+ */
+ if (strcmp(name, "pci") == 0) {
+ num_devs = 0;
+ if ((temp = di_bus_addr(l_node)) != NULL) {
+ mc_slots_data.mc_slot_info[slot_index].slot_addr
+ = (int)strtol(temp, (char **)NULL, 16);
+ }
+ slot_index++;
+ } else {
+ if (strcmp(pname, "pci") == 0) {
+ if ((mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs])
+ != NULL) {
+ (void) strcat(
+ mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs],
+ name);
+ } else {
+ (void) strcpy(
+ mc_slots_data.mc_slot_info[slot_index-1].devs_info[num_devs],
+ name);
+ } /* if ((mc_slots_data.mc_slot_inf */
+
+ num_devs++;
+ mc_slots_data.mc_slot_info[slot_index-1].number_devs
+ = num_devs;
+ } /* if parent is pci */
+
+ } /* if node is pci */
+ if (arg != NULL) {
+ if (strcmp((char *)arg, "sysctrl") == 0) {
+ if (dump_prop_list("System", l_node,
+ di_prop_sys_next)) {
+ (void) dump_prop_list(NULL, l_node,
+ di_prop_global_next);
+ } else {
+ fail_syssoft_prop =
+ dump_prop_list(SYSSOFT_PROP,
+ l_node, di_prop_global_next);
+ }
+
+ fail_drv_prop =
+ dump_prop_list(DRV_PROP, l_node,
+ di_prop_drv_next);
+ /*
+ * (void) dump_prop_list("Hardware",
+ * l_node, di_prop_hw_next);
+ */
+ /* dump_priv_data(l_node); */
+ }
+ }
+
+ return (0);
+
+} /* analyze_nodes(..) */
+
+
+
+/*
+ * To get the slot information,
+ * The OBP defines the 'slot-table' property. But the OS
+ * can override it with 'hsc-slot-map' property
+ * through the .conf file.
+ * Since the formats are different, 2 different property names
+ * are chosen.
+ * The OBP property format is
+ * <phandle>,<pci-devno>,<phys-slotno>,<ga-bits>
+ * The OS property format is (ga-bits is not used however)
+ * <busnexus-path>,<pci-devno>,<phys-slotno>,<ga-bits>
+ * returns 0 on error, 1 otherwise
+ */
+int
+extract_slot_table_from_obp()
+{
+ if (mc_promopen(O_RDONLY)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\ncannot open openprom device"), 0);
+ return (0);
+ }
+
+ if (mc_next(0) == 0)
+ return (0);
+ mc_walk(mc_next(0));
+
+ if (close(oprom_fd) < 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nclose error on %s"), OPENPROMDEV, 0);
+ return (0);
+ }
+
+ return (1);
+
+} /* extract_slot_table_from_obp() */
+
+
+int
+mc_next(int id)
+{
+ Oppbuf oppbuf;
+ struct openpromio *opp = &(oppbuf.opp);
+
+ bzero(oppbuf.buf, BUFSIZE);
+ opp->oprom_size = MAXVALSIZE;
+ opp->oprom_node = id;
+ if (ioctl(oprom_fd, OPROMNEXT, opp) < 0) {
+ log_printf(dgettext(TEXT_DOMAIN, "\nError OPROMNEXT"), 0);
+ return (0);
+ }
+ return (opp->oprom_node);
+
+} /* mc_next(.) */
+
+
+void
+mc_walk(int id)
+{
+ int curnode;
+ mc_dump_node(id);
+ if (curnode = mc_child(id))
+ mc_walk(curnode);
+ if (curnode = mc_next(id))
+ mc_walk(curnode);
+} /* mc_walk(.) */
+
+int
+mc_child(int id)
+{
+ Oppbuf oppbuf;
+ struct openpromio *opp = &(oppbuf.opp);
+
+ bzero(oppbuf.buf, BUFSIZE);
+ opp->oprom_size = MAXVALSIZE;
+ opp->oprom_node = id;
+ if (ioctl(oprom_fd, OPROMCHILD, opp) < 0) {
+ perror("\nOPROMCHILD");
+ exit(0);
+ }
+ return (opp->oprom_node);
+
+} /* mc_child(.) */
+
+
+/*
+ * Print all properties and values
+ */
+void
+mc_dump_node(int id)
+{
+ int k;
+ Oppbuf oppbuf;
+ hsc_prom_slot_table_t *hpstp;
+ struct openpromio *opp = &(oppbuf.opp);
+
+ /* get first prop by asking for null string */
+ bzero(oppbuf.buf, BUFSIZE);
+ for (;;) {
+ /*
+ * get next property name
+ */
+ opp->oprom_size = MAXNAMESZ;
+
+ if (ioctl(oprom_fd, OPROMNXTPROP, opp) < 0) {
+ perror("\nOPROMNXTPROP");
+ return;
+ }
+ if (opp->oprom_size == 0)
+ break;
+ if (strcmp(opp->oprom_array, "slot-table") == 0) {
+ if (mc_getpropval(opp) || opp->oprom_size
+ == (uint_t)-1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\ndata not available"), 0);
+ return;
+ } else {
+ slot_table_size =
+ opp->oprom_size /
+ sizeof (hsc_prom_slot_table_t);
+ hpstp =
+ (hsc_prom_slot_table_t *)opp->oprom_array;
+ for (k = 0; k < slot_table_size; k++, hpstp++) {
+ prom_slot_table[k].pslotnum =
+ hpstp->pslotnum;
+ prom_slot_table[k].ga =
+ hpstp->ga;
+ prom_slot_table[k].pci_devno =
+ hpstp->pci_devno;
+ prom_slot_table[k].phandle =
+ hpstp->phandle;
+ } /* for (k = 0; k < slot_table_size; k++) */
+
+ }
+ }
+ }
+
+} /* mc_dump_node(.) */
+
+
+int
+mc_getpropval(struct openpromio *opp)
+{
+ opp->oprom_size = MAXVALSIZE;
+ if (ioctl(oprom_fd, OPROMGETPROP, opp) < 0) {
+ log_printf(dgettext(TEXT_DOMAIN, "\nError OPROMGETPROP"), 0);
+ return (1);
+ }
+ return (0);
+
+} /* mc_getpropval(.) */
+
+
+
+/*
+ * This function returns nothing.
+ */
+void
+alarm_card_occupant()
+{
+ int scsb_fd;
+ scsb_ioc_rdwr_t ioc_read;
+ uint8_t new_mode = 0;
+ uint8_t old_mode = 0;
+ uchar_t reg_index;
+
+ if (NULL == scsb_node) {
+ if (check_platform() == -1) {
+ return;
+ }
+ }
+
+ if (version_p15_and_p20 == 1)
+ reg_index = 0xe9; /* config status reg offset on SCB */
+ else
+ reg_index = 0xd7; /* config status reg offset on SCB */
+
+ if ((scsb_fd = open(scsb_node, O_RDONLY)) < 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\n%s open failed"), scsb_node, 0);
+ return;
+ }
+
+ /* save off the old mode */
+ if (scsb_mode(scsb_fd, GET, &old_mode) == 0)
+ return;
+ /* we put scsb in diag mode to read this specific ioctl */
+ new_mode = ENVCTRL_DIAG_MODE;
+ if (scsb_mode(scsb_fd, SET, &new_mode) == 0)
+ return;
+ /* now lets read the config register */
+ if (scsb_ioc_reg_read(scsb_fd, reg_index, &ioc_read, 1) == 0)
+ return;
+ /* restore the original mode */
+ if (scsb_mode(scsb_fd, SET, &old_mode) == 0)
+ return;
+ alarm_card_present = (BIT_TEST(ioc_read.ioc_rbuf[0]&0xff, 0) ? 1:0);
+
+} /* alarm_card_occupant() */
+
+
+/*
+ * This function changes the SCSB mode to the desired one
+ * 1 on sucess, 0 otherwise
+ */
+int
+scsb_mode(int fd, scsb_op_t sop, uint8_t *new_mode)
+{
+ struct strioctl sioc;
+
+ if (sop == GET)
+ sioc.ic_cmd = ENVC_IOC_GETMODE;
+ else
+ sioc.ic_cmd = ENVC_IOC_SETMODE;
+
+ sioc.ic_timout = 0;
+ sioc.ic_len = sizeof (uint8_t);
+ sioc.ic_dp = (char *)new_mode;
+
+
+ if (ioctl(fd, I_STR, &sioc) == -1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nscsb_mode():scsb ioctl() failed"), 0);
+ return (0);
+ }
+ return (1);
+
+} /* scsb_mode(...) */
+
+
+/*
+ * 1 on success, 0 otherwise
+ */
+int
+scsb_ioc_reg_read(int fd, uchar_t index, scsb_ioc_rdwr_t *ioc_rd, int num)
+{
+ struct strioctl sioc;
+ scsb_ioc_rdwr_t *rdwrp;
+
+ rdwrp = ioc_rd;
+ sioc.ic_timout = 0;
+ sioc.ic_len = sizeof (scsb_ioc_rdwr_t);
+ sioc.ic_dp = (char *)rdwrp;
+ /* setup read command before ioctl */
+ sioc.ic_cmd = SCSBIOC_REG_READ;
+ rdwrp->ioc_wlen = 0;
+ rdwrp->ioc_rlen = num;
+ rdwrp->ioc_regindex = index;
+ if (ioctl(fd, I_STR, &sioc) == -1) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "scsb_ioc_reg_read(): scsb ioctl() failed\n"), 0);
+ return (0);
+ }
+ return (1);
+
+} /* scsb_ioc_reg_read(....) */
diff --git a/usr/src/lib/libprtdiag_psr/sparc/ontario/Makefile b/usr/src/lib/libprtdiag_psr/sparc/ontario/Makefile
new file mode 100644
index 0000000000..1b6dc46d24
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/ontario/Makefile
@@ -0,0 +1,92 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/ontario/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= ontario.o erie.o pelton.o
+
+include ../Makefile.com
+
+#
+# Override the PSR_MACH variable to use sun4v libraries
+#
+PSR_MACH=sun4v
+
+IFLAGS += -I ../../../libprtdiag/inc
+IFLAGS += -I$(SRC)/cmd/picl/plugins/inc
+LDLIBS += -lpicl
+
+LINTFLAGS += $(IFLAGS)
+
+PLATFORM=SUNW,Sun-Fire-T200
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib
+
+install: all $(USR_PSM_LIBS) $(LINKED_PRTDIAG_DIRS)
+
+#
+# install rules
+#
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(USR_PSM_LIB_DIR):
+ $(INS.dir.root.sys)
+
+$(LINKED_DIRS): $(USR_PLAT_DIR)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIB_DIRS): $(LINKED_DIRS)
+ -$(INS.dir.root.sys)
+
+$(LINKED_PRTDIAG_DIRS): $(USR_PLAT_DIR)
+ -$(INS.slink6)
+
+#
+# used for message files
+#
+POFILE= libprtdiag_psr_ontari.po
+POFILES= ontari.po
+
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/ontario.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.c b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.c
new file mode 100644
index 0000000000..0c48b15736
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.c
@@ -0,0 +1,546 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.open2solaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Sun4v Platform specific functions.
+ *
+ * called when :
+ * machine_type == erie
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <note.h>
+#include <sys/systeminfo.h>
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+#include <picl.h>
+#include "picldefs.h"
+#include <pdevinfo.h>
+#include <display.h>
+#include <display_sun4v.h>
+#include <libprtdiag.h>
+#include "erie.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+
+
+/*
+ * Add all io picl nodes under pci in io list
+ */
+/* ARGSUSED */
+int
+erie_pci_callback(picl_nodehdl_t pcih, void *args)
+{
+ int err = PICL_SUCCESS;
+ picl_nodehdl_t nodeh;
+ char path[MAXSTRLEN];
+ char parent_path[MAXSTRLEN];
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char name[MAXSTRLEN];
+ char model[MAXSTRLEN];
+ char nac[MAXSTRLEN];
+ char bus_type[MAXSTRLEN];
+ int slot = NO_SLOT;
+
+ /* Get the parent node's path - used to determine bus type of child */
+ err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
+ sizeof (parent_path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ /* Walk through this node's children */
+ err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+
+ /* Get child's class */
+ if ((err = erie_get_class(nodeh, piclclass,
+ sizeof (piclclass))) != PICL_SUCCESS)
+ return (err);
+
+ /* If this node is a pci bus or bridge, get node's sibling */
+ if ((strcmp(piclclass, "pci") == 0 ||
+ (strcmp(piclclass, "pciex") == 0))) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ /*
+ * In order to get certain values, it's necessary
+ * to search the picl tree. If there's a problem
+ * with these searches, we'll return the err
+ */
+ if ((err = erie_get_path(nodeh, path, sizeof (path)))
+ != PICL_SUCCESS)
+ return (err);
+ if ((err = erie_get_name(nodeh, name, sizeof (name)))
+ != PICL_SUCCESS)
+ return (err);
+ if ((err = erie_get_model(nodeh, model, sizeof (model)))
+ != PICL_SUCCESS)
+ return (err);
+ erie_get_bus_type(parent_path, bus_type);
+ slot = erie_get_slot_number(path);
+ erie_get_nac(bus_type, path, slot, name, nac, sizeof (nac));
+
+
+ /* Print out the data */
+
+ /* Print NAC */
+ log_printf("%-11s", nac);
+
+ /* Print IO Type */
+ log_printf("%-6s", bus_type);
+
+ /* Print Slot # */
+ if (slot != NO_SLOT) {
+ log_printf("%5d", slot);
+ log_printf("%46s", path);
+ } else {
+ log_printf("%5s", MOTHERBOARD);
+ log_printf("%46s", path);
+ }
+
+ /* Printf Node Name */
+ log_printf("%26s", name);
+ if (strlen(name) > 30)
+ log_printf(dgettext(TEXT_DOMAIN, "+ "));
+ else
+ log_printf(dgettext(TEXT_DOMAIN, " "));
+
+ /* Print Card Model */
+ log_printf("%-8s", model);
+ if (strlen(model) > 8)
+ log_printf(dgettext(TEXT_DOMAIN, "+"));
+ log_printf("\n");
+
+ /* Grab the next child under parent node and do it again */
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+ }
+ return (PICL_WALK_CONTINUE);
+}
+
+
+/*
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Add all IO ASIC revisions to list
+ */
+/* ARGSUSED */
+int
+erie_hw_rev_callback(picl_nodehdl_t pcih, void *args)
+{
+ int err = PICL_SUCCESS;
+ char path[MAXSTRLEN] = "";
+ char nac[MAXSTRLEN];
+ char *compatible;
+ int32_t revision;
+
+ /* Get path of this device */
+ err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
+ sizeof (path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+ /*
+ * If it's a network dev, then print network info.
+ * Else if it's not a network dev, check for FIRE ASIC
+ * Else return PICL_WALK_CONTINUE
+ */
+ if ((strcmp(path, ERIE_NETWORK_0) == 0) ||
+ (strcmp(path, ERIE_NETWORK_1) == 0)) {
+ (void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD,
+ OPHIR, 0);
+ revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ } else if ((strcmp(path, ERIE_NETWORK_2) == 0) ||
+ (strcmp(path, ERIE_NETWORK_3) == 0)) {
+ (void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD,
+ OPHIR, 1);
+ revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ } else if ((strcmp(path, ERIE_LSI_PATH) == 0)) {
+ (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
+ SAS_SATA_HBA);
+ revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ } else if ((strcmp(path, FIRE0) == 0) || (strcmp(path, FIRE1) == 0)) {
+ (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
+ IOBRIDGE);
+ revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ } else if ((strcmp(path, PCIE_PCIX) == 0) ||
+ (strcmp(path, PCIE_PCIE) == 0)) {
+ (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD,
+ PCI_BRIDGE);
+ revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ } else {
+ return (PICL_WALK_CONTINUE);
+ }
+
+ /* Get first compatible value from picl compatible list */
+ err = erie_get_first_compatible_value(pcih, &compatible);
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ /* Print nacation */
+ log_printf("%-20s", nac);
+
+ /* Print Device Path */
+ log_printf("%41s", path);
+
+ /* Print Compatible # */
+ log_printf("%31s", compatible);
+ free(compatible);
+
+ /* Print Revision */
+ log_printf("%6d", revision);
+ log_printf("\n");
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Local functions
+ */
+
+
+/*
+ * This function returns the first picl compatible value
+ */
+int
+erie_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ char *pval;
+
+ err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE)
+ return (PICL_FAILURE);
+
+ /* get first string from table */
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+}
+
+/*
+ * This function returns the revision of
+ * a device.
+ */
+int64_t
+erie_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int8_t int8v;
+ int16_t int16v;
+ int32_t int32v;
+ int64_t int64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int, uint or byte array prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
+ (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ switch (pinfo.size) {
+ case sizeof (int8_t):
+ err = picl_get_propval(proph, &int8v, sizeof (int8v));
+ *ret = err;
+ return (int8v);
+ case sizeof (int16_t):
+ err = picl_get_propval(proph, &int16v, sizeof (int16v));
+ *ret = err;
+ return (int16v);
+ case sizeof (int32_t):
+ err = picl_get_propval(proph, &int32v, sizeof (int32v));
+ *ret = err;
+ return (int32v);
+ case sizeof (int64_t):
+ err = picl_get_propval(proph, &int64v, sizeof (int64v));
+ *ret = err;
+ return (int64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+/*
+ * This function fills in the bus type for an IO device.
+ * If a device hangs off /pci@7c0/pci@0/pci@8, it's on
+ * the pci-x bus. Otherwise, it's on a pci-e bus.
+ *
+ */
+void
+erie_get_bus_type(char path[], char bus_type[])
+{
+ if (strncmp(path, PCIX_BUS, ERIE_PCIX_COMP) == 0) {
+ (void) strcpy(bus_type, "PCIX");
+ } else {
+ (void) strcpy(bus_type, "PCIE");
+ }
+}
+
+/*
+ * Thie function indicates whether a device is in a pci-e slot
+ * or if it's on the motherboard. There's only one pci-e slot
+ * on erie, everything else is on the motherboard.
+ *
+ */
+int
+erie_get_slot_number(char path[])
+{
+ if (strncmp(path, FIRE0, ERIE_PCIE_COMP) == 0)
+ return (0);
+ return (NO_SLOT);
+}
+
+/*
+ * This function takes a path to one of the on-board
+ * network devices and returns the instance# of that
+ * device.
+ *
+ */
+int
+erie_get_network_instance(char path[])
+{
+
+ if (strncmp(path, ERIE_NETWORK_1, strlen(ERIE_NETWORK_1)) == 0) {
+ return (1);
+ } else if (strncmp(path, ERIE_NETWORK_3, strlen(ERIE_NETWORK_3)) == 0) {
+ return (3);
+ } else if (strncmp(path, ERIE_NETWORK_0, strlen(ERIE_NETWORK_0)) == 0) {
+ return (0);
+ } else if (strncmp(path, ERIE_NETWORK_2, strlen(ERIE_NETWORK_2)) == 0) {
+ return (2);
+ } else {
+ return (-1);
+ }
+}
+
+/*
+ * This function gets the path of a node and
+ * the error code from the picl API
+ *
+ */
+int
+erie_get_path(picl_nodehdl_t nodeh, char path[], int size)
+{
+ int err;
+
+ /* hardware path of this node */
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
+ path, size);
+ return (err);
+}
+
+/*
+ * This function returns assings the string passed in
+ * the value of the picl node's name
+ *
+ */
+int
+erie_get_name(picl_nodehdl_t nodeh, char name[], int size)
+{
+ int err;
+ char *compatible;
+ char binding_name[MAXSTRLEN];
+ char lname[MAXSTRLEN];
+
+ /* Get this node's name */
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &lname, size);
+ if (err == PICL_PROPNOTFOUND) {
+ (void) strcpy(lname, "");
+ err = PICL_SUCCESS;
+ }
+
+ /*
+ * If binding_name is found,
+ * name will be <nodename>-<binding_name>
+ */
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+ &binding_name, sizeof (binding_name));
+ if (err == PICL_SUCCESS) {
+ if (strcmp(lname, binding_name) != 0) {
+ (void) strlcat(lname, "-", MAXSTRLEN);
+ (void) strlcat(lname, binding_name, MAXSTRLEN);
+ }
+ /*
+ * if compatible prop is not found, name will be
+ * <nodename>-<compatible>
+ */
+ } else if (err == PICL_PROPNOTFOUND) {
+ err = erie_get_first_compatible_value(nodeh, &compatible);
+ if (err == PICL_SUCCESS) {
+ (void) strlcat(lname, "-", MAXSTRLEN);
+ (void) strlcat(lname, compatible, MAXSTRLEN);
+ }
+ err = PICL_SUCCESS;
+ } else {
+ return (err);
+ }
+
+ /* The name was created fine, copy it to name var */
+ (void) strcpy(name, lname);
+ return (err);
+}
+
+/*
+ * This functions assigns the string passed in the
+ * the value of the picl node's NAC name.
+ */
+void
+erie_get_nac(char bus_type[], char path[], int slot, char name[], char nac[],
+ int size)
+{
+ int instance;
+
+ /* Figure out NAC name and instance, if onboard network node */
+ if (strncmp(name, NETWORK, NET_COMP_NUM) == 0) {
+ instance = erie_get_network_instance(path);
+ (void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD,
+ "NET", instance);
+ } else if (slot != NO_SLOT) {
+ (void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD, bus_type,
+ slot);
+ } else {
+ (void) snprintf(nac, size, "%s/%s", MOTHERBOARD, bus_type);
+ }
+}
+
+/*
+ * This function copies the node's model into model string
+ *
+ */
+int
+erie_get_model(picl_nodehdl_t nodeh, char model[], int size)
+{
+ int err;
+ char tmp_model[MAXSTRLEN];
+
+ /* Get the model of this node */
+ err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
+ &tmp_model, size);
+ if (err == PICL_PROPNOTFOUND) {
+ (void) strcpy(model, "");
+ err = PICL_SUCCESS;
+ } else {
+ (void) strcpy(model, tmp_model);
+ }
+ return (err);
+}
+
+/*
+ * This function copies the node's class into class string
+ *
+ */
+int
+erie_get_class(picl_nodehdl_t nodeh, char piclclass[], int size)
+{
+ int err;
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, size);
+ return (err);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.h b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.h
new file mode 100644
index 0000000000..e507541f89
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/erie.h
@@ -0,0 +1,115 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Sun4v Platform header file.
+ *
+ * called when :
+ * machine_type == erie
+ *
+ */
+
+#ifndef _ERIE_H
+#define _ERIE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ERIE_PLATFORM "SUNW,Sun-Fire-T1000"
+#define ERIE_PCIE_COMP 8
+#define ERIE_PCIX_COMP 20
+#define NO_SLOT -1
+#define NET_COMP_NUM 3
+#define IOBOARD "IOBD"
+#define MOTHERBOARD "MB"
+#define OPHIR "GBE"
+#define NETWORK "network"
+#define ERIE_NETWORK_0 "/pci@7c0/pci@0/network@4"
+#define ERIE_NETWORK_1 "/pci@7c0/pci@0/network@4,1"
+#define ERIE_NETWORK_2 "/pci@7c0/pci@0/pci@8/network@1"
+#define ERIE_NETWORK_3 "/pci@7c0/pci@0/pci@8/network@1,1"
+#define PCIX_BUS "/pci@7c0/pci@0/pci@8"
+#define PCIE_PCIX "/pci@7c0/pci@0/pci@8"
+#define PCIE_PCIE "/pci@7c0/pci@0"
+#define ERIE_LSI_PATH "/pci@7c0/pci@0/pci@8/scsi@2"
+#define FIRE0 "/pci@780"
+#define FIRE1 "/pci@7c0"
+#define IOBRIDGE "IO-BRIDGE"
+#define PCI_BRIDGE "PCI-BRIDGE"
+#define SAS_SATA_HBA "SAS-SATA-HBA"
+
+
+
+/*
+ * Property names
+ */
+#define OBP_PROP_REG "reg"
+#define OBP_PROP_CLOCK_FREQ "clock-frequency"
+#define OBP_PROP_BOARD_NUM "board#"
+#define OBP_PROP_REVISION_ID "revision-id"
+#define OBP_PROP_VERSION_NUM "version#"
+#define OBP_PROP_BOARD_TYPE "board_type"
+#define OBP_PROP_ECACHE_SIZE "ecache-size"
+#define OBP_PROP_IMPLEMENTATION "implementation#"
+#define OBP_PROP_MASK "mask#"
+#define OBP_PROP_COMPATIBLE "compatible"
+#define OBP_PROP_BANNER_NAME "banner-name"
+#define OBP_PROP_MODEL "model"
+#define OBP_PROP_66MHZ_CAPABLE "66mhz-capable"
+#define OBP_PROP_FBC_REG_ID "fbc_reg_id"
+#define OBP_PROP_VERSION "version"
+#define OBP_PROP_INSTANCE "instance"
+
+/*
+ * Function Headers
+ */
+
+
+/* local functions */
+
+int erie_pci_callback(picl_nodehdl_t pcih, void *args);
+int erie_hw_rev_callback(picl_nodehdl_t pcih, void *args);
+int erie_get_first_compatible_value(picl_nodehdl_t nodeh,
+ char **outbuf);
+int64_t erie_get_int_propval(picl_nodehdl_t modh, char *prop_name,
+ int *ret);
+void erie_get_bus_type(char path[], char bus_type[]);
+void erie_get_nac(char bus_type[], char path[], int s,
+ char name[], char loc[], int size);
+int erie_get_slot_number(char path[]);
+int erie_get_network_instance(char path[]);
+int erie_get_name(picl_nodehdl_t nodeh, char name[], int size);
+int erie_get_model(picl_nodehdl_t nodeh, char model[], int size);
+int erie_get_path(picl_nodehdl_t nodeh, char path[], int size);
+int erie_get_class(picl_nodehdl_t nodeh, char piclclass[], int size);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ERIE_H */
diff --git a/usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.c b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.c
new file mode 100644
index 0000000000..4cbe33a73d
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.c
@@ -0,0 +1,649 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Sun4v Platform specific functions.
+ *
+ * called when :
+ * machine_type == ontario
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <note.h>
+#include <sys/systeminfo.h>
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+#include <picl.h>
+#include "picldefs.h"
+#include <pdevinfo.h>
+#include <display.h>
+#include <display_sun4v.h>
+#include <libprtdiag.h>
+#include "ontario.h"
+#include "erie.h"
+#include "pelton.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime
+ */
+void sun4v_display_pci(picl_nodehdl_t plafh);
+void sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh);
+
+
+/* local functions */
+static void sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh);
+static int ontario_pci_callback(picl_nodehdl_t pcih, void *args);
+static int ontario_get_first_compatible_value(picl_nodehdl_t nodeh,
+ char **outbuf);
+static int64_t ontario_get_int_propval(picl_nodehdl_t modh, char *prop_name,
+ int *ret);
+
+static void
+get_bus_type(char *path, struct io_card *card)
+{
+ if (strncmp(path, PCIX_SLOT0, PCIX_COMP_NUM) == 0) {
+ (void) strcpy(card->bus_type, "PCIX");
+ } else {
+ (void) strcpy(card->bus_type, "PCIE");
+ }
+}
+
+static void
+get_slot_number(char *path, struct io_card *card)
+{
+ if (strncmp(path, PCIE_SLOT0, PCIE_COMP_NUM) == 0) {
+ (void) strcpy(card->slot_str, "0");
+ card->slot = 0;
+ } else if (strncmp(path, PCIE_SLOT1, PCIE_COMP_NUM) == 0) {
+ (void) strcpy(card->slot_str, "1");
+ card->slot = 1;
+ } else if (strncmp(path, PCIE_SLOT2, PCIE_COMP_NUM) == 0) {
+ (void) strcpy(card->slot_str, "2");
+ card->slot = 2;
+ } else if (strncmp(path, PCIX_SLOT1, strlen(PCIX_SLOT1)) == 0) {
+ (void) strcpy(card->slot_str, "PCIX");
+ card->slot = -1;
+ } else if (strncmp(path, PCIX_SLOT0, strlen(PCIX_SLOT0)) == 0) {
+ (void) strcpy(card->slot_str, "PCIX");
+ card->slot = -1;
+ } else {
+ (void) strcpy(card->slot_str, IOBOARD);
+ card->slot = -1;
+ }
+}
+
+static int
+ontario_get_network_instance(char *path)
+{
+ if (strncmp(path, NETWORK_1_PATH, strlen(NETWORK_1_PATH)) == 0) {
+ return (1);
+ } else if (strncmp(path, NETWORK_3_PATH, strlen(NETWORK_3_PATH)) == 0) {
+ return (3);
+ } else if (strncmp(path, NETWORK_0_PATH, strlen(NETWORK_0_PATH)) == 0) {
+ return (0);
+ } else if (strncmp(path, NETWORK_2_PATH, strlen(NETWORK_2_PATH)) == 0) {
+ return (2);
+ } else {
+ return (-1);
+ }
+}
+/*
+ * add all io devices under pci in io list
+ */
+/* ARGSUSED */
+static int
+ontario_pci_callback(picl_nodehdl_t pcih, void *args)
+{
+ int err = PICL_SUCCESS;
+ picl_nodehdl_t nodeh;
+ char path[MAXSTRLEN];
+ char parent_path[MAXSTRLEN];
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char name[MAXSTRLEN];
+ char model[MAXSTRLEN];
+ char *compatible;
+ char binding_name[MAXSTRLEN];
+ struct io_card pci_card;
+ int32_t instance;
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
+ sizeof (parent_path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ /* Walk through the children */
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, "pciex") == 0) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ if (strcmp(piclclass, PICL_CLASS_PCI) == 0) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
+ path, sizeof (path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ (void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
+
+ get_bus_type(parent_path, &pci_card);
+
+ get_slot_number(parent_path, &pci_card);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
+ sizeof (name));
+ if (err == PICL_PROPNOTFOUND)
+ (void) strcpy(name, "");
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Figure NAC name */
+ if ((strcmp(name, NETWORK) == 0) &&
+ (strcmp(pci_card.slot_str, IOBOARD) == 0)) {
+ instance = ontario_get_network_instance(path);
+
+ (void) snprintf(pci_card.status,
+ sizeof (pci_card.status), "%s/%s%d", IOBOARD,
+ "NET", instance);
+ } else {
+ if (pci_card.slot != -1) {
+ (void) snprintf(pci_card.status,
+ sizeof (pci_card.status), "%s/%s%d",
+ IOBOARD, pci_card.bus_type, pci_card.slot);
+ } else {
+ (void) snprintf(pci_card.status,
+ sizeof (pci_card.status), "%s/%s", IOBOARD,
+ pci_card.bus_type);
+ }
+ }
+
+ /*
+ * Get the name of this card. If binding_name is found,
+ * name will be <nodename>-<binding_name>
+ */
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+ &binding_name, sizeof (binding_name));
+ if (err == PICL_PROPNOTFOUND) {
+ /*
+ * if compatible prop is found, name will be
+ * <nodename>-<compatible>
+ */
+ err = ontario_get_first_compatible_value(nodeh,
+ &compatible);
+ if (err == PICL_SUCCESS) {
+ (void) strlcat(name, "-", MAXSTRLEN);
+ (void) strlcat(name, compatible, MAXSTRLEN);
+ free(compatible);
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else if (strcmp(name, binding_name) != 0) {
+ (void) strlcat(name, "-", MAXSTRLEN);
+ (void) strlcat(name, binding_name, MAXSTRLEN);
+ }
+
+ (void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
+
+ /* Get the model of this card */
+
+ err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
+ &model, sizeof (model));
+ if (err == PICL_PROPNOTFOUND)
+ (void) strcpy(model, "");
+ else if (err != PICL_SUCCESS)
+ return (err);
+ (void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
+
+ /* Print NAC name */
+ log_printf("%-11s", pci_card.status);
+ /* Print IO Type */
+ log_printf("%6s", pci_card.bus_type);
+ /* Print Slot # */
+ log_printf("%5s", pci_card.slot_str);
+ /* Print Parent Path */
+ log_printf("%46.45s", pci_card.notes);
+ /* Printf Card Name */
+ if (strlen(pci_card.name) > 24)
+ log_printf("%25.24s+", pci_card.name);
+ else
+ log_printf("%26s", pci_card.name);
+ /* Print Card Model */
+ if (strlen(pci_card.model) > 10)
+ log_printf("%10.9s+", pci_card.model);
+ else
+ log_printf("%10s", pci_card.model);
+ log_printf("\n");
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ }
+
+ return (PICL_WALK_CONTINUE);
+}
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+void
+sun4v_display_pci(picl_nodehdl_t plafh)
+{
+ char platbuf[MAXSTRLEN];
+ char *fmt = "%-11s %-5s %-4s %-45s %-25s %-8s";
+ static int banner = FALSE; /* Have we printed the column headings? */
+
+ if (banner == FALSE) {
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " IO Configuration "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+ log_printf(fmt, "", "IO", "", "", "", "", 0);
+ log_printf("\n", 0);
+ log_printf(fmt, "Location", "Type", "Slot", "Path",
+ "Name", "Model", 0);
+ log_printf("\n");
+ log_printf(fmt, "-----------", "-----", "----",
+ "---------------------------------------------",
+ "-------------------------", "---------", 0);
+ log_printf("\n");
+ banner = TRUE;
+ }
+
+ /* Get platform name, if that fails, use ontario name by default */
+ if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) {
+ (void) strcpy(platbuf, ONTARIO_PLATFORM);
+ }
+
+ /*
+ * Call functions based on appropriate platform
+ */
+ if ((strncmp(platbuf, ONTARIO_PLATFORM,
+ strlen(ONTARIO_PLATFORM))) == 0) {
+ (void) picl_walk_tree_by_class(plafh, "pciex",
+ "pciex", ontario_pci_callback);
+ } else if ((strncmp(platbuf, PELTON_PLATFORM,
+ strlen(PELTON_PLATFORM))) == 0) {
+ (void) picl_walk_tree_by_class(plafh, "pciex",
+ "pciex", pelton_pci_callback);
+ } else {
+ (void) picl_walk_tree_by_class(plafh, "pciex", "pciex",
+ erie_pci_callback);
+ (void) picl_walk_tree_by_class(plafh, "pci", "pci",
+ erie_pci_callback);
+ }
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ */
+
+/* ARGSUSED */
+void
+sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh)
+{
+ /* NOTE(ARGUNUSED(kstats)) */
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is if the user
+ * told us to do logging, and we found a system failure.
+ */
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ /* platform_disp_prom_version(tree); */
+ sun4v_display_hw_revisions(root, plafh);
+ }
+}
+
+/*
+ * local functions
+ */
+/*
+ * add all io devices under pci in io list
+ */
+/* ARGSUSED */
+static int
+ontario_hw_rev_callback(picl_nodehdl_t pcih, void *args)
+{
+ int err = PICL_SUCCESS;
+ char path[MAXSTRLEN] = "";
+ char device_path[MAXSTRLEN];
+ char NAC[MAXSTRLEN];
+ char *compatible;
+ int32_t revision;
+ int device_found;
+
+ device_found = 0;
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
+ sizeof (path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ if ((strcmp(path, NETWORK_0_PATH) == 0) ||
+ (strcmp(path, NETWORK_1_PATH) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
+ 0);
+ revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if ((strcmp(path, NETWORK_2_PATH) == 0) ||
+ (strcmp(path, NETWORK_3_PATH) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
+ 1);
+ revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if ((strcmp(path, FIRE_PATH0) == 0) ||
+ (strcmp(path, FIRE_PATH1) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
+ "IO-BRIDGE");
+ revision = ontario_get_int_propval(pcih, OBP_PROP_VERSION_NUM,
+ &err);
+ }
+
+ if ((strcmp(path, PCIX_SLOT0) == 0) ||
+ (strcmp(path, PCIX_SLOT1) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
+ PCI_BRIDGE);
+ revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if (strcmp(path, SWITCH_A_PATH) == 0) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_A);
+ revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if (strcmp(path, SWITCH_B_PATH) == 0) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_B);
+ revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if (strcmp(path, ONT_LSI_PATH) == 0) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
+ SAS_SATA_HBA);
+ revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+ if (device_found == 1) {
+ (void) strcpy(device_path, path);
+ err = ontario_get_first_compatible_value(pcih, &compatible);
+
+ /* Print NAC name */
+ log_printf("%-20s", NAC);
+ /* Print Device Path */
+ if (strlen(device_path) > 38)
+ log_printf("%38.37s+", device_path);
+ else
+ log_printf("%39s", device_path);
+ /* Print Compatible # */
+ log_printf("%31s", compatible);
+ free(compatible);
+ /* Print Revision */
+ log_printf("%6d", revision);
+ log_printf("\n");
+ }
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*ARGSUSED*/
+static void
+sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh)
+{
+ Prom_node *pnode;
+ char *value;
+ char platbuf[MAXSTRLEN];
+ char *fmt = "%-20s %-40s %-30s %-9s";
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n"
+ "========================= HW Revisions "
+ "=======================================\n\n"));
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System PROM revisions:\n"
+ "----------------------\n"));
+
+ pnode = dev_find_node(root, "openprom");
+ if (pnode != NULL) {
+ value = (char *)get_prop_val(find_prop(pnode, "version"));
+ log_printf(value);
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN, "\n\n"
+ "IO ASIC revisions:\n"
+ "------------------\n"));
+ log_printf(fmt, "Location", "Path", "Device", "Revision\n", 0);
+ log_printf(fmt, "--------------------",
+ "----------------------------------------",
+ "------------------------------",
+ "---------\n", 0);
+
+ /* Get platform name, if that fails, use ontario name by default */
+ if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) {
+ (void) strcpy(platbuf, ONTARIO_PLATFORM);
+ }
+
+ /*
+ * Walk tree based on platform
+ */
+ if ((strncmp(platbuf, ONTARIO_PLATFORM,
+ strlen(ONTARIO_PLATFORM))) == 0) {
+ (void) picl_walk_tree_by_class(plafh, "pciex",
+ "pciex", ontario_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "pci",
+ "pci", ontario_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "network",
+ "network", ontario_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
+ ontario_hw_rev_callback);
+ } else if ((strncmp(platbuf, PELTON_PLATFORM,
+ strlen(PELTON_PLATFORM))) == 0) {
+ (void) picl_walk_tree_by_class(plafh, "pciex",
+ "pciex", pelton_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "pci",
+ "pci", pelton_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "network",
+ "network", pelton_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
+ pelton_hw_rev_callback);
+ } else {
+ (void) picl_walk_tree_by_class(plafh, "pciex", "pciex",
+ erie_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "pci", "pci",
+ erie_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "network", "network",
+ erie_hw_rev_callback);
+ (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2",
+ erie_hw_rev_callback);
+ }
+}
+
+/*
+ * return the first compatible value
+ */
+static int
+ontario_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ char *pval;
+
+ err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE)
+ return (PICL_FAILURE);
+
+ /* get first string from table */
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+}
+
+static int64_t
+ontario_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int8_t int8v;
+ int16_t int16v;
+ int32_t int32v;
+ int64_t int64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int, uint or byte array prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
+ (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ switch (pinfo.size) {
+ case sizeof (int8_t):
+ err = picl_get_propval(proph, &int8v, sizeof (int8v));
+ *ret = err;
+ return (int8v);
+ case sizeof (int16_t):
+ err = picl_get_propval(proph, &int16v, sizeof (int16v));
+ *ret = err;
+ return (int16v);
+ case sizeof (int32_t):
+ err = picl_get_propval(proph, &int32v, sizeof (int32v));
+ *ret = err;
+ return (int32v);
+ case sizeof (int64_t):
+ err = picl_get_propval(proph, &int64v, sizeof (int64v));
+ *ret = err;
+ return (int64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.h b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.h
new file mode 100644
index 0000000000..cfb5646fec
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/ontario.h
@@ -0,0 +1,97 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Sun4v Platform header file.
+ *
+ * called when :
+ * machine_type == Ontario
+ *
+ */
+
+#ifndef _ONTARIO_H
+#define _ONTARIO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ONTARIO_PLATFORM "SUNW,Sun-Fire-T200"
+#define H20_IMPL 0x5678
+#define IS_H20(impl) ((impl) == H20_IMPL)
+#define PCIE_COMP_NUM 20
+#define PCIX_COMP_NUM 20
+#define IOBOARD "IOBD"
+#define MOTHERBOARD "MB"
+#define SWITCH_A "PCI-SWITCH0"
+#define SWITCH_B "PCI-SWITCH1"
+#define PCI_BRIDGE "PCI-BRIDGE"
+#define OPHIR "GBE"
+#define NETWORK "network"
+#define PCIE "/PCIE"
+#define PCIX "/PCIX"
+#define FIRE_PATH0 "/pci@780"
+#define FIRE_PATH1 "/pci@7c0"
+#define SWITCH_A_PATH "/pci@780/pci@0"
+#define SWITCH_B_PATH "/pci@7c0/pci@0"
+#define NETWORK_0_PATH "/pci@780/pci@0/pci@1/network@0"
+#define NETWORK_1_PATH "/pci@780/pci@0/pci@1/network@0,1"
+#define NETWORK_2_PATH "/pci@7c0/pci@0/pci@2/network@0"
+#define NETWORK_3_PATH "/pci@7c0/pci@0/pci@2/network@0,1"
+#define PCIE_SLOT0 "/pci@780/pci@0/pci@8"
+#define PCIE_SLOT1 "/pci@7c0/pci@0/pci@8"
+#define PCIE_SLOT2 "/pci@7c0/pci@0/pci@9"
+#define PCIX_SLOT0 "/pci@7c0/pci@0/pci@1/pci@0,2"
+#define PCIX_SLOT1 "/pci@7c0/pci@0/pci@1/pci@0,2"
+#define ONT_LSI_PATH "/pci@7c0/pci@0/pci@1/pci@0,2/LSILogic,sas@2"
+
+/*
+ * Property names
+ */
+#define OBP_PROP_REG "reg"
+#define OBP_PROP_CLOCK_FREQ "clock-frequency"
+#define OBP_PROP_BOARD_NUM "board#"
+#define OBP_PROP_REVISION_ID "revision-id"
+#define OBP_PROP_VERSION_NUM "version#"
+#define OBP_PROP_BOARD_TYPE "board_type"
+#define OBP_PROP_ECACHE_SIZE "ecache-size"
+#define OBP_PROP_IMPLEMENTATION "implementation#"
+#define OBP_PROP_MASK "mask#"
+#define OBP_PROP_COMPATIBLE "compatible"
+#define OBP_PROP_BANNER_NAME "banner-name"
+#define OBP_PROP_MODEL "model"
+#define OBP_PROP_66MHZ_CAPABLE "66mhz-capable"
+#define OBP_PROP_FBC_REG_ID "fbc_reg_id"
+#define OBP_PROP_VERSION "version"
+#define OBP_PROP_INSTANCE "instance"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ONTARIO_H */
diff --git a/usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.c b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.c
new file mode 100644
index 0000000000..f529dbc375
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.c
@@ -0,0 +1,496 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Sun4v Platform specific functions.
+ *
+ * called when :
+ * machine_type == pelton
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+#include <libintl.h>
+#include <note.h>
+#include <sys/systeminfo.h>
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+#include <picl.h>
+#include "picldefs.h"
+#include <pdevinfo.h>
+#include <display.h>
+#include <display_sun4v.h>
+#include <libprtdiag.h>
+#include "pelton.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+
+/* local functions */
+static int pelton_get_first_compatible_value(picl_nodehdl_t nodeh,
+ char **outbuf);
+static int64_t pelton_get_int_propval(picl_nodehdl_t modh, char *prop_name,
+ int *ret);
+
+static void
+get_bus_type(char *path, struct io_card *card)
+{
+ if (strncmp(path, PEL_PCIX_SLOT0, PCIX_COMP_NUM) == 0) {
+ (void) strcpy(card->bus_type, "PCIX");
+ } else if (strncmp(path, PEL_PCIX_SLOT1, PCIX_COMP_NUM) == 0) {
+ (void) strcpy(card->bus_type, "PCIX");
+ } else if (strncmp(path, PEL_PCIX_SLOT2, PCIX_COMP_NUM) == 0) {
+ (void) strcpy(card->bus_type, "PCIX");
+ } else if (strncmp(path, PEL_PCIX_SLOT3, PCIX_COMP_NUM) == 0) {
+ (void) strcpy(card->bus_type, "PCIX");
+ } else {
+ (void) strcpy(card->bus_type, "PCIE");
+ }
+}
+
+static void
+get_slot_number(char *path, struct io_card *card)
+{
+ if (strncmp(path, PEL_PCIE_SLOT0, PCIE_COMP_NUM) == 0) {
+ (void) strcpy(card->slot_str, "0");
+ card->slot = 0;
+ } else if (strncmp(path, PEL_PCIX_SLOT2, strlen(PEL_PCIX_SLOT2)) == 0) {
+ (void) strcpy(card->slot_str, "PCIX");
+ card->slot = -1;
+ } else if (strncmp(path, PEL_PCIX_SLOT1, strlen(PEL_PCIX_SLOT1)) == 0) {
+ (void) strcpy(card->slot_str, "PCIX");
+ card->slot = -1;
+ } else if (strncmp(path, PEL_PCIX_SLOT0, strlen(PEL_PCIX_SLOT0)) == 0) {
+ (void) strcpy(card->slot_str, "PCIX");
+ card->slot = -1;
+ } else {
+ (void) strcpy(card->slot_str, IOBOARD);
+ card->slot = -1;
+ }
+}
+
+static int
+pelton_get_network_instance(char *path)
+{
+ if (strncmp(path, PEL_NETWORK_1_PATH,
+ strlen(PEL_NETWORK_1_PATH)) == 0) {
+ return (1);
+ } else if (strncmp(path, PEL_NETWORK_3_PATH,
+ strlen(PEL_NETWORK_3_PATH)) == 0) {
+ return (3);
+ } else if (strncmp(path, PEL_NETWORK_0_PATH,
+ strlen(PEL_NETWORK_0_PATH)) == 0) {
+ return (0);
+ } else if (strncmp(path, PEL_NETWORK_2_PATH,
+ strlen(PEL_NETWORK_2_PATH)) == 0) {
+ return (2);
+ } else {
+ return (-1);
+ }
+}
+/*
+ * add all io devices under pci in io list
+ */
+/* ARGSUSED */
+int
+pelton_pci_callback(picl_nodehdl_t pcih, void *args)
+{
+ int err = PICL_SUCCESS;
+ picl_nodehdl_t nodeh;
+ char path[MAXSTRLEN];
+ char parent_path[MAXSTRLEN];
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char name[MAXSTRLEN];
+ char model[MAXSTRLEN];
+ char *compatible;
+ char binding_name[MAXSTRLEN];
+ struct io_card pci_card;
+ int32_t instance;
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path,
+ sizeof (parent_path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ /* Walk through the children */
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, "pciex") == 0) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ if (strcmp(piclclass, PICL_CLASS_PCI) == 0) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH,
+ path, sizeof (path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ (void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes));
+
+ get_bus_type(parent_path, &pci_card);
+
+ get_slot_number(parent_path, &pci_card);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name,
+ sizeof (name));
+ if (err == PICL_PROPNOTFOUND)
+ (void) strcpy(name, "");
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+
+ /* Figure NAC name */
+ if ((strcmp(name, NETWORK) == 0) &&
+ (strcmp(pci_card.slot_str, IOBOARD) == 0)) {
+ instance = pelton_get_network_instance(path);
+
+ (void) snprintf(pci_card.status,
+ sizeof (pci_card.status), "%s/%s%d", IOBOARD,
+ "NET", instance);
+ } else {
+ if (pci_card.slot != -1) {
+ (void) snprintf(pci_card.status,
+ sizeof (pci_card.status), "%s/%s%d",
+ IOBOARD, pci_card.bus_type, pci_card.slot);
+ } else {
+ (void) snprintf(pci_card.status,
+ sizeof (pci_card.status), "%s/%s", IOBOARD,
+ pci_card.bus_type);
+ }
+ }
+
+ /*
+ * Get the name of this card. Iif binding_name is found,
+ * name will be <nodename>-<binding_name>
+ */
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+ &binding_name, sizeof (binding_name));
+ if (err == PICL_PROPNOTFOUND) {
+ /*
+ * if compatible prop is found, name will be
+ * <nodename>-<compatible>
+ */
+ err = pelton_get_first_compatible_value(nodeh,
+ &compatible);
+ if (err == PICL_SUCCESS) {
+ (void) strlcat(name, "-", MAXSTRLEN);
+ (void) strlcat(name, compatible, MAXSTRLEN);
+ free(compatible);
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else if (strcmp(name, binding_name) != 0) {
+ (void) strlcat(name, "-", MAXSTRLEN);
+ (void) strlcat(name, binding_name, MAXSTRLEN);
+ }
+
+ (void) strlcpy(pci_card.name, name, sizeof (pci_card.name));
+ free(name);
+
+ /* Get the model of this card */
+
+ err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL,
+ &model, sizeof (model));
+ if (err == PICL_PROPNOTFOUND)
+ (void) strcpy(model, "");
+ else if (err != PICL_SUCCESS)
+ return (err);
+ (void) strlcpy(pci_card.model, model, sizeof (pci_card.model));
+
+ /* Print NAC name */
+ log_printf("%-11s", pci_card.status);
+ /* Print IO Type */
+ log_printf("%6s", pci_card.bus_type);
+ /* Print Slot # */
+ log_printf("%5s", pci_card.slot_str);
+ /* Print Parent Path */
+ log_printf("%46.45s", pci_card.notes);
+ /* Printf Card Name */
+ if (strlen(pci_card.name) > 24)
+ log_printf("%25.24s+", pci_card.name);
+ else
+ log_printf("%26s", pci_card.name);
+ /* Print Card Model */
+ if (strlen(pci_card.model) > 10)
+ log_printf("%10.9s+", pci_card.model);
+ else
+ log_printf("%10s", pci_card.model);
+ log_printf("\n");
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ }
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * local functions
+ */
+/*
+ * add all io devices under pci in io list
+ */
+/* ARGSUSED */
+int
+pelton_hw_rev_callback(picl_nodehdl_t pcih, void *args)
+{
+ int err = PICL_SUCCESS;
+ char path[MAXSTRLEN] = "";
+ char device_path[MAXSTRLEN];
+ char NAC[MAXSTRLEN];
+ char *compatible;
+ int32_t revision;
+ int device_found;
+
+ device_found = 0;
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path,
+ sizeof (path));
+ if (err != PICL_SUCCESS) {
+ return (err);
+ }
+
+ if ((strcmp(path, PEL_NETWORK_0_PATH) == 0) ||
+ (strcmp(path, PEL_NETWORK_1_PATH) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
+ 0);
+ revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if ((strcmp(path, PEL_NETWORK_2_PATH) == 0) ||
+ (strcmp(path, PEL_NETWORK_3_PATH) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR,
+ 1);
+ revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if ((strcmp(path, FIRE_PATH0) == 0) ||
+ (strcmp(path, FIRE_PATH1) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
+ "IO-BRIDGE");
+ revision = pelton_get_int_propval(pcih, OBP_PROP_VERSION_NUM,
+ &err);
+ }
+
+ if ((strcmp(path, PEL_PCIX_SLOT0) == 0) ||
+ (strcmp(path, PEL_PCIX_SLOT1) == 0) ||
+ (strcmp(path, PEL_PCIX_SLOT2) == 0) ||
+ (strcmp(path, PEL_PCIX_SLOT3) == 0)) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
+ PCI_BRIDGE);
+ revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if (strcmp(path, SWITCH_A_PATH) == 0) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_A);
+ revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if (strcmp(path, SWITCH_B_PATH) == 0) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_B);
+ revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+
+ if (strcmp(path, PEL_LSI_PATH) == 0) {
+ device_found = 1;
+ (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD,
+ PEL_SAS_HBA);
+ revision = pelton_get_int_propval(pcih, OBP_PROP_REVISION_ID,
+ &err);
+ }
+ if (device_found == 1) {
+ (void) strcpy(device_path, path);
+ err = pelton_get_first_compatible_value(pcih, &compatible);
+
+ /* Print NAC name */
+ log_printf("%-20s", NAC);
+ /* Print Device Path */
+ if (strlen(device_path) > 38)
+ log_printf("%38.37s+", device_path);
+ else
+ log_printf("%39s", device_path);
+ /* Print Compatible # */
+ log_printf("%31s", compatible);
+ free(compatible);
+ /* Print Revision */
+ log_printf("%6d", revision);
+ log_printf("\n");
+ }
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * return the first compatible value
+ */
+static int
+pelton_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ char *pval;
+
+ err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE)
+ return (PICL_FAILURE);
+
+ /* get first string from table */
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+}
+
+static int64_t
+pelton_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int8_t int8v;
+ int16_t int16v;
+ int32_t int32v;
+ int64_t int64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int, uint or byte array prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
+ (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ switch (pinfo.size) {
+ case sizeof (int8_t):
+ err = picl_get_propval(proph, &int8v, sizeof (int8v));
+ *ret = err;
+ return (int8v);
+ case sizeof (int16_t):
+ err = picl_get_propval(proph, &int16v, sizeof (int16v));
+ *ret = err;
+ return (int16v);
+ case sizeof (int32_t):
+ err = picl_get_propval(proph, &int32v, sizeof (int32v));
+ *ret = err;
+ return (int32v);
+ case sizeof (int64_t):
+ err = picl_get_propval(proph, &int64v, sizeof (int64v));
+ *ret = err;
+ return (int64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.h b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.h
new file mode 100644
index 0000000000..3951933051
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/ontario/common/pelton.h
@@ -0,0 +1,101 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Sun4v Platform header file.
+ *
+ * called when :
+ * machine_type == Pelton
+ *
+ */
+
+#ifndef _PELTON_H
+#define _PELTON_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PELTON_PLATFORM "SUNW,Netra-T2000"
+#define PCIE_COMP_NUM 20
+#define PCIX_COMP_NUM 20
+#define IOBOARD "IOBD"
+#define MOTHERBOARD "MB"
+#define SWITCH_A "PCI-SWITCH0"
+#define SWITCH_B "PCI-SWITCH1"
+#define PCI_BRIDGE "PCI-BRIDGE"
+#define OPHIR "GBE"
+#define NETWORK "network"
+#define PCIE "/PCIE"
+#define PCIX "/PCIX"
+#define FIRE_PATH0 "/pci@780"
+#define FIRE_PATH1 "/pci@7c0"
+#define SWITCH_A_PATH "/pci@780/pci@0"
+#define SWITCH_B_PATH "/pci@7c0/pci@0"
+#define PEL_NETWORK_0_PATH "/pci@780/pci@0/pci@1/network@0"
+#define PEL_NETWORK_1_PATH "/pci@780/pci@0/pci@1/network@0,1"
+#define PEL_NETWORK_2_PATH "/pci@7c0/pci@0/pci@2/network@0"
+#define PEL_NETWORK_3_PATH "/pci@7c0/pci@0/pci@2/network@0,1"
+#define PEL_PCIE_SLOT0 "/pci@7c0/pci@0/pci@8"
+#define PEL_PCIX_SLOT0 "/pci@780/pci@0/pci@8/pci@0"
+#define PEL_PCIX_SLOT1 "/pci@7c0/pci@0/pci@9/pci@0"
+#define PEL_PCIX_SLOT2 "/pci@7c0/pci@0/pci@9/pci@0,2"
+#define PEL_PCIX_SLOT3 "/pci@7c0/pci@0/pci@1/pci@0"
+#define PEL_LSI_PATH "/pci@780/pci@0/pci@8/pci@0/LSILogic,sas@1"
+#define PEL_SAS_HBA "SAS-SATA-HBA"
+
+/*
+ * Property names
+ */
+#define OBP_PROP_REG "reg"
+#define OBP_PROP_CLOCK_FREQ "clock-frequency"
+#define OBP_PROP_BOARD_NUM "board#"
+#define OBP_PROP_REVISION_ID "revision-id"
+#define OBP_PROP_VERSION_NUM "version#"
+#define OBP_PROP_BOARD_TYPE "board_type"
+#define OBP_PROP_ECACHE_SIZE "ecache-size"
+#define OBP_PROP_IMPLEMENTATION "implementation#"
+#define OBP_PROP_MASK "mask#"
+#define OBP_PROP_COMPATIBLE "compatible"
+#define OBP_PROP_BANNER_NAME "banner-name"
+#define OBP_PROP_MODEL "model"
+#define OBP_PROP_66MHZ_CAPABLE "66mhz-capable"
+#define OBP_PROP_FBC_REG_ID "fbc_reg_id"
+#define OBP_PROP_VERSION "version"
+#define OBP_PROP_INSTANCE "instance"
+
+/*
+ * Function Headers
+ */
+int pelton_pci_callback(picl_nodehdl_t pcih, void *args);
+int pelton_hw_rev_callback(picl_nodehdl_t pcih, void *args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PELTON_H */
diff --git a/usr/src/lib/libprtdiag_psr/sparc/schumacher/Makefile b/usr/src/lib/libprtdiag_psr/sparc/schumacher/Makefile
new file mode 100644
index 0000000000..60290b9370
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/schumacher/Makefile
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/schumacher/Makefile
+
+PRTDIAG_DIRS= picl
+
+all := TARGET= all
+lint := TARGET= lint
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+_msg := TARGET= _msg
+
+.KEEP_STATE:
+
+all lint clean clobber install _msg : $(PRTDIAG_DIRS)
+
+$(PRTDIAG_DIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/schumacher/common/schumacher.c b/usr/src/lib/libprtdiag_psr/sparc/schumacher/common/schumacher.c
new file mode 100644
index 0000000000..d9ec91a3e6
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/schumacher/common/schumacher.c
@@ -0,0 +1,3257 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <alloca.h>
+#include <errno.h>
+#include <libintl.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/openpromio.h>
+#include <sys/ddi.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <locale.h>
+#include <picl.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "display_sun4u.h"
+#include "picldefs.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+#define EM_INIT_FAIL dgettext(TEXT_DOMAIN,\
+ "picl_initialize failed: %s\n")
+#define EM_GET_ROOT_FAIL dgettext(TEXT_DOMAIN,\
+ "Getting root node failed: %s\n")
+#define EM_PRTDIAG_FAIL dgettext(TEXT_DOMAIN, "Prtdiag failed!\n")
+
+#define SIGN_ON_MSG dgettext(TEXT_DOMAIN,\
+ "System Configuration: Sun Microsystems ")
+#define SYSCLK_FREQ_MSG dgettext(TEXT_DOMAIN,\
+ "System clock frequency: %d MHZ\n")
+#define MEM_SIZE_MSG dgettext(TEXT_DOMAIN, "Memory size: ")
+
+#define DEFAULT_BOARD_NUM 0
+#define DEFAULT_PORTID 0
+#define CLK_FREQ_66MHZ 66
+#define USB -1
+#define HUB -2
+
+/* bus id */
+#define PCI_TYPE 1
+
+/*
+ * PICL classes
+ */
+#define PICL_CLASS_OPTIONS "options"
+
+/*
+ * Property names
+ */
+
+#define OBP_PROP_REG "reg"
+#define OBP_PROP_CLOCK_FREQ "clock-frequency"
+#define OBP_PROP_BOARD_NUM "board#"
+#define OBP_PROP_REVISION_ID "revision-id"
+#define OBP_PROP_VERSION_NUM "version#"
+#define OBP_PROP_BOARD_TYPE "board_type"
+#define OBP_PROP_ECACHE_SIZE "ecache-size"
+#define OBP_PROP_IMPLEMENTATION "implementation#"
+#define OBP_PROP_MASK "mask#"
+#define OBP_PROP_COMPATIBLE "compatible"
+#define OBP_PROP_BANNER_NAME "banner-name"
+#define OBP_PROP_MODEL "model"
+#define OBP_PROP_66MHZ_CAPABLE "66mhz-capable"
+#define OBP_PROP_FBC_REG_ID "fbc_reg_id"
+#define OBP_PROP_VERSION "version"
+
+#define PROP_POWERFAIL_TIME "powerfail-time"
+#define PICL_PROP_LOW_WARNING_THRESHOLD "LowWarningThreshold"
+
+#define DEFAULT_LINE_WIDTH 78
+#define HEADING_SYMBOL "="
+
+#define SIZE_FIELD 11
+#define MAX_IWAYS 32
+
+typedef struct bank_list {
+ picl_nodehdl_t nodeh;
+ uint32_t iway_count;
+ uint32_t iway[MAX_IWAYS];
+ struct bank_list *next;
+} bank_list_t;
+
+typedef struct {
+ uint64_t base;
+ uint64_t size;
+ int ifactor;
+ int bank_count;
+} seg_info_t;
+
+static struct io_card *io_card_list = NULL; /* The head of the IO card list */
+static bank_list_t *mem_banks = NULL;
+static int mem_xfersize;
+static int no_xfer_size = 0;
+
+static const char *io_device_table[] = {
+ "block",
+ "disk",
+ "cdrom",
+ "floppy",
+ "tape",
+ "network",
+ "display",
+ "serial",
+ "parallel",
+ "scsi",
+ "scsi-2",
+ "scsi-3",
+ "ide",
+ "fcal",
+ "keyboard",
+ "mouse",
+ "dma"
+};
+
+#define NIODEVICE (sizeof (io_device_table) / sizeof (io_device_table[0]))
+
+static const char *bus_table[] = {
+ "ebus",
+ "isa",
+ "pmu"
+};
+
+#define NBUS (sizeof (bus_table) / sizeof (bus_table[0]))
+
+/*
+ * check if it is an IO deice
+ * return 1 if this is a io device; return 0 for else.
+ */
+static int
+is_io_device(char *device_class)
+{
+ int i;
+
+ for (i = 0; i < NIODEVICE; i++) {
+ if (strcmp(device_class, io_device_table[i]) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * check if it is a bus
+ * return 1 if this is a bus; return 0 for else.
+ */
+static int
+is_bus(char *device_class)
+{
+ int i;
+
+ for (i = 0; i < NBUS; i++) {
+ if (strcmp(device_class, bus_table[i]) == 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * search children to get the node by the nodename
+ * return node handler in picl_nodehdl_t *nodeh
+ */
+static int
+picldiag_get_node_by_name(picl_nodehdl_t rooth, char *name,
+ picl_nodehdl_t *nodeh)
+{
+ picl_nodehdl_t childh;
+ int err;
+ char *nodename;
+
+ nodename = alloca(strlen(name) + 1);
+ if (nodename == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
+ nodename, (strlen(name) + 1));
+ if (err != PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ if (strcmp(nodename, name) == 0) {
+ *nodeh = childh;
+ return (PICL_SUCCESS);
+ }
+
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ return (err);
+}
+
+/*
+ * get the value by the property name of the string prop
+ * the value will be in outbuf
+ * Caller must free the outbuf
+ */
+static int
+picldiag_get_string_propval(picl_nodehdl_t modh, char *prop_name, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ char *prop_value;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If it is not a string prop, return NULL
+ */
+ if (pinfo.type != PICL_PTYPE_CHARSTRING)
+ return (PICL_FAILURE);
+
+ prop_value = malloc(pinfo.size);
+ if (prop_value == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, prop_value, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(prop_value);
+ return (err);
+ }
+
+ *outbuf = prop_value;
+ return (PICL_SUCCESS);
+}
+
+
+/*
+ * return the value as a signed integer
+ */
+
+static int64_t
+picldiag_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int8_t int8v;
+ int16_t int16v;
+ int32_t int32v;
+ int64_t int64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int, uint or byte array prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT) &&
+ (pinfo.type != PICL_PTYPE_BYTEARRAY)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ switch (pinfo.size) {
+ case sizeof (int8_t):
+ err = picl_get_propval(proph, &int8v, sizeof (int8v));
+ *ret = err;
+ return (int8v);
+ case sizeof (int16_t):
+ err = picl_get_propval(proph, &int16v, sizeof (int16v));
+ *ret = err;
+ return (int16v);
+ case sizeof (int32_t):
+ err = picl_get_propval(proph, &int32v, sizeof (int32v));
+ *ret = err;
+ return (int32v);
+ case sizeof (int64_t):
+ err = picl_get_propval(proph, &int64v, sizeof (int64v));
+ *ret = err;
+ return (int64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+/*
+ * return the value of the uint prop
+ */
+static uint64_t
+picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ uint8_t uint8v;
+ uint16_t uint16v;
+ uint32_t uint32v;
+ uint64_t uint64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int or uint prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ /* uint prop */
+
+ switch (pinfo.size) {
+ case sizeof (uint8_t):
+ err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
+ *ret = err;
+ return (uint8v);
+ case sizeof (uint16_t):
+ err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
+ *ret = err;
+ return (uint16v);
+ case sizeof (uint32_t):
+ err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
+ *ret = err;
+ return (uint32v);
+ case sizeof (uint64_t):
+ err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
+ *ret = err;
+ return (uint64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+/*
+ * return the value of the float prop
+ */
+static float
+picldiag_get_float_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ float floatv;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return ((float)0);
+ }
+
+ /*
+ * If it is not a float prop, return failure
+ */
+ if (pinfo.type != PICL_PTYPE_FLOAT) {
+ *ret = PICL_FAILURE;
+ return ((float)0);
+ }
+
+ *ret = picl_get_propval(proph, &floatv, sizeof (floatv));
+ return (floatv);
+}
+
+/*
+ * get the clock frequency
+ */
+static int
+picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
+{
+#define ROUND_TO_MHZ(x) (((x) + 500000)/ 1000000)
+ int err;
+ uint64_t clk_freq;
+
+ clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ *freq = ROUND_TO_MHZ(clk_freq);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * get the clock frequency from parent
+ */
+static int
+picldiag_get_clock_from_parent(picl_nodehdl_t nodeh, uint32_t *clk)
+{
+ picl_nodehdl_t parenth;
+ int err;
+
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &parenth, sizeof (parenth));
+
+ while (err == PICL_SUCCESS) {
+ err = picldiag_get_clock_freq(parenth, clk);
+ if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT,
+ &parenth, sizeof (parenth));
+ }
+
+ return (err);
+}
+
+/*
+ * get _fru_parent prop
+ * If not found, then travese superiors (parent nodes) until
+ * a _fru_parent property is found.
+ * If not found, no fru parent
+ */
+static int
+picldiag_get_fru_parent(picl_nodehdl_t nodeh, picl_nodehdl_t *fruparenth)
+{
+ picl_nodehdl_t fruh;
+ int err;
+
+ /* find fru parent */
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
+ &fruh, sizeof (fruh));
+
+ if (err != PICL_SUCCESS)
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_LOC_PARENT,
+ &fruh, sizeof (fruh));
+
+ while (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_FRU_PARENT,
+ &fruh, sizeof (fruh));
+ if (err != PICL_SUCCESS)
+ err = picl_get_propval_by_name(nodeh,
+ PICL_REFPROP_LOC_PARENT, &fruh, sizeof (fruh));
+ }
+
+ if (err == PICL_SUCCESS)
+ *fruparenth = fruh;
+
+ return (err);
+}
+
+/*
+ * get label
+ *
+ * To get the label, use the following algorithm:
+ * Lookup "Label" property in the fru node itself. If no
+ * Label found, then traverse superiors (parent nodes) until
+ * a Label property is found.
+ * if not found, then no label
+ */
+static int
+picldiag_get_label(picl_nodehdl_t nodeh, char **label)
+{
+ int err;
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, label);
+
+ while (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL,
+ label);
+ }
+
+ return (err);
+}
+
+/*
+ * get combined label
+ *
+ * like picldiag_get_label, except concatenates the labels of parent locations
+ * eg SB0/P3 for processor P3 on system board SB0
+ *
+ * if caller specifies non-zero label length, label will be cut to specified
+ * length.
+ * negative length is left justified, non-negative length is right justified
+ */
+static int
+picldiag_get_combined_label(picl_nodehdl_t nodeh, char **label, int lablen)
+{
+ int err;
+ char *ptr;
+ char *ptr1 = NULL;
+ char *ptr2;
+ int len;
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr1);
+ if (err != PICL_PROPNOTFOUND && err != PICL_SUCCESS)
+ return (err);
+
+ for (;;) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &nodeh, sizeof (nodeh));
+ if (err == PICL_PROPNOTFOUND)
+ break;
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_LABEL, &ptr);
+ if (err == PICL_SUCCESS) {
+ if (ptr1 == NULL) {
+ ptr1 = ptr;
+ } else {
+ ptr2 = malloc(strlen(ptr1) + strlen(ptr) + 2);
+ if (ptr2 == NULL)
+ return (PICL_FAILURE);
+ (void) strlcpy(ptr2, ptr, strlen(ptr)-1);
+ (void) strlcat(ptr2, "/", 1);
+ (void) strlcat(ptr2, ptr1, strlen(ptr1)-1);
+ (void) strlcat(ptr2, "\0", 1);
+
+ (void) free(ptr);
+ (void) free(ptr1);
+ ptr1 = ptr2;
+ }
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ }
+
+ if (ptr1 == NULL)
+ return (PICL_PROPNOTFOUND);
+
+ len = strlen(ptr1);
+ /* if no string truncation is desired or required */
+ if ((lablen == 0) || (len <= abs(lablen))) {
+ *label = ptr1;
+ return (PICL_SUCCESS);
+ }
+
+ /* string truncation is required; alloc space for (lablen + \0) */
+ ptr = malloc(abs(lablen) + 1);
+ if (ptr == 0)
+ return (PICL_FAILURE);
+ if (lablen > 0) {
+ /* right justification; label = "+<string>\0" */
+ strlcpy(ptr, "+", 1);
+ strlcat(ptr, ptr1 + len - lablen + 1, lablen + 1);
+ } else {
+ /* left justification; label = "<string>+\0" */
+ strlcpy(ptr, ptr1, abs(lablen) - 1);
+ strcat(ptr, "+");
+ }
+
+ *label = ptr;
+ return (PICL_SUCCESS);
+}
+
+/*
+ * return the first compatible value
+ */
+static int
+picldiag_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ char *pval;
+
+ err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE,
+ &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE)
+ return (PICL_FAILURE);
+
+ /* get first string from table */
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ pval = malloc(pinfo.size);
+ if (pval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, pval, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(pval);
+ return (err);
+ }
+
+ *outbuf = pval;
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print the header in the center
+ */
+static void
+logprintf_header(char *header, size_t line_width)
+{
+ size_t start_pos;
+ size_t i;
+
+ log_printf("\n");
+ start_pos = (line_width - strlen(header) - 2) / 2;
+
+ for (i = 0; i < start_pos; i++)
+ log_printf("%s", HEADING_SYMBOL);
+
+ log_printf(" %s ", header);
+
+ for (i = 0; i < start_pos; i++)
+ log_printf("%s", HEADING_SYMBOL);
+
+ log_printf("\n");
+}
+
+/*
+ * print the size
+ */
+static void
+logprintf_size(uint64_t size)
+{
+
+ uint64_t kbyte = 1024;
+ uint64_t mbyte = 1024 * 1024;
+ uint64_t gbyte = 1024 * 1024 * 1024;
+ uint64_t residue;
+ char buf[SIZE_FIELD];
+
+ if (size >= gbyte) {
+ residue = size % gbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dGB",
+ (int)(size / gbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fGB",
+ (float)size / gbyte);
+ } else if (size >= mbyte) {
+ residue = size % mbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dMB",
+ (int)(size / mbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fMB",
+ (float)size / mbyte);
+ } else {
+ residue = size % kbyte;
+ if (residue == 0)
+ snprintf(buf, sizeof (buf), "%dKB",
+ (int)(size / kbyte));
+ else
+ snprintf(buf, sizeof (buf), "%.2fKB",
+ (float)size / kbyte);
+ }
+
+ log_printf("%-10s ", buf);
+}
+
+/*
+ * display platform banner
+ */
+static int
+display_platform_banner(picl_nodehdl_t plafh)
+{
+ char *platform;
+ char *banner_name;
+ int err;
+
+ /*
+ * get PICL_PROP_MACHINE and PICL_PROP_BANNER_NAME
+ */
+ log_printf(SIGN_ON_MSG);
+ err = picldiag_get_string_propval(plafh, PICL_PROP_MACHINE,
+ &platform);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", platform);
+ free(platform);
+
+ err = picldiag_get_string_propval(plafh, OBP_PROP_BANNER_NAME,
+ &banner_name);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", banner_name);
+ free(banner_name);
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+/*
+ * display the clock frequency
+ */
+static int
+display_system_clock(picl_nodehdl_t plafh)
+{
+ uint32_t system_clk;
+ int err;
+
+ err = picldiag_get_clock_freq(plafh, &system_clk);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf(SYSCLK_FREQ_MSG, system_clk);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback function to display the memory size
+ */
+/*ARGSUSED*/
+static int
+memory_callback(picl_nodehdl_t memh, void *args)
+{
+ uint64_t mem_size;
+ int err;
+
+ log_printf(MEM_SIZE_MSG);
+ mem_size = picldiag_get_uint_propval(memh, PICL_PROP_SIZE, &err);
+ if (err == PICL_SUCCESS)
+ logprintf_size(mem_size);
+ log_printf("\n");
+ no_xfer_size = 0;
+ mem_xfersize = picldiag_get_uint_propval(memh, PICL_PROP_TRANSFER_SIZE,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ no_xfer_size = 1;
+ return (PICL_WALK_TERMINATE);
+}
+
+/*
+ * callback function to print cpu information
+ */
+/*ARGSUSED*/
+static int
+cpu_callback(picl_nodehdl_t nodeh, void *args)
+{
+ int err;
+ int id;
+ uint64_t uintval;
+ uint32_t freq;
+ char *impl_name;
+ char *status;
+ picl_prophdl_t parenth;
+ char *label;
+
+ /*
+ * If no ID is found, return
+ */
+ id = picldiag_get_uint_propval(nodeh, PICL_PROP_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %2d ", id);
+
+ /*
+ * If no freq is found, return
+ */
+ err = picldiag_get_clock_freq(nodeh, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(dgettext(TEXT_DOMAIN, "%4d MHz "), freq);
+
+ /* Ecache size */
+ uintval = picldiag_get_uint_propval(nodeh, OBP_PROP_ECACHE_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS)
+ logprintf_size(uintval);
+ else
+ return (err);
+
+ /* Implementation */
+ impl_name = NULL;
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_NAME, &impl_name);
+ if (err != PICL_SUCCESS)
+ log_printf(dgettext(TEXT_DOMAIN, " <unknown> "));
+ else
+ log_printf(" %-22s ", impl_name);
+
+ /* CPU Mask */
+ uintval = picldiag_get_uint_propval(nodeh, OBP_PROP_MASK, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS)
+ log_printf("%2lld.%-2lld ", (uintval >> 4) & 0xf,
+ uintval & 0xf);
+ else
+ return (err);
+
+ /*
+ * Status - if the node has a status property then display that
+ * otherwise display the State property
+ */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err !=
+ PICL_PROPVALUNAVAILABLE && err != PICL_ENDOFLIST) {
+ return (err);
+ } else {
+ err = picldiag_get_string_propval(nodeh,
+ PICL_PROP_STATE, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err !=
+ PICL_PROPVALUNAVAILABLE && err !=
+ PICL_ENDOFLIST) {
+ return (err);
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN, "unknown "));
+ }
+ }
+
+ /*
+ * Location: use label of fru parent
+ */
+ err = picldiag_get_fru_parent(nodeh, &parenth);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf(" - ");
+ } else if (err == PICL_SUCCESS) {
+ err = picldiag_get_combined_label(parenth, &label, 12);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" - ");
+ else if (err == PICL_SUCCESS) {
+ log_printf("%s", label);
+ free(label);
+ } else
+ return (err);
+ } else
+ return (err);
+
+ log_printf("\n");
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * display cpu information
+ */
+static int
+display_cpu_info(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision on all the boards.
+ */
+ logprintf_header(dgettext(TEXT_DOMAIN, "CPUs"), DEFAULT_LINE_WIDTH);
+ log_printf(dgettext(TEXT_DOMAIN, " E$ CPU"
+ " CPU\n"));
+ log_printf(dgettext(TEXT_DOMAIN,
+ "CPU Freq Size Implementation"
+ " Mask Status Location\n"));
+ log_printf("--- -------- ---------- --------------------- "
+ "----- ------ --------\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU,
+ cpu_callback);
+ return (err);
+}
+
+/*
+ * Inserts an io_card structure into the list.
+ */
+static void
+add_io_card(uint32_t board, uint32_t bus_id, uint32_t slot, char *label,
+ uint32_t freq, char *name, char *model, char *status, char *devfs_path)
+{
+ struct io_card card;
+
+ card.display = 1;
+ card.board = board;
+ switch (bus_id) {
+ case PCI_TYPE:
+ strlcpy(card.bus_type, PCI_NAME, MAXSTRLEN);
+ break;
+ default: /* won't reach here */
+ strlcpy(card.bus_type, "", MAXSTRLEN);
+ break;
+ }
+ if (label == NULL)
+ card.slot = slot;
+ else {
+ card.slot = PCI_SLOT_IS_STRING;
+ (void) strlcpy(card.slot_str, label, MAXSTRLEN);
+ }
+ card.freq = freq;
+ card.status[0] = '\0';
+ card.name[0] = '\0';
+ card.model[0] = '\0';
+ card.notes[0] = '\0';
+ if (status != NULL)
+ strlcpy(card.status, status, MAXSTRLEN);
+ if (name != NULL)
+ strlcpy(card.name, name, MAXSTRLEN);
+ if (model != NULL)
+ strlcpy(card.model, model, MAXSTRLEN);
+ if (status != NULL)
+ strlcpy(card.status, status, MAXSTRLEN);
+ if (devfs_path != NULL)
+ strlcpy(card.notes, devfs_path, MAXSTRLEN);
+
+ io_card_list = insert_io_card(io_card_list, &card);
+}
+
+static void
+append_to_bank_list(bank_list_t *newptr)
+{
+ bank_list_t *ptr;
+
+ if (mem_banks == NULL) {
+ mem_banks = newptr;
+ return;
+ }
+ ptr = mem_banks;
+ while (ptr->next != NULL)
+ ptr = ptr->next;
+
+ ptr->next = newptr;
+}
+
+static void
+free_bank_list(void)
+{
+ bank_list_t *ptr;
+ bank_list_t *tmp;
+
+ for (ptr = mem_banks; ptr != NULL; ptr = tmp) {
+ tmp = ptr->next;
+ free(ptr);
+ }
+ mem_banks = NULL;
+}
+
+
+/*
+ * print label for memory module
+ */
+static int
+logprintf_memory_module_label(picl_nodehdl_t moduleh)
+{
+ picl_nodehdl_t fruparenth;
+ int err;
+ char *label;
+
+ err = picldiag_get_fru_parent(moduleh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-");
+ return (PICL_SUCCESS);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruparenth, &label, 30);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("-");
+ else if (err == PICL_SUCCESS) {
+ log_printf("%-15s", label);
+ free(label);
+ } else
+ return (err);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print the bank id and add the bank handle in the bank list
+ * return the head of the bank list
+ */
+static int
+membank_callback(picl_nodehdl_t bankh, void *args)
+{
+ int err;
+ int64_t id;
+ uint64_t match;
+ uint64_t mask;
+ int i;
+ bank_list_t *newptr;
+ seg_info_t *segp = args;
+
+ /*
+ * print the bank id in the segment table contains column
+ */
+ id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
+ if (segp->bank_count > 0)
+ log_printf(",");
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("-");
+ else if (err == PICL_SUCCESS)
+ log_printf("%-lld", id);
+ else
+ return (err);
+ segp->bank_count++;
+
+ /*
+ * Save the bank information for later (print_bank_table)
+ */
+ newptr = malloc(sizeof (*newptr));
+ if (newptr == NULL)
+ return (PICL_FAILURE);
+
+ newptr->nodeh = bankh;
+ newptr->iway_count = 0;
+ newptr->next = NULL;
+ append_to_bank_list(newptr);
+
+ /*
+ * Compute the way numbers for the bank
+ */
+ if (no_xfer_size)
+ return (PICL_WALK_CONTINUE);
+
+ match = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMATCH, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ mask = picldiag_get_uint_propval(bankh, PICL_PROP_ADDRESSMASK, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ i = 0;
+ while ((i < segp->ifactor) && (newptr->iway_count < MAX_IWAYS)) {
+ if (((segp->base + i * mem_xfersize) & mask) == match)
+ newptr->iway[newptr->iway_count++] = i;
+ ++i;
+ }
+ return (PICL_WALK_CONTINUE);
+}
+
+
+/*
+ * find the memory bank and add the bank handle in the bank list
+ * return the head of the bank list
+ */
+static int
+logprintf_bankinfo(picl_nodehdl_t segh, seg_info_t *segp)
+{
+ int err;
+
+ log_printf(dgettext(TEXT_DOMAIN, "BankIDs "));
+ /*
+ * find memory-bank
+ */
+ segp->bank_count = 0;
+ err = picl_walk_tree_by_class(segh, PICL_CLASS_MEMORY_BANK, segp,
+ membank_callback);
+ log_printf("\n");
+ return (err);
+}
+
+/*
+ * print the label of memory module or the memory module bank ids
+ */
+static int
+logprintf_seg_contains_col(picl_nodehdl_t nodeh, seg_info_t *segp)
+{
+ picl_nodehdl_t moduleh;
+ int err;
+
+ /*
+ * find memory-module if referenced directly from the memory-segment
+ * (ie no memory banks)
+ */
+ err = picl_get_propval_by_name(nodeh, PICL_REFPROP_MEMORY_MODULE,
+ &moduleh, sizeof (moduleh));
+ if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND))
+ return (err);
+ if (err == PICL_SUCCESS) {
+ err = logprintf_memory_module_label(moduleh);
+ log_printf("\n");
+ return (err);
+ }
+
+ /*
+ * memory-module not referenced directly from the memory segment
+ * so list memory banks instead
+ */
+ err = logprintf_bankinfo(nodeh, segp);
+ return (err);
+}
+
+/*
+ * find all memory modules under the given memory module group
+ * and print its label
+ */
+static int
+logprintf_memory_module_group_info(picl_nodehdl_t memgrph, uint64_t mcid)
+{
+ int err;
+ int64_t id;
+ boolean_t got_status;
+ picl_nodehdl_t moduleh;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ picl_nodehdl_t fruparenth;
+ char *status;
+
+ id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ id = -1;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(memgrph, PICL_PROP_CHILD, &moduleh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ /* controller id */
+ log_printf("%-8lld ", mcid);
+
+ /* group id */
+ if (id == -1) {
+ log_printf("- ");
+ } else {
+ log_printf("%-8lld ", id);
+ }
+
+ err = picl_get_propval_by_name(moduleh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE) == 0) {
+ err = logprintf_memory_module_label(moduleh);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ got_status = B_FALSE;
+ err = picldiag_get_fru_parent(moduleh, &fruparenth);
+ if (err == PICL_SUCCESS) {
+ err = picldiag_get_string_propval(fruparenth,
+ PICL_PROP_OPERATIONAL_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ got_status = B_TRUE;
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+ } else if (err != PICL_PROPNOTFOUND)
+ return (err);
+
+ if (!got_status) {
+ err = picldiag_get_string_propval(moduleh,
+ PICL_PROP_STATUS, &status);
+ if (err == PICL_SUCCESS)
+ got_status = B_TRUE;
+ else if (err != PICL_PROPNOTFOUND)
+ return (err);
+ }
+ if (got_status) {
+ log_printf("%s", status);
+ free(status);
+ }
+ err = picl_get_propval_by_name(moduleh, PICL_PROP_PEER,
+ &moduleh, sizeof (picl_nodehdl_t));
+
+ log_printf("\n");
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * search children to find memory module group under memory-controller
+ */
+static int
+find_memory_module_group(picl_nodehdl_t mch, int *print_header)
+{
+ picl_nodehdl_t memgrph;
+ uint64_t mcid;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+
+ mcid = picldiag_get_uint_propval(mch, OBP_PROP_PORTID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ mcid = DEFAULT_PORTID;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(mch, PICL_PROP_CHILD,
+ &memgrph, sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(memgrph,
+ PICL_PROP_CLASSNAME, piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_MODULE_GROUP) == 0) {
+ if (*print_header == 1) {
+ log_printf(
+ dgettext(TEXT_DOMAIN,
+ "\nMemory Module Groups:\n"));
+ log_printf("--------------------------");
+ log_printf("------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "ControllerID GroupID Labels\n"));
+ log_printf("--------------------------");
+ log_printf("------\n");
+ *print_header = 0;
+ }
+ err = logprintf_memory_module_group_info(memgrph, mcid);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ err = picl_get_propval_by_name(memgrph, PICL_PROP_PEER,
+ &memgrph, sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+/*
+ * print memory module group table per memory-controller
+ */
+static int
+print_memory_module_group_table(picl_nodehdl_t plafh)
+{
+ picl_nodehdl_t mch;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ int print_header;
+
+ print_header = 1;
+
+ /*
+ * find memory-controller
+ */
+ err = picl_get_propval_by_name(plafh, PICL_PROP_CHILD, &mch,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(mch, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (strcmp(piclclass, PICL_CLASS_MEMORY_CONTROLLER) != 0) {
+ err = print_memory_module_group_table(mch);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
+ &mch, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ err = find_memory_module_group(mch, &print_header);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(mch, PICL_PROP_PEER,
+ &mch, sizeof (picl_nodehdl_t));
+ }
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+
+ return (err);
+}
+
+/*
+ * print bank table
+ */
+static int
+print_bank_table(void)
+{
+ bank_list_t *ptr;
+ picl_nodehdl_t bankh;
+ picl_nodehdl_t memgrph;
+ picl_nodehdl_t mch;
+ int err;
+ int32_t i;
+ uint64_t size;
+ int id;
+
+ log_printf(dgettext(TEXT_DOMAIN, "\nBank Table:\n"));
+ log_printf("---------------------------------------");
+ log_printf("--------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, " Physical Location\n"));
+ log_printf(dgettext(TEXT_DOMAIN, "ID ControllerID GroupID "));
+ log_printf(dgettext(TEXT_DOMAIN, "Size Interleave Way\n"));
+ log_printf("---------------------------------------");
+ log_printf("--------------------\n");
+
+ for (ptr = mem_banks; ptr != NULL; ptr = ptr->next) {
+ bankh = ptr->nodeh;
+ id = picldiag_get_uint_propval(bankh, PICL_PROP_ID, &err);
+ if (err != PICL_SUCCESS)
+ log_printf("%-8s ", "-");
+ else
+ log_printf("%-8d ", id);
+
+ /* find memory-module-group */
+ err = picl_get_propval_by_name(bankh,
+ PICL_REFPROP_MEMORY_MODULE_GROUP, &memgrph,
+ sizeof (memgrph));
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("%-8s ", "-");
+ log_printf("%-8s ", "-");
+ } else if (err != PICL_SUCCESS)
+ return (err);
+ else {
+ /*
+ * get controller id
+ */
+ err = picl_get_propval_by_name(memgrph,
+ PICL_PROP_PARENT, &mch, sizeof (picl_nodehdl_t));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ id = picldiag_get_uint_propval(mch, OBP_PROP_PORTID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ id = DEFAULT_PORTID; /* use default */
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-8d ", id);
+
+ /* get group id */
+ id = picldiag_get_uint_propval(memgrph, PICL_PROP_ID,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("- ");
+ else if (err == PICL_SUCCESS)
+ log_printf("%-8d ", id);
+ else
+ return (err);
+ }
+
+ size = picldiag_get_uint_propval(bankh, PICL_PROP_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND)
+ log_printf("- ");
+ else if (err == PICL_SUCCESS)
+ logprintf_size(size);
+ else
+ return (err);
+
+ log_printf(" ");
+ for (i = 0; i < ptr->iway_count; i++) {
+ if (i != 0)
+ log_printf(",");
+ log_printf("%d", ptr->iway[i]);
+ }
+
+ log_printf("\n");
+ }
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback function to print segment, add the bank in the list and
+ * return the bank list
+ */
+/* ARGSUSED */
+static int
+memseg_callback(picl_nodehdl_t segh, void *args)
+{
+ seg_info_t seginfo;
+ int err;
+
+ /* get base address */
+ seginfo.base = picldiag_get_uint_propval(segh, PICL_PROP_BASEADDRESS,
+ &err);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ log_printf("0x%-16llx ", seginfo.base);
+ else
+ return (err);
+
+ /* get size */
+ seginfo.size = picldiag_get_uint_propval(segh, PICL_PROP_SIZE, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf("-\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ logprintf_size(seginfo.size);
+ else
+ return (err);
+
+ /* get interleave factor */
+ seginfo.ifactor = picldiag_get_uint_propval(segh,
+ PICL_PROP_INTERLEAVE_FACTOR, &err);
+
+ if (err == PICL_PROPNOTFOUND) {
+ log_printf(" -\n");
+ return (PICL_WALK_CONTINUE);
+ } else if (err == PICL_SUCCESS)
+ log_printf(" %-2d ", seginfo.ifactor);
+ else
+ return (err);
+
+ seginfo.bank_count = 0;
+ err = logprintf_seg_contains_col(segh, &seginfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * search children to find memory-segment and set up the bank list
+ */
+static int
+find_segments(picl_nodehdl_t plafh)
+{
+ int err;
+
+ log_printf(dgettext(TEXT_DOMAIN, "Segment Table:\n"));
+ log_printf("------------------------------");
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Base Address Size "));
+ log_printf(dgettext(TEXT_DOMAIN, "Interleave Factor Contains\n"));
+ log_printf("------------------------------");
+ log_printf("-----------------------------------------\n");
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT,
+ NULL, memseg_callback);
+ return (err);
+}
+
+/*
+ * display memory configuration
+ */
+static int
+display_memory_config(picl_nodehdl_t plafh)
+{
+ int err;
+
+ logprintf_header(dgettext(TEXT_DOMAIN, "Memory Configuration"),
+ DEFAULT_LINE_WIDTH);
+
+ mem_banks = NULL;
+ err = find_segments(plafh);
+
+ if ((err == PICL_SUCCESS) && (mem_banks != NULL))
+ print_bank_table();
+
+ free_bank_list();
+
+ return (print_memory_module_group_table(plafh));
+}
+
+/*
+ * print the hub device
+ */
+static int
+logprintf_hub_devices(picl_nodehdl_t hubh)
+{
+ char *name;
+ int portnum;
+ char *labelp;
+ picl_nodehdl_t parenth;
+ int err;
+
+ err = picldiag_get_string_propval(hubh, PICL_PROP_NAME, &name);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-12.12s ", name);
+ free(name);
+
+ err = picl_get_propval_by_name(hubh, PICL_REFPROP_LOC_PARENT, &parenth,
+ sizeof (picl_nodehdl_t));
+
+ if (err == PICL_SUCCESS) {
+ /* Read the Label */
+ err = picldiag_get_label(parenth, &labelp);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s\n", labelp);
+ free(labelp);
+ return (PICL_SUCCESS);
+ } else if (err != PICL_PROPNOTFOUND) {
+ log_printf("\n");
+ return (err);
+ }
+ } else if (err != PICL_PROPNOTFOUND) {
+ log_printf("\n");
+ return (err);
+ }
+
+ /* No Label, try the reg */
+ err = picl_get_propval_by_name(hubh, OBP_PROP_REG, &portnum,
+ sizeof (portnum));
+ if (err == PICL_PROPNOTFOUND)
+ log_printf(" -\n");
+ else if (err != PICL_SUCCESS) {
+ log_printf("\n");
+ return (err);
+ } else
+ log_printf("%3d\n", portnum);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * callback functions to display hub devices
+ */
+/* ARGSUSED */
+static int
+print_usb_devices(picl_nodehdl_t hubh, void *arg)
+{
+ picl_nodehdl_t chdh;
+ char *rootname;
+ int type = *(int *)arg;
+ int hubnum;
+ int err;
+
+ err = picl_get_propval_by_name(hubh, PICL_PROP_CHILD, &chdh,
+ sizeof (picl_nodehdl_t));
+
+ /* print header */
+ if (err == PICL_SUCCESS) {
+ err = picldiag_get_string_propval(hubh, PICL_PROP_NAME,
+ &rootname);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (type == USB) {
+ log_printf("\n===============================");
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s Devices "), rootname);
+ } else {
+ /* Get its hub number */
+ err = picl_get_propval_by_name(hubh,
+ OBP_PROP_REG, &hubnum, sizeof (hubnum));
+ if ((err != PICL_SUCCESS) &&
+ (err != PICL_PROPNOTFOUND)) {
+ free(rootname);
+ return (err);
+ }
+
+ log_printf("\n===============================");
+ if (err == PICL_SUCCESS)
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s#%d Devices "),
+ rootname, hubnum);
+ else
+ log_printf(dgettext(TEXT_DOMAIN,
+ " %s Devices "), rootname);
+ }
+
+ log_printf("===============================\n\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Name Port#\n"));
+ log_printf("------------ -----\n");
+ free(rootname);
+
+ do {
+ logprintf_hub_devices(chdh);
+
+ err = picl_get_propval_by_name(chdh, PICL_PROP_PEER,
+ &chdh, sizeof (picl_nodehdl_t));
+ } while (err == PICL_SUCCESS);
+ }
+
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback functions to display usb devices
+ */
+/* ARGSUSED */
+static int
+usb_callback(picl_nodehdl_t usbh, void *args)
+{
+ int err;
+ int type;
+
+ type = USB;
+ err = print_usb_devices(usbh, &type);
+ if (err != PICL_WALK_CONTINUE)
+ return (err);
+ type = HUB;
+ err = picl_walk_tree_by_class(usbh, NULL, &type, print_usb_devices);
+ if (err == PICL_SUCCESS)
+ err = PICL_WALK_CONTINUE;
+ return (err);
+}
+
+
+/*
+ * find usb devices and print its information
+ */
+static int
+display_usb_devices(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * get the usb node
+ */
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_USB, NULL,
+ usb_callback);
+ return (err);
+}
+
+
+
+/*
+ * If nodeh is the io device, add it into the io list and return
+ * If it is not an io device and it has the subtree, traverse the subtree
+ * and add all leaf io devices
+ */
+static int
+add_io_leaves(picl_nodehdl_t nodeh, char *parentname, uint32_t board,
+ uint32_t bus_id, uint64_t slot, uint32_t freq, char *model, char *status)
+{
+ picl_nodehdl_t childh;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ int err;
+ char *nameval;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ char nodename[MAXSTRLEN];
+ char name[MAXSTRLEN];
+ char *devfs_path;
+ char *compatible;
+ picl_nodehdl_t fruparenth;
+ char *label;
+ char binding_name[MAXSTRLEN];
+
+ err = picl_get_propinfo_by_name(nodeh, PICL_PROP_NAME, &pinfo,
+ &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ nameval = alloca(pinfo.size);
+ if (nameval == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, nameval, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ (void) strlcpy(nodename, nameval, MAXSTRLEN);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /* if binding_name is found, name will be <nodename>-<binding_name> */
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME,
+ binding_name, sizeof (binding_name));
+ if (err == PICL_PROPNOTFOUND) {
+ /*
+ * if compatible prop is found, name will be
+ * <nodename>-<compatible>
+ */
+ err = picldiag_get_first_compatible_value(nodeh, &compatible);
+ if (err == PICL_SUCCESS) {
+ strlcat(nodename, "-", MAXSTRLEN);
+ strlcat(nodename, compatible, MAXSTRLEN);
+ free(compatible);
+ } else if (err != PICL_PROPNOTFOUND) {
+ return (err);
+ }
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else if (strcmp(nodename, binding_name) != 0) {
+ if (strcmp(nodename, piclclass) == 0) {
+ /*
+ * nodename same as binding name -
+ * no need to display twice
+ */
+ strlcpy(nodename, binding_name, MAXSTRLEN);
+ } else {
+ strlcat(nodename, "-", MAXSTRLEN);
+ strlcat(nodename, binding_name, MAXSTRLEN);
+ }
+ }
+
+ /*
+ * If it is an immediate child under pci and not
+ * a bus node, add it to the io list.
+ * If it is a child under sub-bus and it is in an io
+ * device, add it to the io list.
+ */
+ if (((parentname == NULL) && (!is_bus(piclclass))) ||
+ ((parentname != NULL) && (is_io_device(piclclass)))) {
+ if (parentname == NULL)
+ (void) snprintf(name, MAXSTRLEN, "%s", nodename);
+ else
+ (void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
+ nodename);
+
+ /*
+ * append the class if its class is not a generic
+ * obp-device class
+ */
+ if (strcmp(piclclass, PICL_CLASS_OBP_DEVICE))
+ (void) snprintf(name, MAXSTRLEN, "%s (%s)", name,
+ piclclass);
+
+ err = picldiag_get_fru_parent(nodeh, &fruparenth);
+ if (err == PICL_PROPNOTFOUND) {
+ label = NULL;
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ err = picldiag_get_combined_label(fruparenth, &label,
+ 15);
+ if (err == PICL_PROPNOTFOUND)
+ label = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+ }
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH,
+ &devfs_path);
+ if (err == PICL_PROPNOTFOUND)
+ devfs_path = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ add_io_card(board, bus_id, slot, label, freq, name,
+ model, status, devfs_path);
+ if (label != NULL)
+ free(label);
+ if (devfs_path != NULL)
+ free(devfs_path);
+ return (PICL_SUCCESS);
+ }
+
+ /*
+ * If there is any child, Go through each child.
+ */
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
+ &childh, sizeof (picl_nodehdl_t));
+
+ /* there is a child */
+ while (err == PICL_SUCCESS) {
+ if (parentname == NULL)
+ (void) strlcpy(name, nodename, MAXSTRLEN);
+ else
+ (void) snprintf(name, MAXSTRLEN, "%s/%s", parentname,
+ nodename);
+
+ err = add_io_leaves(childh, name, board, bus_id, slot, freq,
+ model, status);
+ if (err != PICL_SUCCESS)
+ return (err);
+ /*
+ * get next child
+ */
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+ return (err);
+}
+
+
+/*
+ * add all io devices under pci in io list
+ */
+/* ARGSUSED */
+static int
+pci_callback(picl_nodehdl_t pcih, void *args)
+{
+ picl_nodehdl_t nodeh;
+ int err;
+ char piclclass[PICL_CLASSNAMELEN_MAX];
+ uint32_t boardnum;
+ uint32_t bus_id;
+ uint32_t slot;
+ uint32_t freq;
+ char *model;
+ char *status;
+
+ /* Fill in common infomation */
+ bus_id = PCI_TYPE;
+
+ /*
+ * Check if it has the freq, if not,
+ * If not, use its parent's freq
+ * if its parent's freq is not found, return
+ */
+ err = picldiag_get_clock_freq(pcih, &freq);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picldiag_get_clock_from_parent(pcih, &freq);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If no board# is found, set boardnum to 0
+ */
+ boardnum = picldiag_get_uint_propval(pcih, OBP_PROP_BOARD_NUM, &err);
+ if (err == PICL_PROPNOTFOUND)
+ boardnum = DEFAULT_BOARD_NUM;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Walk through the children */
+
+ err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ piclclass, sizeof (piclclass));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Skip PCI bridge and USB devices because they will be
+ * processed later
+ */
+ if ((strcmp(piclclass, PICL_CLASS_PCI) == 0) ||
+ (strcmp(piclclass, PICL_CLASS_USB) == 0)) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ /* Get the device id for pci card */
+ slot = picldiag_get_uint_propval(nodeh,
+ PICL_PROP_DEVICE_ID, &err);
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER,
+ &nodeh, sizeof (picl_nodehdl_t));
+ continue;
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* Get the model of this card */
+ err = picldiag_get_string_propval(nodeh, OBP_PROP_MODEL,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS,
+ &status);
+ if (err == PICL_PROPNOTFOUND) {
+ status = malloc(5);
+ if (status == NULL)
+ return (PICL_FAILURE);
+ strlcpy(status, "okay", 5);
+ } else if (err != PICL_SUCCESS)
+ return (err);
+
+ err = add_io_leaves(nodeh, NULL, boardnum, bus_id, slot,
+ freq, model, status);
+
+ if (model != NULL)
+ free(model);
+
+ if (status != NULL)
+ free(status);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+
+ return (err);
+}
+
+
+/*
+ * loop through all children and add io devices in io list
+ */
+static int
+process_io_leaves(picl_nodehdl_t rooth)
+{
+ picl_nodehdl_t nodeh;
+ char classval[PICL_CLASSNAMELEN_MAX];
+ int err;
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh,
+ sizeof (picl_nodehdl_t));
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
+ classval, sizeof (classval));
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
+ sizeof (picl_nodehdl_t));
+ }
+
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_SUCCESS);
+
+ return (err);
+}
+
+
+/*
+ * find all io devices and add them in the io list
+ */
+static int
+gather_io_cards(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /*
+ * look for io devices under the immediate children of platform
+ */
+ err = process_io_leaves(plafh);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_PCI,
+ PICL_CLASS_PCI, pci_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ return (err);
+}
+
+static void
+picldiag_display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == 0) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Bus Freq Slot + Name +\n"), 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Type MHz Status "
+ "Path "
+ "Model"), 0);
+ log_printf("\n", 0);
+ log_printf("---- ---- ---------- "
+ "---------------------------- "
+ "--------------------", 0);
+ log_printf("\n", 0);
+ banner = 1;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf("%-4s ", p->bus_type, 0);
+ log_printf("%3d ", p->freq, 0);
+ /*
+ * We check to see if it's an int or
+ * a char string to display for slot.
+ */
+ if (p->slot == PCI_SLOT_IS_STRING)
+ log_printf("%10s ", p->slot_str, 0);
+ else
+ log_printf("%10d ", p->slot, 0);
+
+ log_printf("%-28.28s", p->name, 0);
+ if (strlen(p->name) > 28)
+ log_printf("+ ", 0);
+ else
+ log_printf(" ", 0);
+ log_printf("%-19.19s", p->model, 0);
+ if (strlen(p->model) > 19)
+ log_printf("+", 0);
+ log_printf("\n", 0);
+ log_printf(" %10s ", p->status, 0);
+ if (strlen(p->notes) > 0)
+ log_printf("%s", p->notes, 0);
+ log_printf("\n\n", 0);
+ }
+}
+
+/*
+ * display all io devices
+ */
+static int
+display_io_device_info(picl_nodehdl_t plafh)
+{
+ int err;
+
+ err = gather_io_cards(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ logprintf_header(dgettext(TEXT_DOMAIN, "IO Devices"),
+ DEFAULT_LINE_WIDTH);
+
+ picldiag_display_io_cards(io_card_list);
+
+ free_io_cards(io_card_list);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print fan device information
+ */
+static int
+logprintf_fan_info(picl_nodehdl_t fanh)
+{
+ int err;
+ char *label;
+ char *unit;
+ int64_t speed;
+ int64_t min_speed;
+ picl_nodehdl_t fruph;
+
+ err = picldiag_get_fru_parent(fanh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 14);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-14s ", label);
+ free(label);
+
+ err = picldiag_get_label(fanh, &label);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-14s ", label);
+ free(label);
+ } else if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" - ");
+ } else
+ return (err);
+
+ speed = picldiag_get_uint_propval(fanh, PICL_PROP_FAN_SPEED, &err);
+ if (err == PICL_SUCCESS) {
+ min_speed = picldiag_get_uint_propval(fanh,
+ PICL_PROP_LOW_WARNING_THRESHOLD, &err);
+ if (err != PICL_SUCCESS)
+ min_speed = 0;
+ if (speed < min_speed) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "failed (%lld"), speed);
+ err = picldiag_get_string_propval(fanh,
+ PICL_PROP_FAN_SPEED_UNIT, &unit);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", unit);
+ free(unit);
+ }
+ log_printf(")");
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN, "okay"));
+ }
+ } else {
+ err = picldiag_get_string_propval(fanh,
+ PICL_PROP_FAN_SPEED_UNIT, &unit);
+ if (err == PICL_SUCCESS) {
+ log_printf("%-12s ", unit);
+ free(unit);
+ }
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+fan_callback(picl_nodehdl_t fanh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+ log_printf(dgettext(TEXT_DOMAIN, "Fan Status:\n"));
+ log_printf("---------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Sensor Status \n"));
+ log_printf("---------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_fan_info(fanh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find fan device and print its speed
+ */
+static int
+display_fan_speed(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_FAN,
+ &print_header, fan_callback);
+ return (err);
+}
+
+/*
+ * print temperature sensor information
+ */
+static int
+logprintf_temp_info(picl_nodehdl_t temph)
+{
+ int err;
+ char *label;
+ int64_t temperature;
+ int64_t threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_temp = 0;
+
+ err = picldiag_get_fru_parent(temph, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 14);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-14s ", label);
+ free(label);
+
+ err = picldiag_get_label(temph, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-14s ", label);
+ free(label);
+
+ temperature = picldiag_get_int_propval(temph, PICL_PROP_TEMPERATURE,
+ &err);
+ if (err == PICL_SUCCESS) {
+ got_temp = 1;
+ status = "okay";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_int_propval(temph, PICL_PROP_HIGH_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_temp && temperature > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(temph, PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ if (strcmp(status, "failed") == 0 ||
+ strcmp(status, "warning") == 0)
+ log_printf("(%.2lldC)", temperature);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+temp_callback(picl_nodehdl_t temph, void *arg)
+{
+ int err;
+ int *countp = arg;
+
+ if (*countp == 0) {
+ log_printf("\n");
+ log_printf("---------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Temperature sensors:\n"));
+ log_printf("------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Sensor Status\n"));
+ log_printf("------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_temp_info(temph);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find temp sensors and print the temp
+ */
+/* ARGSUSED */
+static int
+display_temp(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_SENSOR,
+ &print_header, temp_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_TEMPERATURE_INDICATOR,
+ &print_header, temp_callback);
+ return (err);
+}
+
+/*
+ * print current sensor information
+ */
+static int
+logprintf_current_info(picl_nodehdl_t currenth)
+{
+ int err;
+ char *label;
+ float current;
+ float threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_current = 0;
+
+ err = picldiag_get_fru_parent(currenth, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-10s ", label);
+ free(label);
+
+ err = picldiag_get_label(currenth, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-10s ", label);
+ free(label);
+
+ current = picldiag_get_float_propval(currenth, PICL_PROP_CURRENT, &err);
+ if (err == PICL_SUCCESS) {
+ status = "okay";
+ got_current = 1;
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(currenth,
+ PICL_PROP_HIGH_SHUTDOWN, &err);
+ if (err == PICL_SUCCESS) {
+ if (got_current && current > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(currenth,
+ PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf(" %s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ if (strcmp(status, "failed") == 0 ||
+ strcmp(status, "warning") == 0)
+ log_printf("(%.2fA)", current);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+current_callback(picl_nodehdl_t currh, void *arg)
+{
+ int err;
+ int *countp = arg;
+
+ if (*countp == 0) {
+ log_printf("------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Current sensors:\n"));
+ log_printf("------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Sensor Status\n"));
+ log_printf("------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_current_info(currh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find curr sensors and print the curr
+ */
+/* ARGSUSED */
+static int
+display_current(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_SENSOR,
+ &print_header, current_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_CURRENT_INDICATOR,
+ &print_header, current_callback);
+ return (err);
+}
+
+/*
+ * print voltage sensor information
+ */
+static int
+logprintf_voltage_info(picl_nodehdl_t voltageh)
+{
+ int err;
+ char *label;
+ float voltage;
+ float threshold;
+ picl_nodehdl_t fruph;
+ char *status = "unknown";
+ int got_voltage = 0;
+
+ err = picldiag_get_fru_parent(voltageh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("%-10s ", label);
+ free(label);
+
+ err = picldiag_get_label(voltageh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-12s ", label);
+ free(label);
+
+ voltage = picldiag_get_float_propval(voltageh, PICL_PROP_VOLTAGE, &err);
+ if (err == PICL_SUCCESS) {
+ status = "okay";
+ got_voltage = 1;
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage < threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_LOW_SHUTDOWN,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage < threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh, PICL_PROP_HIGH_WARNING,
+ &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage > threshold)
+ status = "warning";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ threshold = picldiag_get_float_propval(voltageh,
+ PICL_PROP_HIGH_SHUTDOWN, &err);
+ if (err == PICL_SUCCESS) {
+ if (got_voltage && voltage > threshold)
+ status = "failed";
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ }
+
+ err = picldiag_get_string_propval(voltageh,
+ PICL_PROP_CONDITION, &status);
+ if (err == PICL_SUCCESS) {
+ log_printf("%s", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ return (err);
+ } else {
+ log_printf("%s ", status);
+ if (strcmp(status, "warning") == 0 ||
+ strcmp(status, "failed") == 0)
+ log_printf("(%.2fV)", voltage);
+ }
+
+ log_printf("\n");
+ return (PICL_SUCCESS);
+}
+
+static int
+voltage_callback(picl_nodehdl_t voltageh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+ log_printf("--------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Voltage sensors:\n"));
+ log_printf("-------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Sensor Status\n"));
+ log_printf("-------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_voltage_info(voltageh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find voltage sensors and print voltage
+ */
+/* ARGSUSED */
+static int
+display_voltage(picl_nodehdl_t plafh)
+{
+ int err;
+ int print_header;
+
+ print_header = 0;
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_SENSOR,
+ &print_header, voltage_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_VOLTAGE_INDICATOR,
+ &print_header, voltage_callback);
+ return (err);
+}
+
+/*
+ * print led device information
+ */
+static int
+logprintf_led_info(picl_nodehdl_t ledh)
+{
+ int err;
+ char *label;
+ char *state;
+ char *color;
+ picl_nodehdl_t fruph;
+
+ err = picldiag_get_fru_parent(ledh, &fruph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS) {
+ log_printf(" - ", label);
+ } else {
+ log_printf("%-10s ", label);
+ free(label);
+ }
+
+ err = picldiag_get_label(ledh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-20s ", label);
+ free(label);
+
+ err = picldiag_get_string_propval(ledh, PICL_PROP_STATE, &state);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" - ");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%-10s ", state);
+ free(state);
+ }
+
+ err = picldiag_get_string_propval(ledh, PICL_PROP_COLOR, &color);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf("\n");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%-16s\n", color);
+ free(color);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+static int
+led_callback(picl_nodehdl_t ledh, void *arg)
+{
+ int *countp = arg;
+ int err;
+
+ if (*countp == 0) {
+
+ log_printf("--------------------------------------"
+ "------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Led State:\n"));
+ log_printf("--------------------------------------"
+ "------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Led State"
+ " Color\n"));
+ log_printf("--------------------------------------"
+ "------------\n");
+ }
+ *countp += 1;
+ err = logprintf_led_info(ledh);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * callback function search children to find led devices and print status
+ */
+/* ARGSUSED */
+static int
+display_led_status(picl_nodehdl_t plafh)
+{
+ int print_header;
+
+ print_header = 0;
+ picl_walk_tree_by_class(plafh, PICL_CLASS_LED,
+ &print_header, led_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print keyswitch device information
+ */
+static int
+logprintf_keyswitch_info(picl_nodehdl_t keyswitchh, picl_nodehdl_t fruph)
+{
+ int err;
+ char *label;
+ char *state;
+
+ err = picldiag_get_combined_label(fruph, &label, 10);
+ if (err != PICL_SUCCESS) {
+ log_printf("%-14s", " -");
+ } else {
+ log_printf("%-14s ", label);
+ free(label);
+ }
+
+ err = picldiag_get_label(keyswitchh, &label);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%-11s ", label);
+ free(label);
+
+ err = picldiag_get_string_propval(keyswitchh, PICL_PROP_STATE, &state);
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE) {
+ log_printf(" -\n");
+ } else if (err != PICL_SUCCESS) {
+ return (err);
+ } else {
+ log_printf("%s\n", state);
+ free(state);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+static int
+keyswitch_callback(picl_nodehdl_t keyswitchh, void *arg)
+{
+ int *countp = arg;
+ int err;
+ picl_nodehdl_t fruph;
+
+ /*
+ * Tamale simulates a key-switch on ENxS. So the presence of a
+ * node of class keyswitch is not sufficient. If it has a fru parent
+ * or location parent, then believe it.
+ */
+ err = picl_get_propval_by_name(keyswitchh, PICL_REFPROP_FRU_PARENT,
+ &fruph, sizeof (fruph));
+ if (err == PICL_PROPNOTFOUND) {
+ err = picl_get_propval_by_name(keyswitchh,
+ PICL_REFPROP_LOC_PARENT, &fruph, sizeof (fruph));
+ }
+ if (err == PICL_PROPNOTFOUND || err == PICL_PROPVALUNAVAILABLE)
+ return (PICL_WALK_CONTINUE);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (*countp == 0) {
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Keyswitch:\n"));
+ log_printf("-----------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Keyswitch State\n"));
+ log_printf("-----------------------------------------\n");
+ }
+ *countp += 1;
+ err = logprintf_keyswitch_info(keyswitchh, fruph);
+ if (err == PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+ return (err);
+}
+
+/*
+ * search children to find keyswitch device(s) and print status
+ */
+/* ARGSUSED */
+static int
+display_keyswitch(picl_nodehdl_t plafh)
+{
+ int print_header = 0;
+
+ picl_walk_tree_by_class(plafh, PICL_CLASS_KEYSWITCH,
+ &print_header, keyswitch_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * display environment status
+ */
+static int
+display_envctrl_status(picl_nodehdl_t plafh)
+{
+ logprintf_header(dgettext(TEXT_DOMAIN, "Environmental Status"),
+ DEFAULT_LINE_WIDTH);
+
+ display_fan_speed(plafh);
+ display_temp(plafh);
+ display_current(plafh);
+ display_voltage(plafh);
+ display_keyswitch(plafh);
+ display_led_status(plafh);
+
+ return (PICL_SUCCESS);
+}
+
+/*
+ * print fru operational status
+ */
+static int
+logprintf_fru_oper_status(picl_nodehdl_t fruh, int *countp)
+{
+ int err;
+ char *label;
+ char *status;
+
+ err = picldiag_get_combined_label(fruh, &label, 15);
+ if (err != PICL_SUCCESS)
+ return (PICL_WALK_CONTINUE);
+
+ err = picldiag_get_string_propval(fruh,
+ PICL_PROP_OPERATIONAL_STATUS, &status);
+ if (err == PICL_SUCCESS) {
+ if (*countp == 0) {
+ logprintf_header(dgettext(TEXT_DOMAIN,
+ "FRU Operational Status"),
+ DEFAULT_LINE_WIDTH);
+ log_printf("-------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Fru Operational Status:\n"));
+ log_printf("-------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Location Status \n"));
+ log_printf("-------------------------\n");
+ }
+ *countp += 1;
+ log_printf("%-15s ", label);
+ free(label);
+ log_printf("%s\n", status);
+ free(status);
+ } else if (err != PICL_PROPNOTFOUND && err != PICL_PROPVALUNAVAILABLE) {
+ free(label);
+ return (err);
+ } else {
+ free(label);
+ }
+ return (PICL_WALK_CONTINUE);
+}
+
+static int
+fru_oper_status_callback(picl_nodehdl_t fruh, void *arg)
+{
+ int err;
+
+ err = logprintf_fru_oper_status(fruh, (int *)arg);
+ return (err);
+}
+
+/*
+ * display fru operational status
+ */
+static int
+display_fru_oper_status(picl_nodehdl_t frutreeh)
+{
+ int print_header;
+
+ print_header = 0;
+ picl_walk_tree_by_class(frutreeh, PICL_CLASS_FRU,
+ &print_header, fru_oper_status_callback);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * check if the node having the version prop
+ * If yes, print its nodename and version
+ */
+/* ARGSUSED */
+static int
+asicrev_callback(picl_nodehdl_t nodeh, void *arg)
+{
+ uint32_t version;
+ char *name;
+ char *model;
+ char *status;
+ int err;
+
+ version = picldiag_get_uint_propval(nodeh, OBP_PROP_VERSION_NUM,
+ &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* devfs-path */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_DEVFS_PATH, &name);
+ if (err == PICL_PROPNOTFOUND)
+ name = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* model */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_BINDING_NAME,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* status */
+ err = picldiag_get_string_propval(nodeh, PICL_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND)
+ status = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Display the data
+ */
+
+ /* name */
+ if (name != NULL) {
+ log_printf("%-22s ", name);
+ free(name);
+ } else
+ log_printf("%-22s ", "unknown");
+ /* model */
+ if (model != NULL) {
+ log_printf("%-15s ", model);
+ free(model);
+ } else
+ log_printf("%-15s ", "unknown");
+ /* status */
+ if (status == NULL)
+ log_printf("%-15s ", "okay");
+ else {
+ log_printf("%-15s ", status);
+ free(status);
+ }
+ /* revision */
+ log_printf(" %-4d\n", version);
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * traverse the tree to display asic revision id for ebus
+ */
+/* ARGSUSED */
+static int
+ebus_callback(picl_nodehdl_t ebush, void *arg)
+{
+ uint32_t id;
+ char *name;
+ int err;
+ char *model;
+ char *status;
+
+ id = picldiag_get_uint_propval(ebush, OBP_PROP_REVISION_ID, &err);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_CONTINUE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* devfs-path */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_DEVFS_PATH, &name);
+ if (err == PICL_PROPNOTFOUND)
+ name = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* model */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_BINDING_NAME,
+ &model);
+ if (err == PICL_PROPNOTFOUND)
+ model = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /* status */
+ err = picldiag_get_string_propval(ebush, PICL_PROP_STATUS, &status);
+ if (err == PICL_PROPNOTFOUND)
+ status = NULL;
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * Display the data
+ */
+
+ /* name */
+ if (name != NULL) {
+ log_printf("%-22s ", name);
+ free(name);
+ } else
+ log_printf("%-22s ", "unknown");
+ /* model */
+ if (model != NULL) {
+ log_printf("%-15s ", model);
+ free(model);
+ } else
+ log_printf("%-15s ", "unknown");
+ /* status */
+ if (status == NULL)
+ log_printf("%-15s ", "okay");
+ else {
+ log_printf("%-15s ", status);
+ free(status);
+ }
+ /* revision */
+ log_printf(" %-4d\n", id);
+
+ return (PICL_WALK_CONTINUE);
+}
+
+/*
+ * display asic revision id
+ */
+static int
+display_hw_revisions(picl_nodehdl_t plafh)
+{
+ int err;
+
+ /* Print the header */
+ logprintf_header(dgettext(TEXT_DOMAIN, "HW Revisions"),
+ DEFAULT_LINE_WIDTH);
+
+ log_printf(dgettext(TEXT_DOMAIN, "ASIC Revisions:\n"));
+ log_printf("-----------------------------");
+ log_printf("--------------------------------------\n");
+ log_printf(dgettext(TEXT_DOMAIN, "Path Device"));
+ log_printf(dgettext(TEXT_DOMAIN,
+ " Status Revision\n"));
+ log_printf("-----------------------------");
+ log_printf("--------------------------------------\n");
+
+ err = picl_walk_tree_by_class(plafh, NULL, NULL, asicrev_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_EBUS,
+ NULL, ebus_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf("\n");
+
+ return (err);
+}
+
+/*
+ * find the options node and its powerfail_time prop
+ * If found, display the list of latest powerfail.
+ */
+/* ARGSUSED */
+static int
+options_callback(picl_nodehdl_t nodeh, void *arg)
+{
+ time_t value;
+ char *failtime;
+ int err;
+
+ err = picldiag_get_string_propval(nodeh, PROP_POWERFAIL_TIME,
+ &failtime);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_TERMINATE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ value = (time_t)atoi(failtime);
+ free(failtime);
+ if (value == 0)
+ return (PICL_WALK_TERMINATE);
+
+ log_printf(dgettext(TEXT_DOMAIN, "Most recent AC Power Failure:\n"));
+ log_printf("=============================\n");
+ log_printf("%s", ctime(&value));
+ log_printf("\n");
+ return (PICL_WALK_TERMINATE);
+}
+
+/*
+ * display the OBP and POST prom revisions
+ */
+/* ARGSUSED */
+static int
+flashprom_callback(picl_nodehdl_t flashpromh, void *arg)
+{
+ picl_prophdl_t proph;
+ picl_prophdl_t tblh;
+ picl_prophdl_t rowproph;
+ picl_propinfo_t pinfo;
+ char *prom_version = NULL;
+ char *obp_version = NULL;
+ int err;
+
+ err = picl_get_propinfo_by_name(flashpromh, OBP_PROP_VERSION,
+ &pinfo, &proph);
+ if (err == PICL_PROPNOTFOUND)
+ return (PICL_WALK_TERMINATE);
+ else if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf(dgettext(TEXT_DOMAIN, "System PROM revisions:\n"));
+ log_printf("----------------------\n");
+
+ /*
+ * If it's a table prop, the first element is OBP revision
+ * The second one is POST revision.
+ * If it's a charstring prop, the value will be only OBP revision
+ */
+ if (pinfo.type == PICL_PTYPE_CHARSTRING) {
+ prom_version = alloca(pinfo.size);
+ if (prom_version == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(proph, prom_version, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", prom_version);
+ }
+
+ if (pinfo.type != PICL_PTYPE_TABLE) /* not supported type */
+ return (PICL_WALK_TERMINATE);
+
+ err = picl_get_propval(proph, &tblh, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_get_next_by_row(tblh, &rowproph);
+ if (err == PICL_SUCCESS) {
+ /* get first row */
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ prom_version = alloca(pinfo.size);
+ if (prom_version == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(rowproph, prom_version, pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", prom_version);
+
+ /* get second row */
+ err = picl_get_next_by_col(rowproph, &rowproph);
+ if (err == PICL_SUCCESS) {
+ err = picl_get_propinfo(rowproph, &pinfo);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ obp_version = alloca(pinfo.size);
+ if (obp_version == NULL)
+ return (PICL_FAILURE);
+ err = picl_get_propval(rowproph, obp_version,
+ pinfo.size);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf("%s\n", obp_version);
+ }
+ }
+
+ return (PICL_WALK_TERMINATE);
+}
+
+static int
+display_system_info(int serrlog, int log_flag, picl_nodehdl_t rooth)
+{
+ int err;
+ picl_nodehdl_t plafh;
+ picl_nodehdl_t frutreeh;
+
+ err = picldiag_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ if (!log_flag) {
+ err = display_platform_banner(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_system_clock(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY,
+ PICL_CLASS_MEMORY, memory_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_cpu_info(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_io_device_info(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_memory_config(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_usb_devices(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ if (serrlog) {
+ err = picl_walk_tree_by_class(rooth, PICL_CLASS_OPTIONS,
+ NULL, options_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picldiag_get_node_by_name(rooth, PICL_NODE_FRUTREE,
+ &frutreeh);
+
+ /* return ok if no frutree in picl on schumacher */
+ if (err != PICL_SUCCESS)
+ return (PICL_SUCCESS);
+
+ err = display_fru_oper_status(frutreeh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = display_hw_revisions(plafh);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ err = picl_walk_tree_by_class(plafh, PICL_CLASS_FLASHPROM,
+ NULL, flashprom_callback);
+ if (err != PICL_SUCCESS)
+ return (err);
+ }
+
+ return (PICL_SUCCESS);
+}
+
+/* ARGSUSED */
+int
+do_prominfo(int serrlog, char *pgname, int log_flag, int prt_flag)
+{
+ int err;
+ char *errstr;
+ int done;
+ picl_nodehdl_t rooth;
+
+ err = picl_initialize();
+ if (err != PICL_SUCCESS) {
+ fprintf(stderr, EM_INIT_FAIL, picl_strerror(err));
+ exit(1);
+ }
+
+ do {
+ done = 1;
+ err = picl_get_root(&rooth);
+ if (err != PICL_SUCCESS) {
+ fprintf(stderr, EM_GET_ROOT_FAIL, picl_strerror(err));
+ exit(1);
+ }
+
+ err = display_system_info(serrlog, log_flag, rooth);
+
+ if ((err == PICL_STALEHANDLE) || (err == PICL_INVALIDHANDLE))
+ done = 0;
+ } while (!done);
+
+ if (err != PICL_SUCCESS) {
+ errstr = picl_strerror(err);
+ fprintf(stderr, EM_PRTDIAG_FAIL);
+ fprintf(stderr, "%s\n", errstr? errstr : " ");
+ }
+
+ (void) picl_shutdown();
+
+ return (0);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/schumacher/picl/Makefile b/usr/src/lib/libprtdiag_psr/sparc/schumacher/picl/Makefile
new file mode 100644
index 0000000000..9ab6ff4330
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/schumacher/picl/Makefile
@@ -0,0 +1,89 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/schumacher/picl/Makefile
+
+UTSBASE = $(SRC)/uts
+
+PLATFORM_OBJECTS= schumacher.o
+
+objs/%.o pics/%.o: ../common/%.c
+ $(COMPILE.c) $(IFLAGS) -o $@ $<
+ $(POST_PROCESS_O)
+
+include $(SRC)/lib/libprtdiag_psr/sparc/Makefile.com
+
+SRCS= $(OBJECTS:%.o=../common/%.c)
+
+LDLIBS += -lpicl
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../../libprtdiag/inc
+IFLAGS += -I$(SRC)/cmd/picl/plugins/inc
+LINTFLAGS += $(IFLAGS)
+
+PLATFORM= SUNW,Netra-CP3010
+
+.KEEP_STATE:
+
+PLATLIBS= $(PLATFORM:%=$(USR_PLAT_DIR)/%/lib/)
+
+install: all $(PLATLIBS) $(USR_PSM_LIBS) \
+ $(LINKED_PRTDIAG_DIRS)
+
+#
+# install rules for /usr/platform/${PLATFORM}/lib/libprtdiag_psr.so.1
+#
+$(PLATLIBS):
+ $(INS.dir)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(USR_PSM_LIB_DIR):
+ $(INS.dir)
+
+$(LINKED_DIRS): $(USR_PLAT_DIR)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIB_DIRS): $(LINKED_DIRS)
+ -$(INS.dir.root.sys)
+
+$(LINKED_PRTDIAG_DIRS): $(USR_PLAT_DIR)
+ -$(INS.slink6)
+
+#
+# Rules for making message files
+#
+
+MSGFILES= ../common/schumacher.c
+POFILE= libprtdiag_psr_schumacher_picl.po
+
+$(POFILE): pofile_MSGFILES
+
+_msg: $(MSGDOMAINPOFILE)
+
+include $(SRC)/Makefile.msg.targ
+
diff --git a/usr/src/lib/libprtdiag_psr/sparc/serengeti/Makefile b/usr/src/lib/libprtdiag_psr/sparc/serengeti/Makefile
new file mode 100644
index 0000000000..011a74efcd
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/serengeti/Makefile
@@ -0,0 +1,78 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/serengeti/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= serengeti.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+IFLAGS += -I$(UTSBASE)/sun4u/serengeti
+IFLAGS += -I$(UTSBASE)/sun4u
+LINTFLAGS += $(IFLAGS)
+
+LDLIBS += -lcfgadm
+
+PLATFORM=SUNW,Sun-Fire
+
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/serengeti; $(MAKE) $(USR_PSM_LIB_DIR)
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+#
+# used for message files
+#
+POFILE= libprtdiag_psr_serengeti.po
+POFILES= serengeti.po
+
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/serengeti.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/serengeti/common/serengeti.c b/usr/src/lib/libprtdiag_psr/sparc/serengeti/common/serengeti.c
new file mode 100644
index 0000000000..63a8c36092
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/serengeti/common/serengeti.c
@@ -0,0 +1,2113 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Serengeti Platform specific functions.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <string.h>
+#include <assert.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <fcntl.h>
+#include <varargs.h>
+
+#include <sys/openpromio.h>
+#include <sys/sysmacros.h>
+
+#include <sys/serengeti.h>
+#include <sys/sgfrutypes.h>
+
+#include <pdevinfo.h>
+#include <display.h>
+#include <pdevinfo_sun4u.h>
+#include <display_sun4u.h>
+#include <libprtdiag.h>
+
+#include <config_admin.h>
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+#define SCHIZO_COMPATIBLE "pci108e,8001"
+#define XMITS_COMPATIBLE "pci108e,8002"
+
+#define ACTIVE 0
+#define INACTIVE 1
+#define DISPLAY_INFO 40
+
+#define EVNT2STR(e) ((e) == CFGA_STAT_NONE ? "none" : \
+ (e) == CFGA_STAT_EMPTY ? "empty" : \
+ (e) == CFGA_STAT_DISCONNECTED ? "disconnected" : \
+ (e) == CFGA_STAT_CONNECTED ? "connected" : \
+ (e) == CFGA_STAT_UNCONFIGURED ? "unconfigured" : \
+ (e) == CFGA_STAT_CONFIGURED ? "configured" : \
+ "unknown")
+
+#define COND2STR(c) ((c) == CFGA_COND_UNKNOWN ? "unknown" : \
+ (c) == CFGA_COND_OK ? "ok" : \
+ (c) == CFGA_COND_FAILING ? "failing" : \
+ (c) == CFGA_COND_FAILED ? "failed" : \
+ (c) == CFGA_COND_UNUSABLE ? "unusable" : \
+ "???")
+
+#define SG_CLK_FREQ_TO_MHZ(x) (((x) + 500000) / 1000000)
+
+#define MAX_STATUS_LEN 8
+#define SG_FAIL "fail"
+#define SG_DISABLED "disabled"
+#define SG_DEGRADED "degraded"
+#define SG_OK "ok"
+
+#define SG_SCHIZO_FAILED 1
+#define SG_SCHIZO_GOOD 0
+
+#define DEFAULT_MAX_FREQ 66 /* 66 MHz */
+#define PCIX_MAX_FREQ 100 /* 100 MHz */
+
+#define CFG_CPU "::cpu"
+
+#define CFG_SET_FRU_NAME_NODE(str, num) \
+{ \
+ char tmp_str[MAX_FRU_NAME_LEN]; \
+ sprintf(tmp_str, "/N%d", num); \
+ strncat(str, tmp_str, sizeof (tmp_str)); \
+}
+
+#define CFG_SET_FRU_NAME_CPU_BOARD(str, num) \
+{ \
+ char tmp_str[MAX_FRU_NAME_LEN]; \
+ sprintf(tmp_str, ".%s%d", SG_HPU_TYPE_CPU_BOARD_ID, num); \
+ strncat(str, tmp_str, sizeof (tmp_str)); \
+}
+
+#define CFG_SET_FRU_NAME_MODULE(str, num) \
+{ \
+ char tmp_str[MAX_FRU_NAME_LEN]; \
+ sprintf(tmp_str, "%s%d", CFG_CPU, num); \
+ strncat(str, tmp_str, sizeof (tmp_str)); \
+}
+
+extern int print_flag;
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (Serengeti systems only)
+ */
+int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
+void *get_prop_val(Prop *prop);
+Prop *find_prop(Prom_node *pnode, char *name);
+char *get_node_name(Prom_node *pnode);
+char *get_node_type(Prom_node *pnode);
+void add_node(Sys_tree *, Prom_node *);
+void display_pci(Board_node *);
+void display_ffb(Board_node *, int);
+void display_io_cards(struct io_card *list);
+void display_cpu_devices(Sys_tree *tree);
+void display_cpus(Board_node *board);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
+void get_failed_parts(void);
+int display_failed_parts(Sys_tree *tree);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
+
+/* Local Functions */
+static void serengeti_display_hw_revisions(Prom_node *root,
+ Board_node *bnode);
+static Board_node *serengeti_find_board(Sys_tree *root, int board, int nodeid);
+static Board_node *serengeti_insert_board(Sys_tree *root, int board, int nid);
+static int display_schizo_revisions(Board_node *bdlist, int mode);
+static void display_sgsbbc_revisions(Board_node *bdlist);
+static void serengeti_display_board_info(int state);
+static void serengeti_display_board_info_header(int state);
+static boolean_t cpu_node_configured(char *const node);
+static void display_io_max_bus_speed(struct io_card *p);
+static void display_io_slot_info(struct io_card *p);
+static void get_slot_name(struct io_card *card, char *slot_name);
+
+/* The bus max freq is determined based on board level in use */
+int board_bus_max_freq = DEFAULT_MAX_FREQ; /* 66MHz default */
+
+/*
+ * Serengeti now uses both the devinfo tree and the OBP tree for it's
+ * prtdiag. The devinfo tree is used for getting the HW config of the
+ * system and the OBP device tree is used for listing the failed HW
+ * in the system. This is because devinfo currently does not include
+ * any PROM nodes with a status of 'fail' so we need to go to OBP to
+ * get a list of failed HW. We use the tree flag to allow the same code
+ * to walk both trees.
+ *
+ * We really need to look at having a single tree for all platforms!
+ */
+#define DEVINFO_TREE 1
+#define OBP_TREE 2
+
+static int tree = DEVINFO_TREE;
+
+#ifdef DEBUG
+#define D_PRINTFINDENT printfindent
+void
+printfindent(int indent, char *fmt, ...)
+{
+ va_list ap;
+ int i = 0;
+ for (i = 0; i < indent; i ++)
+ printf("\t");
+
+ va_start(ap);
+ (void) vprintf(fmt, ap);
+ va_end(ap);
+}
+#else
+#define D_PRINTFINDENT
+#endif
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+void
+display_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+ Prom_node *pci;
+ Prom_node *card_node;
+ Prom_node *pci_bridge_node;
+ Prom_node *child_pci_bridge_node;
+ char *slot_name = NULL; /* info in "slot-names" prop */
+ char *child_name;
+ char *name, *type;
+ char *pname, *ptype;
+ char buf[MAXSTRLEN];
+ int *int_val;
+ int pci_bus;
+ int pci_bridge = 0;
+ int pci_bridge_dev_no;
+ char *slot_name_arr[SG_MAX_SLOTS_PER_IO_BD] = {NULL};
+ int i;
+ int portid;
+ int level = 0;
+ int version, *pversion;
+#ifdef DEBUG
+ int slot_name_bits;
+#endif
+
+ if (board == NULL)
+ return;
+
+ /* Initialize all the common information */
+ card.display = TRUE;
+ card.board = board->board_num;
+ card.node_id = board->node_id;
+
+ /*
+ * Search for each schizo and xmits, then find/display all nodes under
+ * each schizo and xmits node found.
+ */
+ for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
+ pci != NULL;
+ pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
+
+ /* set max freq for this board */
+ board_bus_max_freq = DEFAULT_MAX_FREQ;
+ /*
+ * Find out if this is a PCI or cPCI IO Board.
+ * If "enum-impl" property exists in pci node => cPCI.
+ */
+ value = get_prop_val(find_prop(pci, "enum-impl"));
+ if (value == NULL) {
+ (void) sprintf(card.bus_type, "PCI");
+ } else {
+ (void) sprintf(card.bus_type, "cPCI");
+ }
+
+ if (strstr((char *)get_prop_val(
+ find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
+ sprintf(card.notes, "%s", XMITS_COMPATIBLE);
+ /*
+ * With XMITS 3.X and PCI-X mode, the bus speed
+ * can be higher than 66MHZ.
+ */
+ value = (int *)get_prop_val
+ (find_prop(pci, "module-revision#"));
+ if (value) {
+ pversion = (int *)value;
+ version = *pversion;
+ if (version >= 4)
+ board_bus_max_freq = PCIX_MAX_FREQ;
+ }
+ } else if (strstr((char *)get_prop_val(
+ find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
+ sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
+ else
+ sprintf(card.notes, " ");
+
+ /*
+ * Get slot-name properties from parent node and
+ * store them in an array.
+ */
+ value = (char *)get_prop_val(find_prop(pci, "slot-names"));
+ if (value != NULL) {
+#ifdef DEBUG
+ /* save the 4 byte bitmask */
+ slot_name_bits = *(int *)value;
+#endif
+ /* array starts after first int */
+ slot_name_arr[0] = (char *)value + sizeof (int);
+
+ D_PRINTFINDENT(0, "slot_name_arr[0] is [%s]\n",
+ slot_name_arr[0]);
+
+ for (i = 1; i < SG_MAX_SLOTS_PER_IO_BD; i++) {
+ slot_name_arr[i] = (char *)slot_name_arr[i - 1]
+ + strlen(slot_name_arr[i - 1]) +1;
+
+ D_PRINTFINDENT(0, "slot_name_arr[%d] is [%s]\n", i,
+ slot_name_arr[i]);
+
+ }
+ }
+
+ /*
+ * Search for Children of this node ie. Cards.
+ * Note: any of these cards can be a pci-bridge
+ * that itself has children. If we find a
+ * pci-bridge we need to handle it specially.
+ *
+ * There can now be the condition of a pci-bridge
+ * being the child of a pci-bridge which create a
+ * two levels of pci-bridges. This special condition
+ * needs to be handled as well. The variable level
+ * is used to track the depth of the tree. This
+ * variable is then used to find instances of this case.
+ */
+ level = 0;
+ card_node = pci->child;
+ while (card_node != NULL) {
+ pci_bridge = 0;
+
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(card_node, "name"));
+ if (name == NULL) {
+ card_node = card_node->sibling;
+ continue;
+ }
+ D_PRINTFINDENT(level, "NAME is %s\n", name);
+
+ type = (char *)get_prop_val(
+ find_prop(card_node, "device_type"));
+
+ /*
+ * get dev# and func# for this card from the
+ * 'reg' property.
+ */
+ int_val = (int *)get_prop_val(
+ find_prop(card_node, "reg"));
+ if (int_val != NULL) {
+ card.dev_no = (((*int_val) & 0xF800) >> 11);
+ card.func_no = (((*int_val) & 0x700) >> 8);
+ } else {
+ card.dev_no = -1;
+ card.func_no = -1;
+ }
+
+ /*
+ * If this is a pci-bridge, then store it's dev#
+ * as it's children nodes need this to get their slot#.
+ * We set the pci_bridge flag so that we know we are
+ * looking at a pci-bridge node. This flag gets reset
+ * every time we enter this while loop.
+ */
+
+ /*
+ * Check for a PCI-PCI Bridge for PCI and cPCI
+ * IO Boards using the name and type properties.
+ *
+ * If level is greater then 0, then check the parent
+ * node to see if it was also a pci-bridge. We do not
+ * this when level is 0 as this will see the schizo or
+ * xmits device as a pci-bridge node. This will mess
+ * up the slot number of child nodes.
+ */
+ if ((type != NULL) &&
+ (strncmp(name, "pci", 3) == 0) &&
+ (strcmp(type, "pci") == 0)) {
+ if (level > 0) {
+ pname = (char *)get_prop_val(
+ find_prop(card_node->parent, "name"));
+ ptype = (char *)get_prop_val(
+ find_prop(card_node->parent,
+ "device_type"));
+
+ if ((ptype != NULL) && (pname != NULL) &&
+ (strncmp(pname, "pci", 3) == 0) &&
+ (strcmp(ptype, "pci") == 0)) {
+ child_pci_bridge_node = card_node;
+ } else {
+ pci_bridge_dev_no = card.dev_no;
+ pci_bridge_node = card_node;
+ }
+ } else {
+ pci_bridge_dev_no = card.dev_no;
+ pci_bridge_node = card_node;
+ }
+ pci_bridge = TRUE;
+
+ D_PRINTFINDENT(level,
+ "pci_bridge_dev_no is [%d]\n",
+ pci_bridge_dev_no);
+ }
+
+ /*
+ * Get slot-names property from slot_names_arr.
+ * If we are the child of a pci_bridge we use the
+ * dev# of the pci_bridge as an index to get
+ * the slot number. We know that we are a child of
+ * a pci-bridge if our parent is the same as the last
+ * pci_bridge node found above.
+ */
+ if (type)
+ D_PRINTFINDENT(level,
+ "*** name is [%s] - type is [%s]\n",
+ name, type);
+ else
+ D_PRINTFINDENT(level,
+ "*** name is [%s]\n", name);
+
+ if (card.dev_no != -1) {
+ /*
+ * We compare this cards parent node with the
+ * pci_bridge_node to see if it's a child.
+ */
+ if (((level > 0) &&
+ (card_node->parent->parent ==
+ pci_bridge_node)) ||
+ (card_node->parent == pci_bridge_node)) {
+ /* use dev_no of pci_bridge */
+ D_PRINTFINDENT(level,
+ " pci_bridge_dev_no is [%d]\n",
+ pci_bridge_dev_no);
+
+ slot_name =
+ slot_name_arr[pci_bridge_dev_no -1];
+ } else {
+ /* use cards own dev_no */
+ D_PRINTFINDENT(level,
+ " card.dev_no is [%d]\n",
+ card.dev_no);
+
+ slot_name =
+ slot_name_arr[card.dev_no - 1];
+ }
+
+ get_slot_name(&card, slot_name);
+
+ } else {
+ (void) sprintf(card.slot_str, "%c", '-');
+ }
+
+ /*
+ * Get the portid of the schizo and xmits that this card
+ * lives under.
+ */
+ portid = -1;
+ value = get_prop_val(find_prop(pci, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+ card.schizo_portid = portid;
+
+#ifdef DEBUG
+ (void) sprintf(card.notes, "%s portid [%d] dev_no[%d]"
+ " slot_name[%s] name_bits[%d]",
+ card.notes,
+ portid,
+ card.dev_no, slot_name,
+ slot_name_bits);
+#endif
+
+ /*
+ * Find out whether this is PCI bus A or B
+ * using the 'reg' property.
+ */
+ int_val = (int *)get_prop_val
+ (find_prop(pci, "reg"));
+
+ if (int_val != NULL) {
+ int_val ++; /* skip over first integer */
+ pci_bus = ((*int_val) & 0x7f0000);
+ if (pci_bus == 0x600000)
+ card.pci_bus = 'A';
+ else if (pci_bus == 0x700000)
+ card.pci_bus = 'B';
+ else
+ card.pci_bus = '-';
+ } else {
+ card.pci_bus = '-';
+ }
+
+
+ /*
+ * Check for failed status.
+ */
+ if (node_status(card_node, SG_FAIL))
+ strncpy(card.status, SG_FAIL,
+ sizeof (SG_FAIL));
+ else if (node_status(card_node, SG_DISABLED))
+ strncpy(card.status, SG_DISABLED,
+ sizeof (SG_DISABLED));
+ else
+ strncpy(card.status, SG_OK,
+ sizeof (SG_OK));
+
+ /* Get the model of this card */
+ value = get_prop_val(find_prop(card_node, "model"));
+ if (value == NULL)
+ card.model[0] = '\0';
+ else {
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+ /* Skip sgsbbc nodes, they are not cards */
+ if (strcmp(card.model, "SUNW,sgsbbc") == 0) {
+ card_node = card_node->sibling;
+ continue;
+ }
+ }
+
+ /*
+ * Check if further processing is necessary to display
+ * this card uniquely.
+ */
+ distinguish_identical_io_cards(name, card_node, &card);
+
+ /*
+ * The card may have a "clock-frequency" but we
+ * are not interested in that. Instead we get the
+ * "clock-frequency" of the PCI Bus that the card
+ * resides on. PCI-A can operate at 33Mhz or 66Mhz
+ * depending on what card is plugged into the Bus.
+ * PCI-B always operates at 33Mhz.
+ *
+ */
+ int_val = get_prop_val(find_prop(pci,
+ "clock-frequency"));
+ if (int_val != NULL) {
+ card.freq = SG_CLK_FREQ_TO_MHZ(*int_val);
+ } else {
+ card.freq = -1;
+ }
+
+ /*
+ * Figure out how we want to display the name
+ */
+ value = get_prop_val(find_prop(card_node,
+ "compatible"));
+ if (value != NULL) {
+ /* use 'name'-'compatible' */
+ (void) sprintf(buf, "%s-%s", name,
+ (char *)value);
+ } else {
+ /* just use 'name' */
+ (void) sprintf(buf, "%s", name);
+ }
+ name = buf;
+
+ /*
+ * If this node has children, add the device_type
+ * of the child to the name value of this card.
+ */
+ child_name = (char *)get_node_name(card_node->child);
+ if ((card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(card_node->child,
+ "device_type"));
+ if (value != NULL) {
+ /* add device_type of child to name */
+ (void) sprintf(card.name, "%s/%s (%s)",
+ name, child_name,
+ (char *)value);
+ } else {
+ /* just add childs name */
+ (void) sprintf(card.name, "%s/%s", name,
+ child_name);
+ }
+ } else {
+ (void) sprintf(card.name, "%s", (char *)name);
+ }
+
+ /*
+ * If this is a pci-bridge, then add the word
+ * 'pci-bridge' to it's model.
+ */
+ if (pci_bridge) {
+ if (strlen(card.model) == 0)
+ (void) sprintf(card.model,
+ "%s", "pci-bridge");
+ else
+ (void) sprintf(card.model,
+ "%s/pci-bridge", card.model);
+ }
+
+ /* insert this card in the list to be displayed later */
+ card_list = insert_io_card(card_list, &card);
+
+ /*
+ * If we are dealing with a pci-bridge, we need to move
+ * down to the children of this bridge if there are any.
+ *
+ * If we are not, we are either dealing with a regular
+ * card (in which case we move onto the sibling of this
+ * card) or we are dealing with a child of a pci-bridge
+ * (in which case we move onto the child's siblings or
+ * if there are no more siblings for this child, we
+ * move onto the parents siblings).
+ *
+ * Once we reach the last child node of a pci-bridge,
+ * we need to back up the tree to the parents sibling
+ * node. If our parent has no more siblings, we need
+ * to check our grand parent for siblings.
+ *
+ * If we have no more siblings, we simply point to
+ * to the child's sibling which moves us onto the next
+ * bus leaf.
+ *
+ * The variable level gets adjusted on some of the
+ * conditions as this is used to track level within
+ * the tree we have reached.
+ */
+ if (pci_bridge) {
+ if (card_node->child != NULL) {
+ level++;
+ card_node = card_node->child;
+ } else
+ card_node = card_node->sibling;
+ } else {
+ if ((card_node->parent == pci_bridge_node) &&
+ (card_node->sibling == NULL)) {
+ card_node = pci_bridge_node->sibling;
+ if (level > 0)
+ level--;
+ } else if ((card_node->parent ==
+ child_pci_bridge_node) &&
+ (card_node->parent->parent ==
+ pci_bridge_node)) {
+ if ((child_pci_bridge_node->sibling) &&
+ (card_node->sibling == NULL)) {
+ card_node =
+ child_pci_bridge_node->sibling;
+ if (level > 0)
+ level--;
+ } else if ((pci_bridge_node->sibling) &&
+ (card_node->sibling == NULL)) {
+ card_node =
+ pci_bridge_node->sibling;
+ if (level > 1)
+ level = level - 2;
+ else if (level > 0)
+ level--;
+ } else
+ card_node = card_node->sibling;
+ } else
+ card_node = card_node->sibling;
+ }
+ } /* end-while */
+ } /* end-for */
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+/*
+ * display_ffb
+ *
+ * There are no FFB's on a Serengeti, however in the generic library,
+ * the display_ffb() function is implemented so we have to define an
+ * empty function here.
+ */
+/*ARGSUSED0*/
+void
+display_ffb(Board_node *board, int table)
+{}
+
+static void
+serengeti_display_board_info_header(int state)
+{
+ char *fmt = "%-9s %-11s %-12s %-12s %-9s %-40s\n";
+
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ if (state == ACTIVE)
+ log_printf(dgettext(TEXT_DOMAIN,
+ " Active Boards for Domain "), 0);
+ else
+ log_printf(dgettext(TEXT_DOMAIN,
+ " Available Boards/Slots for Domain "), 0);
+ log_printf("===========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ log_printf(fmt, "", "Board", "Receptacle", "Occupant", "", "", 0);
+
+ log_printf(fmt, "FRU Name", "Type", "Status", "Status",
+ "Condition", "Info", 0);
+
+ log_printf(fmt, "---------", "-----------", "-----------",
+ "------------", "---------",
+ "----------------------------------------", 0);
+}
+
+static void
+serengeti_display_board_info(int state)
+{
+ int i, z, ret;
+ int nlist = 0;
+ int available_board_count = 0;
+ struct cfga_list_data *board_cfg = NULL;
+ char *err_string = NULL;
+ char tmp_id[CFGA_LOG_EXT_LEN + 1];
+ char tmp_info[DISPLAY_INFO + 1];
+ const char listops[] = "class=sbd";
+ struct cfga_list_data dat;
+ cfga_flags_t flags = NULL;
+
+ ret = config_list_ext(0, NULL, &board_cfg, &nlist,
+ NULL, listops,
+ &err_string, flags);
+
+ if (ret == CFGA_OK) {
+ serengeti_display_board_info_header(state);
+ for (i = 0; i < nlist; i++) {
+ dat = board_cfg[i];
+
+ if ((state != ACTIVE) &&
+ (dat.ap_o_state == CFGA_STAT_CONFIGURED))
+ continue;
+ else if ((state == ACTIVE) &&
+ (dat.ap_o_state != CFGA_STAT_CONFIGURED))
+ continue;
+ if (state == INACTIVE)
+ available_board_count++;
+
+ memcpy(tmp_id, dat.ap_log_id, CFGA_LOG_EXT_LEN);
+ tmp_id[CFGA_LOG_EXT_LEN] = '\0';
+ for (z = 0; z < strlen(tmp_id); z++) {
+ if (tmp_id[z] == '.')
+ tmp_id[z] = '/';
+ }
+ log_printf("/%-8s ", tmp_id, 0);
+ log_printf("%-11s ", dat.ap_type, 0);
+
+ log_printf("%-12s ", EVNT2STR(dat.ap_r_state), 0);
+ log_printf("%-12s ", EVNT2STR(dat.ap_o_state), 0);
+ log_printf("%-8s ", COND2STR(dat.ap_cond), 0);
+
+ memcpy(tmp_info, dat.ap_info, DISPLAY_INFO);
+ tmp_info[DISPLAY_INFO - 1] = '\0';
+ if (strlen(tmp_info) >= (DISPLAY_INFO - 1))
+ tmp_info[DISPLAY_INFO - 2] = '+';
+ log_printf("%-*s\n", (DISPLAY_INFO - 1), tmp_info, 0);
+ }
+ if ((state == INACTIVE) &&
+ (available_board_count == 0)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "There are currently no "
+ "Boards/Slots available "
+ "to this Domain\n"), 0);
+ }
+ }
+ if (board_cfg)
+ free(board_cfg);
+ if (err_string)
+ free(err_string);
+}
+
+/*
+ * add_node
+ *
+ * This function adds a board node to the board structure where that
+ * that node's physical component lives.
+ */
+void
+add_node(Sys_tree *root, Prom_node *pnode)
+{
+ int board = -1;
+ int portid = -1;
+ int nodeid = -1;
+
+ void *value = NULL;
+ Board_node *bnode = NULL;
+ Prom_node *p = NULL;
+ char *type;
+
+ /* Get the board number of this board from the portid prop */
+ if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
+ if ((type = get_node_type(pnode)) && (strcmp(type, "cpu") == 0))
+ value =
+ get_prop_val(find_prop(pnode->parent, "portid"));
+ }
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+
+ nodeid = SG_PORTID_TO_NODEID(portid);
+ board = SG_PORTID_TO_BOARD_NUM(portid);
+
+ /* find the board node with the same board number */
+ if ((bnode = serengeti_find_board(root, board, nodeid)) == NULL) {
+ bnode = serengeti_insert_board(root, board, nodeid);
+ }
+
+ /* now attach this prom node to the board list */
+ /* Insert this node at the end of the list */
+ pnode->sibling = NULL;
+ if (bnode->nodes == NULL)
+ bnode->nodes = pnode;
+ else {
+ p = bnode->nodes;
+ while (p->sibling != NULL)
+ p = p->sibling;
+ p->sibling = pnode;
+ }
+}
+
+
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ char *fmt = "%-10s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-4s %-34s";
+
+ static int banner = FALSE; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == FALSE) {
+ log_printf(fmt, "", "", "", "", "", "Bus", "Max",
+ "", "", "", 0);
+ log_printf("\n", 0);
+ log_printf(fmt, "", "IO", "Port", "Bus", "", "Freq", "Bus",
+ "Dev,", "", "", 0);
+ log_printf("\n", 0);
+ log_printf(fmt, "FRU Name", "Type", " ID", "Side", "Slot",
+ "MHz", "Freq", "Func", "State", "Name", 0);
+#ifdef DEBUG
+ log_printf("Model Notes\n", 0);
+#else
+ log_printf("Model\n", 0);
+#endif
+
+ log_printf(fmt, "----------", "----", "----", "----", "----",
+ "----", "----", "----", "-----",
+ "--------------------------------", 0);
+#ifdef DEBUG
+ log_printf("---------------------- ", 0);
+#endif
+ log_printf("----------------------\n", 0);
+ banner = TRUE;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+
+ display_io_slot_info(p);
+
+ display_io_max_bus_speed(p);
+
+ log_printf("\n", 0);
+ }
+}
+
+static void
+display_io_slot_info(struct io_card *p)
+{
+ char fru_name[MAX_FRU_NAME_LEN] = "";
+
+ SG_SET_FRU_NAME_NODE(fru_name, p->node_id);
+ SG_SET_FRU_NAME_IO_BOARD(fru_name, p->board);
+ SG_SET_FRU_NAME_MODULE(fru_name, p->schizo_portid % 2);
+
+ log_printf("%-8s ", fru_name, 0);
+ log_printf("%-4s ", p->bus_type, 0);
+ log_printf("%-3d ", p->schizo_portid, 0);
+ log_printf("%c ", p->pci_bus, 0);
+ log_printf("%-1s ", p->slot_str, 0);
+ log_printf("%-3d ", p->freq, 0);
+}
+
+#define BUS_SPEED_PRINT(speed) log_printf(" %d ", speed, 0)
+
+static void
+display_io_max_bus_speed(struct io_card *p)
+{
+ int speed = board_bus_max_freq;
+
+ switch (p->pci_bus) {
+ case 'A':
+ BUS_SPEED_PRINT(speed);
+ break;
+ case 'B':
+ if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
+ if ((strncmp(p->slot_str, "1", 1) == 0) ||
+ (strncmp(p->slot_str, "0", 1) == 0))
+ BUS_SPEED_PRINT(33);
+ else
+ BUS_SPEED_PRINT(speed);
+ } else
+ BUS_SPEED_PRINT(33);
+ break;
+ default:
+ log_printf(" - ", 0);
+ break;
+ }
+
+ log_printf("%-1d,%-1d ", p->dev_no, p->func_no, 0);
+ log_printf("%-5s ", p->status, 0);
+
+ log_printf("%-32.32s%c ", p->name,
+ ((strlen(p->name) > 32) ? '+' : ' '), 0);
+ log_printf("%-22.22s%c", p->model,
+ ((strlen(p->model) > 22) ? '+' : ' '), 0);
+#ifdef DEBUG
+ log_printf(" %s", p->notes, 0);
+#endif /* DEBUG */
+}
+
+void
+display_cpu_devices(Sys_tree *tree)
+{
+ Board_node *bnode;
+
+ /* printf formats */
+ char *fmt1 = "%-10s %-7s %-4s %-4s %-7s %-4s\n";
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision of all cpus.
+ */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(" CPUs ", 0);
+ log_printf("=========================", 0);
+ log_printf("======================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ log_printf(fmt1, "", "CPU ", "Run", " E$", "CPU", "CPU", 0);
+
+ log_printf(fmt1, "FRU Name", "ID ", "MHz", " MB",
+ "Impl.", "Mask", 0);
+
+ log_printf(fmt1, "----------", "-------", "----", "----",
+ "-------", "----", 0);
+
+ /* Now display all of the cpus on each board */
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ display_cpus(bnode);
+ bnode = bnode->next;
+ }
+
+ log_printf("\n", 0);
+}
+
+static boolean_t
+cpu_node_configured(char *const node)
+{
+ int ret, i;
+ int nlist = 0;
+ boolean_t rv;
+ char *err_string = NULL;
+ char *const *ap_args = NULL;
+ struct cfga_list_data *statlist = NULL;
+ struct cfga_list_data dat;
+ cfga_flags_t flags = CFGA_FLAG_LIST_ALL;
+
+ if (node == NULL)
+ return (FALSE);
+
+ ap_args = &node;
+ ret = config_list_ext(1, &node, &statlist, &nlist,
+ NULL, NULL, &err_string, flags);
+
+ if (ret == CFGA_OK) {
+ dat = statlist[0];
+
+ if (dat.ap_o_state == CFGA_STAT_CONFIGURED)
+ rv = TRUE;
+ else
+ rv = FALSE;
+ } else {
+ rv = FALSE;
+ }
+ if (statlist)
+ free(statlist);
+ if (err_string)
+ free(err_string);
+ return (rv);
+}
+
+/*
+ * Display the CPUs present on this board.
+ */
+void
+display_cpus(Board_node *board)
+{
+ Prom_node *cpu;
+ int freq; /* CPU clock frequency */
+ int ecache_size; /* External cache size */
+ int board_num = board->board_num;
+ int *mid;
+ int *impl;
+ int *mask;
+ int decoded_mask;
+ int *coreid;
+ int mid_prev = -1;
+ int ecache_size_prev = 0;
+ char fru_prev[MAX_FRU_NAME_LEN] = "";
+
+ /*
+ * display the CPUs' operating frequency, cache size, impl. field
+ * and mask revision.
+ */
+ for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
+ cpu = dev_next_type(cpu, "cpu")) {
+ char fru_name[MAX_FRU_NAME_LEN] = "";
+ char cfg_fru_name[MAX_FRU_NAME_LEN] = "";
+
+ mid = (int *)get_prop_val(find_prop(cpu, "portid"));
+ if (mid == NULL)
+ mid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
+ freq = SG_CLK_FREQ_TO_MHZ(get_cpu_freq(cpu));
+ ecache_size = get_ecache_size(cpu);
+ impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
+ mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
+
+ /* Do not display a failed CPU node */
+ if ((impl == NULL) || (freq == 0) || (node_failed(cpu)))
+ continue;
+
+ /* FRU Name */
+ SG_SET_FRU_NAME_NODE(fru_name, board->node_id);
+
+ SG_SET_FRU_NAME_CPU_BOARD(fru_name, board_num);
+ SG_SET_FRU_NAME_MODULE(fru_name, *mid % 4);
+
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ coreid = (int *)get_prop_val(find_prop(cpu,
+ "reg"));
+ if (coreid == NULL) {
+ continue;
+ }
+
+ /*
+ * The assumption is made that 2 cores will always be
+ * listed together in the device tree. If either core
+ * is "bad" then the FRU will not be listed.
+ *
+ * As display_cpus on Serengeti does actually process
+ * all cpu's per board a copy of the fru_name needs to
+ * be made as the following core may not be its
+ * sibling. If this is the case it is assumed that a
+ * sibling core has failed, so the fru should not be
+ * displayed.
+ *
+ * For the first instance of a core, fru_prev is
+ * expected to be empty. The current values are then
+ * stored and the next board->nodes is processed. If
+ * this is a sibling core, the ecache size it tallied
+ * and the previous value reset and processing
+ * continues.
+ *
+ * If the following core is not a sibling, the new
+ * values are stored and the next board->nodes is
+ * processed.
+ */
+ if (strncmp(fru_prev, "", sizeof (fru_prev)) == 0) {
+ strncpy(fru_prev, fru_name, sizeof (fru_name));
+ mid_prev = *mid;
+ ecache_size_prev = ecache_size;
+ continue;
+ } else {
+ if (strncmp(fru_name, fru_prev,
+ sizeof (fru_prev)) == 0) {
+ /*
+ * Jaguar has a split E$, so the size
+ * for both cores must be added together
+ * to get the total size for the entire
+ * chip.
+ *
+ * Panther E$ (L3) is logically shared,
+ * so the total size is equal to the
+ * core size.
+ */
+ if (IS_JAGUAR(*impl)) {
+ ecache_size += ecache_size_prev;
+ }
+
+ ecache_size_prev = 0;
+ strncpy(fru_prev, "",
+ sizeof (fru_prev));
+ } else {
+ mid_prev = *mid;
+ ecache_size_prev = ecache_size;
+ strncpy(fru_prev, fru_name,
+ sizeof (fru_name));
+ continue;
+ }
+ }
+ }
+
+ /*
+ * If cpu is not configured, do not display it
+ */
+ CFG_SET_FRU_NAME_NODE(cfg_fru_name, board->node_id);
+ CFG_SET_FRU_NAME_CPU_BOARD(cfg_fru_name, board_num);
+ CFG_SET_FRU_NAME_MODULE(cfg_fru_name, *mid % 4);
+
+ if (!(cpu_node_configured(cfg_fru_name))) {
+ continue;
+ }
+
+
+ log_printf("%-10s ", fru_name, 0);
+
+ /* CPU MID */
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ log_printf("%3d,%3d ", mid_prev, *mid, 0);
+ mid_prev = -1;
+ } else
+ log_printf("%3d ", *mid, 0);
+
+ /* Running frequency */
+ log_printf(" %4d ", freq, 0);
+
+ /* Ecache size */
+ if (ecache_size == 0)
+ log_printf("%3s ", "N/A", 0);
+ else
+ log_printf("%4.1f ",
+ (float)ecache_size / (float)(1<<20),
+ 0);
+
+ /* Implementation */
+ if (impl == NULL) {
+ log_printf("%6s ", " N/A", 0);
+ } else {
+ switch (*impl) {
+ case CHEETAH_IMPL:
+ log_printf("%-7s ", "US-III", 0);
+ break;
+ case CHEETAH_PLUS_IMPL:
+ log_printf("%-7s ", "US-III+", 0);
+ break;
+ case JAGUAR_IMPL:
+ log_printf("%-7s ", "US-IV", 0);
+ break;
+ case PANTHER_IMPL:
+ log_printf("%-7s ", "US-IV+", 0);
+ break;
+ default:
+ log_printf("%-7x ", *impl, 0);
+ break;
+ }
+ }
+
+ /* CPU Mask */
+ if (mask == NULL) {
+ log_printf(" %3s ", "N/A", 0);
+ } else {
+ if (IS_CHEETAH(*impl))
+ decoded_mask = REMAP_CHEETAH_MASK(*mask);
+ else
+ decoded_mask = *mask;
+
+ log_printf(" %d.%d ",
+ (decoded_mask >> 4) & 0xf,
+ decoded_mask & 0xf, 0);
+ }
+
+ log_printf("\n", 0);
+ }
+}
+
+
+/*ARGSUSED3*/
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Hardware Failures "), 0);
+ log_printf("==================================", 0);
+ log_printf("\n", 0);
+
+ /*
+ * Get a list of failed parts (ie. devices with a status of
+ * 'fail') from the OBP device tree and display them.
+ */
+ get_failed_parts();
+
+ /* return unless -v option specified */
+ if (!flag) {
+ log_printf("\n", 0);
+ return;
+ }
+
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ /* Print the PROM revisions here */
+ serengeti_display_hw_revisions(root, tree->bd_list);
+}
+
+/*
+ * local functions - functions that are only needed inside this library
+ */
+
+static void
+serengeti_display_hw_revisions(Prom_node *root, Board_node *bdlist)
+{
+ Prom_node *pnode;
+ char *value;
+
+ /* Print the header */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
+ log_printf("=======================================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ /* Display Prom revision header */
+ log_printf("System PROM revisions:\n", 0);
+ log_printf("----------------------\n", 0);
+
+ /*
+ * Display OBP version info
+ */
+ pnode = dev_find_node(root, "openprom");
+ if (pnode != NULL) {
+ value = (char *)get_prop_val(find_prop(pnode, "version"));
+ log_printf("%s\n\n", value, 0);
+ } else {
+ log_printf("OBP ???\n\n", value, 0);
+ }
+
+ /*
+ * Display ASIC revisions
+ */
+ log_printf("IO ASIC revisions:\n", 0);
+ log_printf("------------------\n", 0);
+
+ log_printf(" Port\n", 0);
+ log_printf("FRU Name Model ID Status", 0);
+#ifdef DEBUG
+ log_printf(" Version Notes\n", 0);
+#else
+ log_printf(" Version\n", 0);
+#endif
+ /* ---------FRU Name--Model-----------Port-Status */
+ log_printf("----------- --------------- ---- ---------- "
+#ifdef DEBUG
+ "------- "
+#endif
+ "-------\n", 0);
+ /*
+ * Display SCHIZO version info
+ */
+ display_schizo_revisions(bdlist, SG_SCHIZO_GOOD);
+
+ /*
+ * Display sgsbbc version info
+ */
+ display_sgsbbc_revisions(bdlist);
+}
+
+/*
+ * This function displays Schizo and Xmits revision of boards
+ */
+static int
+display_schizo_revisions(Board_node *bdlist, int mode)
+{
+ Prom_node *pnode;
+ int *int_val;
+ int portid;
+ int prev_portid = -1;
+ char *model;
+ char *status_a, *status_b;
+ char status[MAX_STATUS_LEN];
+ int version;
+ int node_id;
+#ifdef DEBUG
+ uint32_t a_notes, b_notes;
+#endif
+ int pci_bus;
+ /*
+ * rv is used when mode is set to SG_SCHIZO_FAILED.
+ * We need to signal if a failure is found so that
+ * the correct headers/footers can be printed.
+ *
+ * rv = 1 implies a failed/disavled schizo device
+ * rv = 0 implies all other cases
+ */
+ int rv = 0;
+ Board_node *bnode;
+ void *value;
+
+ bnode = bdlist;
+ while (bnode != NULL) {
+ /*
+ * search this board node for all Schizos
+ */
+ for (pnode = dev_find_node_by_compatible(bnode->nodes,
+ SCHIZO_COMPATIBLE); pnode != NULL;
+ pnode = dev_next_node_by_compatible(pnode,
+ SCHIZO_COMPATIBLE)) {
+
+ char fru_name[MAX_FRU_NAME_LEN] = "";
+
+ /*
+ * get the reg property to determine
+ * whether we are looking at side A or B
+ */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "reg"));
+ if (int_val != NULL) {
+ int_val ++; /* second integer in array */
+ pci_bus = ((*int_val) & 0x7f0000);
+ }
+
+ /* get portid */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "portid"));
+ if (int_val == NULL)
+ continue;
+
+ portid = *int_val;
+
+ /*
+ * If this is a new portid and it is PCI bus B,
+ * we skip onto the PCI bus A. (PCI-A and PCI-B share
+ * the same portid)
+ */
+ if ((portid != prev_portid) && (pci_bus == 0x700000)) {
+ prev_portid = portid;
+ /* status */
+ status_b = (char *)get_prop_val
+ (find_prop(pnode, "status"));
+#ifdef DEBUG
+ b_notes = pci_bus;
+#endif
+ continue; /* skip to the next schizo */
+ }
+
+ /*
+ * This must be side A of the same Schizo.
+ * Gather all its props and display them.
+ */
+#ifdef DEBUG
+ a_notes = pci_bus;
+#endif
+
+ prev_portid = portid;
+
+ /* get the node-id */
+ node_id = SG_PORTID_TO_NODEID(portid);
+
+ /* model */
+ model = (char *)get_prop_val
+ (find_prop(pnode, "model"));
+
+ /* version */
+ value = (int *)get_prop_val
+ (find_prop(pnode, "module-revision#"));
+
+ if (value)
+ int_val = (int *)value;
+ else
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "version#"));
+ if (int_val != NULL)
+ version = *int_val;
+ else
+ version = -1;
+
+ /* status */
+ status_a = (char *)get_prop_val(find_prop
+ (pnode, "status"));
+
+ /*
+ * Display the data
+ */
+ /* FRU Name */
+ SG_SET_FRU_NAME_NODE(fru_name, node_id);
+ SG_SET_FRU_NAME_IO_BOARD(fru_name,
+ SG_IO_BD_PORTID_TO_BD_NUM(portid));
+ SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
+
+ if (mode == SG_SCHIZO_FAILED) {
+ if ((status_a != (char *)NULL) &&
+ ((status_b != (char *)NULL))) {
+ if ((strcmp
+ (status_a, SG_DISABLED) == 0) &&
+ (strcmp(status_b,
+ SG_DISABLED) == 0)) {
+ log_printf("\tFRU Type : %s\n ",
+ model, 0);
+ log_printf("\tLocation : %s\n",
+ fru_name, 0);
+ log_printf
+ ("\tPROM status: %s\n\n",
+ SG_DISABLED, 0);
+ rv = 1;
+ }
+ }
+ continue;
+ }
+ /*
+ * This section of code is executed when displaying
+ * non-failed schizo devices. If the mode is set to
+ * SG_SCHIZO_FAILED, then this section of code will
+ * not be executed
+ */
+ if ((status_a == (char *)NULL) &&
+ ((status_b == (char *)NULL)))
+ sprintf(status, " %s ", SG_OK);
+ else if ((status_a == (char *)NULL) &&
+ ((strcmp(status_b, SG_DISABLED) == 0)))
+ sprintf(status, " %s", SG_DEGRADED);
+ else if ((status_b == (char *)NULL) &&
+ ((strcmp(status_a, SG_DISABLED) == 0)))
+ sprintf(status, " %s", SG_DEGRADED);
+ else
+ continue;
+
+ log_printf("%-12s", fru_name, 0);
+
+ /* model */
+
+ if (model != NULL)
+ log_printf("%-15s ", model, 0);
+ else
+ log_printf("%-15s ", "unknown", 0);
+ /* portid */
+ log_printf("%-3d ", portid, 0);
+
+ /* status */
+ log_printf("%s", status, 0);
+
+ /* version */
+ log_printf(" %-4d ", version, 0);
+#ifdef DEBUG
+ log_printf("0x%x 0x%x", a_notes, b_notes, 0);
+ log_printf(" %d", portid, 0);
+#endif
+ log_printf("\n", 0);
+ }
+ bnode = bnode->next;
+ }
+ return (rv);
+}
+
+static void
+display_sgsbbc_revisions(Board_node *bdlist)
+{
+
+ Prom_node *pnode;
+ int *int_val;
+ int portid;
+ char *model;
+ char *status;
+ int revision;
+ int node_id;
+ Board_node *bnode;
+
+#ifdef DEBUG
+ char *slot_name;
+ char notes[30];
+ char *value;
+#endif
+
+ bnode = bdlist;
+ while (bnode != NULL) {
+ /*
+ * search this board node for all sgsbbc's
+ */
+ for (pnode = dev_find_node_by_type(bnode->nodes, "model",
+ "SUNW,sgsbbc"); pnode != NULL;
+ pnode = dev_next_node_by_type(pnode, "model",
+ "SUNW,sgsbbc")) {
+
+ char fru_name[MAX_FRU_NAME_LEN] = "";
+
+ /*
+ * We need to go to this node's parent to
+ * get a portid to tell us what board it is on
+ */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode->parent, "portid"));
+ if (int_val == NULL)
+ continue;
+
+ portid = *int_val;
+ /* get the node-id */
+ node_id = SG_PORTID_TO_NODEID(portid);
+
+ /* model */
+ model = (char *)get_prop_val
+ (find_prop(pnode, "model"));
+
+ /* status */
+ status = (char *)get_prop_val(find_prop
+ (pnode, "status"));
+
+ /* revision */
+ int_val = (int *)get_prop_val
+ (find_prop(pnode, "revision-id"));
+ if (int_val != NULL)
+ revision = *int_val;
+ else
+ revision = -1;
+
+#ifdef DEBUG
+ value = (char *)get_prop_val(
+ find_prop(pnode->parent, "slot-names"));
+ if (value != NULL) {
+ /* Skip the 4 byte bitmask */
+ slot_name = (char *)value + sizeof (int);
+ } else {
+ strcpy(slot_name, "not_found");
+ }
+ (void) sprintf(notes, "[%s] portid [%d]", slot_name,
+ portid);
+#endif
+ /*
+ * Display the data
+ */
+ /* FRU Name */
+ SG_SET_FRU_NAME_NODE(fru_name, node_id);
+ SG_SET_FRU_NAME_IO_BOARD(fru_name,
+ SG_IO_BD_PORTID_TO_BD_NUM(portid));
+ SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
+ log_printf("%-12s", fru_name, 0);
+
+ /* model */
+ if (model != NULL)
+ log_printf("%-15s ", model, 0);
+ else
+ log_printf("%-15s ", "unknown", 0);
+ /* portid */
+ log_printf("%-3d ", portid, 0);
+ /* status */
+ if (status == (char *)NULL)
+ log_printf(" ok ", 0);
+ else
+ log_printf(" fail ", 0);
+ /* revision */
+ log_printf(" %-4d ", revision, 0);
+#ifdef DEBUG
+ log_printf("%s", notes, 0);
+#endif
+ log_printf("\n", 0);
+ }
+ bnode = bnode->next;
+ }
+}
+
+/*ARGSUSED0*/
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ serengeti_display_board_info(ACTIVE);
+ serengeti_display_board_info(INACTIVE);
+}
+
+/*
+ * display_failed_parts
+ *
+ * Display the failed parts in the system. This function looks for
+ * the status property in all PROM nodes contained in the Sys_tree
+ * passed in.
+ */
+int
+display_failed_parts(Sys_tree *tree)
+{
+ int system_failed = 0;
+ int bank_failed = 0;
+ int schizo_failed = FALSE;
+ int portid, nodeid, board;
+ Board_node *bnode = tree->bd_list;
+ Prom_node *pnode;
+ int *coreid, *impl;
+ print_flag = TRUE;
+
+ /*
+ * go through all of the OBP nodes looking for
+ * failed units.
+ */
+ while (bnode != NULL) {
+
+ pnode = find_failed_node(bnode->nodes);
+ if ((pnode != NULL) && !system_failed) {
+ system_failed = TRUE;
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed Field Replaceable Units (FRU) in "
+ "System:\n"), 0);
+ log_printf("=========================="
+ "====================\n", 0);
+ }
+
+ while (pnode != NULL) {
+ void *status;
+ char *name, *type, *model;
+
+ char fru_name[MAX_FRU_NAME_LEN] = "";
+
+ status = get_prop_val(find_prop(pnode, "status"));
+ name = get_node_name(pnode);
+
+ /* sanity check of data retreived from PROM */
+ if ((status == NULL) || (name == NULL)) {
+ pnode = next_failed_node(pnode);
+ continue;
+ }
+
+ type = get_node_type(pnode);
+ portid = get_id(pnode);
+ model = (char *)get_prop_val
+ (find_prop(pnode, "model"));
+
+ /*
+ * Determine whether FRU is CPU module, Mem Controller,
+ * PCI card, schizo,xmits or sgsbbc.
+ */
+ if ((model != NULL) && strstr(model, "sgsbbc")) {
+ /*
+ * sgsbbc / bootbus-controller
+ */
+ portid = get_id(pnode->parent);
+ nodeid = SG_PORTID_TO_NODEID(portid);
+ board = SG_PORTID_TO_BOARD_NUM(portid);
+
+ SG_SET_FRU_NAME_NODE(fru_name, nodeid);
+ SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
+ SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
+
+ log_printf("\tFailed Device : %s (%s)\n", model,
+ name, 0);
+ log_printf("\tLocation : %s\n", fru_name, 0);
+
+ } else if (strstr(name, "pci") && (portid == -1)) {
+ /*
+ * PCI Bridge if name = pci and it doesn't
+ * have a portid.
+ */
+ portid = get_id(pnode->parent);
+ nodeid = SG_PORTID_TO_NODEID(portid);
+ board = SG_PORTID_TO_BOARD_NUM(portid);
+
+ SG_SET_FRU_NAME_NODE(fru_name, nodeid);
+ SG_SET_FRU_NAME_IO_BOARD(fru_name, board);
+ SG_SET_FRU_NAME_MODULE(fru_name, portid % 2);
+
+ log_printf("\tFRU type : ", 0);
+ log_printf("PCI Bridge Device\n", 0);
+ log_printf("\tLocation : %s\n", fru_name, 0);
+
+ } else if ((type != NULL) &&
+ (strstr(type, "cpu") ||
+ strstr(type, "memory-controller"))) {
+ /*
+ * CPU or memory controller
+ */
+ portid = get_id(pnode);
+ /*
+ * For cpu nodes that belong to a CMP, the
+ * portid is stored in the parent "cmp" node.
+ */
+ if (portid == -1)
+ portid = get_id(pnode->parent);
+ nodeid = SG_PORTID_TO_NODEID(portid);
+ board = SG_PORTID_TO_BOARD_NUM(portid);
+
+ SG_SET_FRU_NAME_NODE(fru_name, nodeid);
+ SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
+ SG_SET_FRU_NAME_MODULE(fru_name, portid % 4);
+
+ log_printf("\tFRU type : ", 0);
+
+ if (strstr(type, "memory-controller"))
+ log_printf("Memory Controller on ", 0);
+
+ log_printf("UltraSPARC module\n", 0);
+
+ log_printf("\tLocation : %s\n", fru_name, 0);
+
+ } else {
+ /*
+ * It should only be a PCI card if we get to
+ * here but lets check to be sure.
+ */
+ char *parents_model, *grandparents_model;
+ Prom_node *parent_pnode;
+ int pci_card_found = 0;
+
+ if (pnode->parent != NULL)
+ parent_pnode = pnode->parent;
+
+ /*
+ * Is our parent a schizo or xmits
+ */
+ parents_model = (char *)get_prop_val
+ (find_prop(pnode->parent, "model"));
+ if ((parents_model != NULL) &&
+ (strstr(parents_model, "SUNW,schizo") ||
+ strstr(parents_model, "SUNW,xmits"))) {
+ portid = get_id(pnode->parent);
+ pci_card_found = TRUE;
+ }
+
+ /*
+ * Is our grandparent a schizo xmits
+ */
+ grandparents_model = (char *)get_prop_val
+ (find_prop(parent_pnode->parent, "model"));
+ if ((grandparents_model != NULL) &&
+ (strstr(grandparents_model,
+ "SUNW,schizo") ||
+ strstr(grandparents_model,
+ "SUNW,xmits"))) {
+ portid = get_id(parent_pnode->parent);
+ pci_card_found = TRUE;
+ }
+
+ if (pci_card_found) {
+ nodeid = SG_PORTID_TO_NODEID(portid);
+ board = SG_PORTID_TO_BOARD_NUM(portid);
+
+ SG_SET_FRU_NAME_NODE(fru_name, nodeid);
+ SG_SET_FRU_NAME_IO_BOARD(fru_name,
+ board);
+ SG_SET_FRU_NAME_MODULE(fru_name,
+ portid % 2);
+
+ log_printf("\tFRU type :", 0);
+ log_printf(" PCI Card\n", 0);
+ log_printf("\tLocation : %s\n",
+ fru_name, 0);
+ }
+ }
+ log_printf("\tPROM status: %s\n\n", status, 0);
+
+ pnode = next_failed_node(pnode);
+ }
+ bnode = bnode->next;
+
+ }
+
+ bank_failed = display_us3_failed_banks(system_failed);
+ schizo_failed = display_schizo_revisions(tree->bd_list,
+ SG_SCHIZO_FAILED);
+ if (system_failed || bank_failed || schizo_failed)
+ return (1);
+ else
+ return (0);
+}
+
+
+/*
+ * This routine displays the memory configuration for all boards in the
+ * system.
+ */
+/*ARGSUSED0*/
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode = tree->bd_list;
+
+ log_printf("========================= Memory Configuration"
+ " ===============================\n", 0);
+ log_printf("\n Logical Logical Logical ", 0);
+ log_printf("\n Port Bank Bank Bank "
+ "DIMM Interleave Interleave", 0);
+ log_printf("\nFRU Name ID Num Size Status "
+ "Size Factor Segment", 0);
+ log_printf("\n------------- ---- ---- ------ ----------- "
+ "------ ---------- ----------", 0);
+
+ while (bnode != NULL) {
+ if (get_us3_mem_regs(bnode)) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nFailed to get memory information.\n"), 0);
+ return;
+ }
+ bnode = bnode->next;
+ }
+
+ /* Display what we have found */
+ display_us3_banks();
+}
+
+/*
+ * This function provides Serengeti's formatting of the memory config
+ * information that get_us3_mem_regs() and display_us3_banks() code has
+ * gathered. It overrides the generic print_us3_memory_line() code
+ * which prints an error message.
+ */
+void
+print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
+{
+ int nodeid, board, mcid;
+ char fru_name[MAX_FRU_NAME_LEN] = "";
+
+ mcid = SG_PORTID_TO_SAFARI_ID(portid);
+ nodeid = SG_PORTID_TO_NODEID(portid);
+ board = SG_PORTID_TO_BOARD_NUM(portid);
+
+ SG_SET_FRU_NAME_NODE(fru_name, nodeid);
+ SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
+ SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
+ SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
+
+ log_printf("\n%-13s %2d %2d %4lldMB %11-s %4lldMB "
+ " %2d-way %d",
+ fru_name, mcid,
+ (bank_id % 4), bank_size, bank_status, dimm_size,
+ intlv, seg_id, 0);
+}
+
+void
+print_us3_failed_memory_line(int portid, int bank_id, char *bank_status)
+{
+ int nodeid, board, mcid;
+ char fru_name[MAX_FRU_NAME_LEN] = "";
+
+ mcid = SG_PORTID_TO_SAFARI_ID(portid);
+ nodeid = SG_PORTID_TO_NODEID(portid);
+ board = SG_PORTID_TO_BOARD_NUM(portid);
+
+ SG_SET_FRU_NAME_NODE(fru_name, nodeid);
+ SG_SET_FRU_NAME_CPU_BOARD(fru_name, board);
+ SG_SET_FRU_NAME_MODULE(fru_name, mcid % 4);
+ SG_SET_FRU_NAME_BANK(fru_name, (bank_id % 4) % 2);
+
+ log_printf("\tFRU type : ", 0);
+ log_printf("Physical Memory Bank\n", 0);
+ log_printf("\tLocation : %s (Logical Bank %2d)\n",
+ fru_name, (bank_id %4), 0);
+ log_printf("\tPROM status: %s\n\n", bank_status, 0);
+}
+
+
+/*
+ * Find the requested board struct in the system device tree.
+ *
+ * This function overrides the functionality of the generic find_board()
+ * function in libprtdiag, but since we need to pass another parameter,
+ * we cannot simply overlay the symbol table.
+ */
+static Board_node *
+serengeti_find_board(Sys_tree *root, int board, int nodeid)
+{
+ Board_node *bnode = root->bd_list;
+
+ while ((bnode != NULL) &&
+ ((board != bnode->board_num) || (nodeid != bnode->node_id))) {
+ bnode = bnode->next;
+ }
+ return (bnode);
+}
+
+
+/*
+ * Add a board to the system list in order (sorted by NodeID then board#).
+ * Initialize all pointer fields to NULL.
+ */
+static Board_node *
+serengeti_insert_board(Sys_tree *root, int board, int nodeid)
+{
+ Board_node *bnode;
+ Board_node *temp = root->bd_list;
+
+ if ((bnode = (Board_node *) malloc(sizeof (Board_node))) == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ bnode->nodes = NULL;
+ bnode->next = NULL;
+ bnode->board_num = board;
+ bnode->node_id = nodeid;
+ bnode->board_type = UNKNOWN_BOARD;
+
+ if (temp == NULL)
+ root->bd_list = bnode;
+
+ else if ((temp->board_num > board) && (temp->node_id >= nodeid)) {
+ bnode->next = temp;
+ root->bd_list = bnode;
+
+ } else {
+ while ((temp->next != NULL) &&
+ ((board > temp->next->board_num) ||
+ (nodeid > temp->node_id)))
+ temp = temp->next;
+
+ bnode->next = temp->next;
+ temp->next = bnode;
+ }
+ root->board_cnt++;
+
+ return (bnode);
+}
+
+/*
+ * We call do_devinfo() in order to use the libdevinfo device tree
+ * instead of OBP's device tree.
+ */
+int
+do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+
+ return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
+
+}
+
+/*
+ * return the property value for the Prop passed in depending on
+ * which tree (OBP/DEVINFO) is being used.
+ */
+void *
+get_prop_val(Prop *prop)
+{
+ if (prop == NULL)
+ return (NULL);
+
+ /* Check which tree is being used. */
+ if (tree == DEVINFO_TREE)
+ return ((void *)(prop->value.val_ptr));
+ else {
+ if (prop->value.opp.holds_array)
+ return ((void *)(prop->value.opp.oprom_array));
+ else
+ return ((void *)(&prop->value.opp.oprom_node[0]));
+ }
+}
+
+/*
+ * Search a Prom node and retrieve the property with the correct
+ * name depending on which tree (OBP/DEVINFO) is being used.
+ */
+Prop *
+find_prop(Prom_node *pnode, char *name)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ if (pnode->props == NULL)
+ return (NULL);
+
+ prop = pnode->props;
+
+ /* Check which tree is being used. */
+ if (tree == DEVINFO_TREE) {
+ while ((prop != NULL) &&
+ (strcmp((char *)(prop->name.val_ptr), name)))
+ prop = prop->next;
+ } else {
+ while ((prop != NULL) && (strcmp((char *)
+ (prop->name.opp.oprom_array), name)))
+ prop = prop->next;
+ }
+ return (prop);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property
+ * depending on which tree (OBP/DEVINFO) is being used.
+ */
+char *
+get_node_name(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ /* Check which tree is being used. */
+ if (tree == DEVINFO_TREE) {
+ if (strcmp("name", (char *)prop->name.val_ptr) == 0)
+ return ((char *)prop->value.val_ptr);
+ } else {
+ if (strcmp("name", prop->name.opp.oprom_array) == 0)
+ return (prop->value.opp.oprom_array);
+ }
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the device_type property
+ * depending on which tree (OBP/DEVINFO) is being used.
+ */
+char *
+get_node_type(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ /* Check which tree is being used. */
+ if (tree == DEVINFO_TREE) {
+ if (strcmp("device_type", (char *)prop->name.val_ptr)
+ == 0)
+ return ((char *)prop->value.val_ptr);
+ } else {
+ if (strcmp("device_type", prop->name.opp.oprom_array)
+ == 0)
+ return (prop->value.opp.oprom_array);
+ }
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+/*
+ * Take a snapshot of the OBP device tree and walk this snapshot
+ * to find all failed HW (ie. devices with a status property of
+ * 'fail'). Call display_failed_parts() to display the failed HW.
+ */
+void
+get_failed_parts(void)
+{
+ int system_failed = 0;
+ Sys_tree obp_sys_tree; /* system information */
+
+ /* set the the system tree fields */
+ obp_sys_tree.sys_mem = NULL;
+ obp_sys_tree.boards = NULL;
+ obp_sys_tree.bd_list = NULL;
+ obp_sys_tree.board_cnt = 0;
+
+ if (promopen(O_RDONLY)) {
+ (void) fprintf(stderr, "%s",
+ dgettext(TEXT_DOMAIN, "openprom device "
+ "open failed"));
+ return;
+ }
+
+ if ((is_openprom() == 0) || (next(0) == 0)) {
+ (void) fprintf(stderr, "%s",
+ dgettext(TEXT_DOMAIN, "openprom device "
+ "error encountered."));
+ return;
+ }
+
+ tree = OBP_TREE; /* Switch to the OBP tree */
+
+ (void) walk(&obp_sys_tree, NULL, next(0));
+
+ system_failed = display_failed_parts(&obp_sys_tree);
+
+ if (!system_failed) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "No Hardware failures found in System\n"), 0);
+ }
+ promclose();
+ tree = DEVINFO_TREE; /* Switch back to the DEVINFO tree */
+}
+
+/*
+ * get_slot_name figures out the slot no. for the card. In the case of
+ * XMITS slots 2 & 3 and slots 6 & 7 are reversed in slot_name by OBP
+ * so we need to cater for this to correctly identify the slot no.
+ */
+static void
+get_slot_name(struct io_card *card, char *slot_name)
+{
+ char tmp_ptr[2];
+
+ if (strlen(slot_name) != 0) {
+ if (strcmp(card->notes, XMITS_COMPATIBLE) == 0) {
+ (void) sprintf(tmp_ptr, "%c",
+ slot_name[strlen(slot_name) -1]);
+ switch (tmp_ptr[0]) {
+ case '2':
+ (void) sprintf(card->slot_str, "%c", '3');
+ break;
+ case '3':
+ (void) sprintf(card->slot_str, "%c", '2');
+ break;
+ case '6':
+ (void) sprintf(card->slot_str, "%c", '7');
+ break;
+ case '7':
+ (void) sprintf(card->slot_str, "%c", '6');
+ break;
+ default:
+ (void) sprintf(card->slot_str, "%c",
+ slot_name[strlen(slot_name) -1]);
+ }
+ } else
+ (void) sprintf(card->slot_str, "%c",
+ slot_name[strlen(slot_name) -1]);
+ } else
+ (void) sprintf(card->slot_str, "-");
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/snowbird/Makefile b/usr/src/lib/libprtdiag_psr/sparc/snowbird/Makefile
new file mode 100644
index 0000000000..e2742a5665
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/snowbird/Makefile
@@ -0,0 +1,95 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/snowbird/Makefile
+#
+# Need to make libctsmc library first.
+#
+LIBCTSMC = ../../../../../src/cmd/picl/plugins/sun4u/snowbird/lib/libctsmc
+all: ctsmclib
+ctsmclib: $(LIBCTSMC)/libctsmc.c $(LIBCTSMC)/smclib.h
+ cd $(LIBCTSMC); $(MAKE)
+
+LIBBASE = ../../../../../src/lib
+UTSBASE = ../../../../uts
+SUN4U_INC_BASE = $(UTSBASE)/sun4u/sys
+SB_INC_BASE = $(UTSBASE)/sun4u/snowbird/sys
+
+PLATFORM_OBJECTS= snowbird.o
+
+include ../Makefile.com
+
+IFLAGS = -I$(USR_PLAT_DIR)/sun4u/include -I../../../libprtdiag/inc -I$(LIBBASE)/libdevinfo
+IFLAGS += -I$(SUN4U_INC_BASE) -I$(SB_INC_BASE) -I$(SRC)/cmd/picl/plugins/inc
+IFLAGS += -I$(LIBCTSMC)
+LINTFLAGS += $(IFLAGS)
+LDLIBS += -L$(LIBCTSMC)
+LDLIBS += -L$(LIBBASE)/libdevinfo -ldevinfo -L$(LIBBASE)/libcfgadm \
+ -lcfgadm -lpicl -lctsmc
+DYNFLAGS += -R/usr/platform/SUNW,Netra-CP2300/lib
+
+
+#
+# SUNW,Netra-CP2300 platform can link to
+# /usr/platform/SUNW,Netra-CP2300/lib/libprtdiag_psr.so
+#
+PLATFORM=SUNW,Netra-CP2300
+
+.KEEP_STATE:
+
+PLATLIBS= $(PLATFORM:%=$(USR_PLAT_DIR)/%/lib/)
+
+install: all $(PLATLIBS) $(USR_PSM_LIBS)
+
+#
+# install rules for SUNW,Netra-CP2300/lib/libprtdiag_psr.so
+#
+$(PLATLIBS):
+ $(INS.dir)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/snowbird; $(MAKE) $(USR_PSM_LIB_DIR)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+# New additions to generate msg file
+POFILE = libprtdiag_psr_snowbird.po
+POFILES = snowbird.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/snowbird.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/snowbird/common/snowbird.c b/usr/src/lib/libprtdiag_psr/sparc/snowbird/common/snowbird.c
new file mode 100644
index 0000000000..a1c952e720
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/snowbird/common/snowbird.c
@@ -0,0 +1,1120 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+/*
+ * This program prints the diagnostics of Sanibel system. It
+ * also prints other miscellaneous information about watchdog, temperature
+ * of CPU sensor, firmware versions of SMC and, micro controller role
+ * etc. The basic sources of output is PICL, and SMC.
+ */
+
+/* includes */
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <dirent.h>
+#include <sys/param.h>
+#include <picl.h>
+#include <libintl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+#include <sys/openpromio.h>
+#include <fcntl.h>
+#include <smc_if.h>
+#include <stropts.h>
+#include <alloca.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <sys/utsname.h>
+#include <stddef.h>
+#include <pdevinfo.h>
+#include <display_sun4u.h>
+#include <libprtdiag.h>
+#include <smclib.h>
+#include <smc_commands.h>
+#include <picldefs.h>
+
+/* #defines for the PICL library API usage and local static variables */
+#define PD_CPCI_SLOT_TYPE "cpci"
+#define PD_PCI_SLOT_TYPE "pci"
+#define PD_PRESENT 1
+#define PD_BLANK " "
+#define PD_ENABLED 1
+#define PD_DISABLED 0
+#define SNOWBIRD "SUNW,Netra-CP2300"
+#define CHASSIS_NODE_NAME "chassis"
+
+/* #defines for the SMC and IPMI commands */
+#define POLL_TIMEOUT 10000
+#define DEFAULT_SEQN 0xff
+
+/* SMC driver */
+#define PD_SMC_DRV_PATH "/dev/ctsmc"
+
+/* Constants */
+#define OBP_PROP_BANNER_NAME "banner-name"
+#define OBP_PROP_CLOCK_FREQ "clock-frequency"
+
+
+
+/* #defines for local usage */
+#define PD_SUCCESS 0
+#define PD_FAILURE 1
+#define PD_INTERNAL_FAILURE 2
+#define PD_ERROR -1
+
+/* static global variables */
+static int pd_print_option;
+static uint8_t pd_smc_glbl_enabl_rsp[2];
+static boolean_t pd_hdr_prt = B_TRUE;
+static int pd_smc_fd = 0;
+
+
+/* function declarations used in this program */
+static uint32_t pd_check_for_snowbird();
+static uint32_t pd_prt_snowbird_diag();
+static uint32_t pd_check_cpu_health();
+static uint32_t pd_check_tty_debug_mode();
+static uint32_t pd_query_SMC_firmware_version();
+static uint32_t pd_check_slots();
+int32_t pd_prt_slot_info(picl_nodehdl_t, void *);
+int do_prominfo(int syserrlog, char *pname, int log_flag, int prt_flag);
+static uint32_t pd_query_watchdog_state();
+int pd_check_wd_state(picl_nodehdl_t, void *);
+static uint32_t pd_print_fruinfo_hdr();
+static uint32_t pd_print_device_info(int);
+static uint32_t pd_get_role_information();
+static uint32_t pd_get_message_flags();
+static uint32_t pd_get_reset_mode();
+static uint32_t pd_get_sensor_reading();
+static uint32_t pd_get_sensor_threshold();
+static uint32_t pd_prt_cpci_condition(picl_nodehdl_t nodeh);
+static uint32_t pd_check_location_parent(picl_nodehdl_t nodeh);
+static uint64_t
+picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret);
+static int picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq);
+static int display_system_clock(picl_nodehdl_t plafh);
+
+/*
+ * return the value of the uint prop
+ */
+static uint64_t
+picldiag_get_uint_propval(picl_nodehdl_t modh, char *prop_name, int *ret)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ uint8_t uint8v;
+ uint16_t uint16v;
+ uint32_t uint32v;
+ uint64_t uint64v;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS) {
+ *ret = err;
+ return (0);
+ }
+
+ /*
+ * If it is not an int or uint prop, return failure
+ */
+ if ((pinfo.type != PICL_PTYPE_INT) &&
+ (pinfo.type != PICL_PTYPE_UNSIGNED_INT)) {
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+
+ /* uint prop */
+
+ switch (pinfo.size) {
+ case sizeof (uint8_t):
+ err = picl_get_propval(proph, &uint8v, sizeof (uint8v));
+ *ret = err;
+ return (uint8v);
+ case sizeof (uint16_t):
+ err = picl_get_propval(proph, &uint16v, sizeof (uint16v));
+ *ret = err;
+ return (uint16v);
+ case sizeof (uint32_t):
+ err = picl_get_propval(proph, &uint32v, sizeof (uint32v));
+ *ret = err;
+ return (uint32v);
+ case sizeof (uint64_t):
+ err = picl_get_propval(proph, &uint64v, sizeof (uint64v));
+ *ret = err;
+ return (uint64v);
+ default: /* not supported size */
+ *ret = PICL_FAILURE;
+ return (0);
+ }
+}
+
+
+
+/*
+ * get the clock frequency
+ */
+static int
+picldiag_get_clock_freq(picl_nodehdl_t modh, uint32_t *freq)
+{
+#define ROUND_TO_MHZ(x) (((x) + 500000)/ 1000000)
+
+ int err;
+ uint64_t clk_freq;
+
+ clk_freq = picldiag_get_uint_propval(modh, OBP_PROP_CLOCK_FREQ, &err);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ *freq = ROUND_TO_MHZ(clk_freq);
+
+ return (PICL_SUCCESS);
+}
+
+
+/*
+ * display the clock frequency
+ */
+static int
+display_system_clock(picl_nodehdl_t plafh)
+{
+ uint32_t system_clk;
+ int err;
+
+ err = picldiag_get_clock_freq(plafh, &system_clk);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System clock frequency: %d MHZ\n"), system_clk);
+
+ return (PICL_SUCCESS);
+}
+
+
+/*
+ * get the value by the property name of the string prop
+ * Caller must free the outbuf
+ */
+static int
+picldiag_get_string_propval(picl_nodehdl_t modh, char *prop_name, char **outbuf)
+{
+ int err;
+ picl_prophdl_t proph;
+ picl_propinfo_t pinfo;
+ char *prop_value;
+
+ err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph);
+ if (err != PICL_SUCCESS)
+ return (err);
+
+ /*
+ * If it is not a string prop, return NULL
+ */
+ if (pinfo.type != PICL_PTYPE_CHARSTRING)
+ return (PICL_FAILURE);
+
+ prop_value = malloc(pinfo.size);
+ if (prop_value == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval(proph, prop_value, pinfo.size);
+ if (err != PICL_SUCCESS) {
+ free(prop_value);
+ return (err);
+ }
+
+ *outbuf = prop_value;
+ return (PICL_SUCCESS);
+}
+
+
+
+/*
+ * display platform banner
+ */
+static int
+display_platform_banner(picl_nodehdl_t plafh)
+{
+ char *platform;
+ char *banner_name;
+ int err;
+
+ /*
+ * get PICL_PROP_MACHINE and PICL_PROP_BANNER_NAME
+ */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "System Configuration: Sun Microsystems "), 0);
+ err = picldiag_get_string_propval(plafh, PICL_PROP_MACHINE,
+ &platform);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", platform, 0);
+ free(platform);
+
+ err = picldiag_get_string_propval(plafh, OBP_PROP_BANNER_NAME,
+ &banner_name);
+ if (err != PICL_SUCCESS)
+ return (err);
+ log_printf(" %s", banner_name, 0);
+ free(banner_name);
+
+ log_printf("\n", 0);
+ return (PICL_SUCCESS);
+}
+
+/*
+ * search children to get the node by the nodename
+ */
+static int
+picldiag_get_node_by_name(picl_nodehdl_t rooth, char *name,
+ picl_nodehdl_t *nodeh)
+{
+ picl_nodehdl_t childh;
+ int err;
+ char *nodename;
+
+ nodename = alloca(strlen(name) + 1);
+ if (nodename == NULL)
+ return (PICL_FAILURE);
+
+ err = picl_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
+ sizeof (picl_nodehdl_t));
+
+ while (err == PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_NAME,
+ nodename, (strlen(name) + 1));
+ if (err != PICL_SUCCESS) {
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ continue;
+ }
+
+ if (strcmp(nodename, name) == 0) {
+ *nodeh = childh;
+ return (PICL_SUCCESS);
+ }
+
+ err = picl_get_propval_by_name(childh, PICL_PROP_PEER,
+ &childh, sizeof (picl_nodehdl_t));
+ }
+
+ return (err);
+}
+
+
+/*
+ * This routine is invoked when prtdiag starts execution. It prints
+ * system configuration, memory size, initializes PICL and acts as
+ * a driver routine for prtdiag output for Snowbird.
+ */
+/* ARGSUSED */
+int
+do_prominfo(int syserrlog, char *pname, int log_flag, int prt_flag)
+{
+
+ struct mem_total memory_total; /* total memory in system */
+ struct grp_info grps;
+ uint8_t status = PD_SUCCESS;
+ picl_nodehdl_t rooth;
+ picl_nodehdl_t plafh;
+ struct system_kstat_data *kstats = NULL;
+ Sys_tree *tree = NULL;
+
+ sys_clk = -1;
+ pd_print_option = syserrlog;
+
+ if ((status = picl_initialize()) != PICL_SUCCESS) {
+ log_printf("prtdiag: failed to initialize the PICL\n", 0);
+ exit(1);
+ }
+
+ if ((status = picl_get_root(&rooth)) != PICL_SUCCESS) {
+ log_printf("prtdiag: failed\n", 0);
+ exit(1);
+ }
+
+ status = picldiag_get_node_by_name(rooth, PICL_NODE_PLATFORM, &plafh);
+ if (status != PICL_SUCCESS)
+ return (status);
+
+ if (!log_flag) {
+
+ status = display_platform_banner(plafh);
+ if (status != PICL_SUCCESS)
+ return (status);
+
+ status = display_system_clock(plafh);
+ if (status != PICL_SUCCESS)
+ return (status);
+
+ /* display the memory Size */
+ display_memorysize(tree, kstats, &grps, &memory_total);
+ }
+
+ if ((pd_smc_fd = open(PD_SMC_DRV_PATH, O_RDWR)) == -1)
+ return (PD_FAILURE);
+
+ if ((status = pd_check_for_snowbird()) != PD_SUCCESS)
+ return (status);
+
+ if ((status = pd_prt_snowbird_diag()) != PD_SUCCESS)
+ return (status);
+
+ (void) close(pd_smc_fd);
+
+ if (picl_shutdown() != PICL_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+ return (PD_SUCCESS);
+
+}
+
+/*
+ * This routine prints out the platform name.
+ */
+
+static uint32_t
+pd_check_for_snowbird()
+{
+
+ char si_platform[30];
+
+ if (sysinfo(SI_PLATFORM, si_platform, sizeof (si_platform)) == -1) {
+ return (PD_FAILURE);
+ }
+ /* is it a Snowbird? */
+ if (strcmp(si_platform, SNOWBIRD) != 0)
+ return (PD_FAILURE);
+
+ log_printf("platform Type : %s\n", si_platform, 0);
+ return (PD_SUCCESS);
+
+}
+
+
+/*
+ * Driver routine for satellite specific output. This is also used by
+ * host driver routine as all satellite information is printed by host.
+ * It also prints some host specific information for formatting purposes
+ */
+
+static uint32_t
+pd_prt_snowbird_diag()
+{
+ uint8_t status = PD_SUCCESS;
+ if ((status = pd_check_cpu_health()) != PD_SUCCESS) {
+ return (status);
+ }
+ if (pd_print_option) {
+
+ log_printf(
+ "\n %11s Other Miscellaneous Information \n",
+ PD_BLANK, 0);
+ log_printf(
+ "%12s ------------------------------- \n",
+ PD_BLANK, 0);
+
+ if ((status = pd_get_role_information()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ if (pd_smc_glbl_enabl_rsp[1] & 0x10) {
+ log_printf(
+ "IPMI Response Notification\t\tEnabled\n", 0);
+ } else {
+ log_printf(
+ "IPMI Response Notification\t\tDisabled\n", 0);
+ }
+ if ((status = pd_query_SMC_firmware_version()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ if ((status = pd_check_tty_debug_mode()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ if ((status = pd_get_reset_mode()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ if ((status = pd_get_message_flags()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ if ((status = pd_query_watchdog_state()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ if ((status = pd_get_sensor_reading()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ if ((status = pd_get_sensor_threshold()) != PD_SUCCESS) {
+ return (status);
+ }
+
+ }
+ return (status);
+
+}
+
+/*
+ * This routine prints the mode in which SMC is running. It uses the
+ * response from SMC global enables to determine the mode
+ */
+static uint32_t
+pd_check_tty_debug_mode()
+{
+
+ if (pd_smc_glbl_enabl_rsp[1] & 0x20) {
+ log_printf("SMC verbose mode\t\t\tON\n", 0);
+ } else {
+ log_printf("SMC verbose mode\t\t\tOFF\n", 0);
+ }
+
+ return (PD_SUCCESS);
+}
+
+/* This routine prints SMC f/w version */
+static uint32_t
+pd_query_SMC_firmware_version()
+{
+
+ sc_reqmsg_t req_pkt;
+ sc_rspmsg_t rsp_pkt;
+ uint8_t ver, rev, bldrev;
+
+
+ smc_init_smc_msg(&req_pkt, SMC_QUERY_FIRMWARE_VERSION,
+ DEFAULT_SEQN, 0);
+ smc_send_msg(-1, &req_pkt, &rsp_pkt, POLL_TIMEOUT);
+ ver = (rsp_pkt.data[0] & 0xf0) >> 4;
+ rev = rsp_pkt.data[0] & 0x0f;
+ bldrev = rsp_pkt.data[2] & 0x3f;
+
+ log_printf("SMC f/w version is\t\t\t%d.%d.%d\n", ver, rev, bldrev, 0);
+
+ return (PD_SUCCESS);
+
+}
+
+/*
+ * This routine checks CPU's health by using SMC self test results command
+ * It acts as driver routine for printing cPCI slot information
+ */
+static uint32_t
+pd_check_cpu_health()
+{
+
+ sc_reqmsg_t req_pkt;
+ sc_rspmsg_t rsp_pkt;
+ uint8_t dev_id = 0x1f;
+#ifdef DEBUG
+ uint8_t i2c_chk = 0x40;
+#endif
+ uint8_t mem_test = 0x20;
+
+ smc_init_smc_msg(&req_pkt, SMC_GET_SMC_SELF_TEST_RESULT,
+ DEFAULT_SEQN, 0);
+ smc_send_msg(-1, &req_pkt, &rsp_pkt, POLL_TIMEOUT);
+
+ dev_id = rsp_pkt.data[0] & dev_id;
+
+#ifdef DEBUG
+ if (rsp_pkt.data[0] & i2c_chk) {
+ pd_print_device_info(dev_id);
+ }
+#endif
+ if (rsp_pkt.data[0] & mem_test) {
+ pd_print_device_info(dev_id);
+ }
+ return (pd_check_slots());
+
+}
+
+/*
+ * This routine decodes error message for CPU failures and prints details
+ * of the failure
+ */
+static uint32_t
+pd_print_device_info(int dev_id)
+{
+
+ switch (dev_id) {
+ case 1:
+ log_printf("Mux Philip 9540\n", 0);
+ break;
+ case 2:
+ log_printf("cpu temp max1617\n", 0);
+ break;
+ case 3:
+ log_printf("pmc temp max 1617\n", 0);
+ break;
+ case 4:
+ log_printf("MB HS temp max 1617\n", 0);
+ break;
+ case 5:
+ log_printf("MB mem temp max1617\n", 0);
+ break;
+ case 6:
+ log_printf("MB gpio Philip8574\n", 0);
+ break;
+ case 7:
+ log_printf("MB Fru ID ID i2c eep\n", 0);
+ break;
+ case 8:
+ log_printf("MB enet ID ID i2d eep\n", 0);
+ break;
+ case 9:
+ log_printf("MB gpio Philip8574A\n", 0);
+ break;
+ case 10:
+ log_printf("SDRAM mod1 temp max1617\n", 0);
+ break;
+ case 11:
+ log_printf("SDRAM mod ID ID i2c eep\n", 0);
+ break;
+ case 12:
+ log_printf("SDRAM mod2 temp max1617\n", 0);
+ break;
+ case 13:
+ log_printf("SDRAM mod ID ID i2c eep\n", 0);
+ break;
+ case 14:
+ log_printf("Power mod temp ds1721\n", 0);
+ break;
+ case 15:
+ log_printf("Power mod gpio Philip 8574\n", 0);
+ break;
+ case 16:
+ log_printf("Power mod ID eep ST M24C01\n", 0);
+ break;
+ case 17:
+ log_printf("SMC ID i2c eep\n", 0);
+ break;
+
+ default:
+ log_printf("device id unknown\n", 0);
+ break;
+
+ }
+
+ return (PD_SUCCESS);
+
+}
+
+/*
+ * This routine walks PICL tree by "Location" class and calls prt_slot_info
+ * routine to print the slot information
+ */
+
+/*ARGSUSED*/
+static uint32_t
+pd_check_slots()
+{
+
+ picl_nodehdl_t nodeh;
+ char *c_args = NULL;
+
+ if (picl_get_root(&nodeh) != PICL_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+
+ if (picl_walk_tree_by_class(nodeh, PICL_CLASS_LOCATION,
+ (void *)c_args, pd_prt_slot_info) != PICL_SUCCESS) {
+ return (PD_INTERNAL_FAILURE);
+ }
+
+ return (PD_SUCCESS);
+
+}
+
+
+/*ARGSUSED*/
+int32_t
+
+pd_prt_slot_info(picl_nodehdl_t nodeh, void *c_args)
+{
+
+ char *valbuf;
+ char label_txt[30];
+ int unit_no = -1, ctr = 0;
+ picl_nodehdl_t childh;
+ picl_propinfo_t propinfo;
+ picl_prophdl_t proph;
+
+ /* if not immediate child of "chassis" node, ignore it */
+ if (pd_check_location_parent(nodeh) != PD_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+
+ /* get the label on the location */
+ if (picl_get_prop_by_name(nodeh, PICL_PROP_LABEL,
+ &proph) != PICL_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+ if (picl_get_propinfo(proph, &propinfo) != PICL_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+ valbuf = (char *) malloc(sizeof (char) * (propinfo.size));
+ if (valbuf == NULL)
+ return (PD_INTERNAL_FAILURE);
+
+ if (picl_get_propval(proph, (void *)valbuf, propinfo.size)
+ != PICL_SUCCESS) {
+ free(valbuf);
+ return (PD_INTERNAL_FAILURE);
+ }
+
+ while (valbuf[ctr] != ' ' && valbuf[ctr] != NULL) {
+ label_txt[ctr] = valbuf[ctr];
+ ++ctr;
+ }
+
+ label_txt[ctr++] = '\0';
+
+ if (valbuf[ctr] != NULL) {
+ unit_no = atoi(valbuf+ctr);
+ }
+
+ free(valbuf);
+
+ /* get the slot type for the location */
+ if (picl_get_prop_by_name(nodeh, PICL_PROP_SLOT_TYPE,
+ &proph) != PICL_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+ if (picl_get_propinfo(proph, & propinfo) != PICL_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+ valbuf = (char *) malloc(sizeof (char) * (propinfo.size));
+ if (valbuf == NULL)
+ return (PD_INTERNAL_FAILURE);
+
+ if (picl_get_propval(proph, (void *)valbuf,
+ propinfo.size) != PICL_SUCCESS) {
+ free(valbuf);
+ return (PD_INTERNAL_FAILURE);
+ }
+
+ if ((strcmp(valbuf, PD_CPCI_SLOT_TYPE) == 0) ||
+ (strcmp(valbuf, PD_PCI_SLOT_TYPE) == 0)) {
+ (void) pd_print_fruinfo_hdr();
+ log_printf("\n%s ", label_txt, 0);
+
+ /* For Snowbird no unit number is present on the label */
+ unit_no = 1;
+ log_printf(" %d Yes cPSB IO Slot\n", unit_no, 0);
+
+ if (picl_get_propval_by_name(nodeh, PICL_PROP_CHILD,
+ &childh, sizeof (childh)) == PICL_SUCCESS) {
+ pd_prt_cpci_condition(childh);
+ }
+ /* For Snowbird auto configuration is always enabled */
+ log_printf("%29s Properties:\n", PD_BLANK, 0);
+ log_printf("%31s auto-config = enabled\n", PD_BLANK, 0);
+ }
+
+
+ free(valbuf);
+ return (PD_SUCCESS);
+
+}
+
+
+
+static uint32_t
+pd_print_fruinfo_hdr()
+{
+
+ log_printf(
+ "\n %19s FRU Information \n",
+ PD_BLANK, 0);
+ log_printf(
+ "%11s ------------------------------------------------\n",
+ PD_BLANK, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "FRU FRU FRU Miscellaneous\n"), 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Type Unit# Present Information\n"), 0);
+ log_printf("---- ----- -------", 0);
+ log_printf(" --------------------------------\n", 0);
+ return (PD_SUCCESS);
+
+}
+
+static uint32_t
+pd_check_location_parent(picl_nodehdl_t nodeh)
+{
+
+ picl_nodehdl_t parenth;
+ char *prop_name;
+
+ if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT,
+ &parenth, sizeof (parenth)) != PICL_SUCCESS) {
+ return (PD_FAILURE);
+ }
+
+ prop_name = (char *) malloc(sizeof (char) * PICL_PROPNAMELEN_MAX);
+ if (prop_name == NULL) {
+ return (PD_FAILURE);
+ }
+
+ if (picl_get_propval_by_name(parenth, PICL_PROP_NAME, (void *)prop_name,
+ PICL_PROPNAMELEN_MAX) != PICL_SUCCESS) {
+ free(prop_name);
+ return (PD_FAILURE);
+ }
+
+ if (strcmp(prop_name, CHASSIS_NODE_NAME) == 0) {
+ free(prop_name);
+ return (PD_SUCCESS);
+ } else {
+ free(prop_name);
+ return (PD_FAILURE);
+ }
+
+}
+
+
+/*ARGSUSED*/
+static uint32_t
+pd_query_watchdog_state()
+{
+
+ picl_nodehdl_t nodehandle;
+ char *c_args = NULL;
+
+ if (picl_get_root(&nodehandle) != PICL_SUCCESS) {
+ return (PD_INTERNAL_FAILURE);
+ }
+
+ if (picl_walk_tree_by_class(nodehandle, PICL_CLASS_WATCHDOG_TIMER,
+ (void *)c_args, pd_check_wd_state) != PICL_SUCCESS)
+ return (PD_INTERNAL_FAILURE);
+
+ return (PD_SUCCESS);
+
+}
+
+/*ARGSUSED*/
+int
+pd_check_wd_state(picl_nodehdl_t nodeh, void *c_args)
+{
+
+ char *prop_name, *valbuf;
+ picl_propinfo_t propinfo;
+ picl_prophdl_t proph;
+
+ prop_name = (char *) malloc(sizeof (char) * PICL_PROPNAMELEN_MAX);
+ if (prop_name == NULL) {
+ return (PICL_WALK_TERMINATE);
+ }
+
+ if (picl_get_propval_by_name(nodeh, PICL_PROP_NAME,
+ (void *)prop_name, PICL_PROPNAMELEN_MAX) != PICL_SUCCESS) {
+ free(prop_name);
+ return (PICL_WALK_TERMINATE);
+ }
+
+ if ((picl_get_prop_by_name(nodeh, PICL_PROP_STATE,
+ &proph)) != PICL_SUCCESS) {
+ free(prop_name);
+ return (PICL_WALK_TERMINATE);
+ }
+
+ if ((picl_get_propinfo(proph, &propinfo)) != PICL_SUCCESS) {
+ free(prop_name);
+ return (PICL_WALK_TERMINATE);
+ }
+
+ valbuf = (char *) malloc(sizeof (char) * (propinfo.size));
+ if (valbuf == NULL) {
+ free(prop_name);
+ return (PICL_WALK_TERMINATE);
+ }
+
+ if ((picl_get_propval(proph, (void *)valbuf,
+ propinfo.size)) != PICL_SUCCESS) {
+ free(valbuf);
+ free(prop_name);
+ return (PICL_WALK_TERMINATE);
+ }
+
+ if (pd_hdr_prt) {
+ log_printf("\n Watch Dog Status \n", 0);
+ log_printf(" ---------------- \n", 0);
+ log_printf("Node Status\n", 0);
+ log_printf("---- ------\n", 0);
+ pd_hdr_prt = B_FALSE;
+ }
+
+ log_printf("%s ", prop_name, 0);
+ log_printf("%s\n", valbuf, 0);
+
+ free(prop_name);
+ free(valbuf);
+ return (PICL_WALK_CONTINUE);
+
+}
+
+
+static uint32_t
+pd_get_role_information()
+{
+
+ sc_reqmsg_t req_pkt;
+ sc_rspmsg_t rsp_pkt;
+ uint8_t usparc_role;
+
+ smc_init_smc_msg(&req_pkt, SMC_GET_ROLE_INFO,
+ DEFAULT_SEQN, 0);
+ smc_send_msg(-1, &req_pkt, &rsp_pkt, POLL_TIMEOUT);
+ usparc_role = rsp_pkt.data[1];
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "UltraSPARC Host Role\t\t\t"), 0);
+ if (usparc_role & 0x80) {
+ log_printf(
+ dgettext(TEXT_DOMAIN,
+ "System Board Computer (SBC)\n"), 0);
+ }
+ if (usparc_role & 0x40) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Standby System Board Computer (Standby SBC)\n"), 0);
+ }
+ if (usparc_role & 0x20) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Alternate System Board Computer (Alternate SBC)\n"), 0);
+ }
+ if (usparc_role & 0x10) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Satellite Board Computer (SAT)\n"), 0);
+ }
+ return (PD_SUCCESS);
+
+}
+
+
+static uint32_t
+pd_get_message_flags()
+{
+
+ sc_reqmsg_t req_pkt;
+ sc_rspmsg_t rsp_pkt;
+
+ smc_init_smc_msg(&req_pkt, SMC_GET_MESSAGE_FLAGS,
+ DEFAULT_SEQN, 0);
+ smc_send_msg(-1, &req_pkt, &rsp_pkt, POLL_TIMEOUT);
+
+ if (rsp_pkt.data[0] & 0x01) {
+ log_printf("Messages Available in queue Recieving\n", 0);
+ } else {
+ log_printf("No messages in queue for Recieving\n", 0);
+ }
+
+ return (PD_SUCCESS);
+
+
+}
+
+
+
+static uint32_t
+pd_get_reset_mode()
+{
+
+ sc_reqmsg_t req_pkt;
+ sc_rspmsg_t rsp_pkt;
+
+
+ smc_init_smc_msg(&req_pkt, SMC_GET_CONFIG_BLOCK,
+ DEFAULT_SEQN, 0);
+ smc_send_msg(-1, &req_pkt, &rsp_pkt, POLL_TIMEOUT);
+
+ log_printf("Reset Mode\t\t\t\t%x \n", rsp_pkt.data[2], 0);
+
+ return (PD_SUCCESS);
+
+}
+
+
+static uint32_t
+pd_get_sensor_reading()
+{
+
+
+ sc_reqmsg_t req_pkt;
+ sc_rspmsg_t rsp_pkt;
+
+ req_pkt.data[0] = 0x0e;
+
+ smc_init_smc_msg(&req_pkt, SMC_SENSOR_READING_GET,
+ DEFAULT_SEQN, 1);
+ smc_send_msg(-1, &req_pkt, &rsp_pkt, POLL_TIMEOUT);
+ log_printf("\nCPU Node Temperature Information\n", PD_BLANK, 0);
+ log_printf("--------------------------------\n", PD_BLANK, 0);
+ log_printf("Temperature Reading: %d\n\n", rsp_pkt.data[0], 0);
+
+ return (PD_SUCCESS);
+
+}
+
+
+static uint32_t
+pd_get_sensor_threshold()
+{
+
+
+ sc_reqmsg_t req_pkt;
+ sc_rspmsg_t rsp_pkt;
+ uint8_t thres_mask;
+ req_pkt.data[0] = 0x0e;
+
+ smc_init_smc_msg(&req_pkt, SMC_SENSOR_THRESHOLD_GET,
+ DEFAULT_SEQN, 1);
+ smc_send_msg(-1, &req_pkt, &rsp_pkt, POLL_TIMEOUT);
+ log_printf("Critical Threshold Information\n", 0);
+ log_printf("------------------------------\n", 0);
+
+ thres_mask = rsp_pkt.data[0];
+
+ if (thres_mask & 0x20) {
+ log_printf("High Power-Off Threshold %9s", PD_BLANK, 0);
+ if (rsp_pkt.data[6] & 0x80) {
+ log_printf("-%d\n",
+ (int)((uint8_t)~rsp_pkt.data[6] + 1), 0);
+ } else {
+ log_printf(" %d\n", rsp_pkt.data[6], 0);
+ }
+ }
+
+ if (thres_mask & 0x10) {
+ log_printf("High Shutdown Threshold %10s", PD_BLANK, 0);
+ if (rsp_pkt.data[5] & 0x80) {
+ log_printf("-%d\n",
+ (int)((uint8_t)~rsp_pkt.data[5] + 1), 0);
+ } else {
+ log_printf(" %d\n", rsp_pkt.data[5], 0);
+ }
+ }
+
+
+ if (thres_mask & 0x08) {
+ log_printf("High Warning Threshold %11s", PD_BLANK, 0);
+ if (rsp_pkt.data[4] & 0x80) {
+ log_printf("-%d\n",
+ (int)((uint8_t)~rsp_pkt.data[4] + 1), 0);
+ } else {
+ log_printf(" %d\n", rsp_pkt.data[4], 0);
+ }
+ }
+
+ if (thres_mask & 0x04) {
+ log_printf("Low Power Off Threshold %10s", PD_BLANK, 0);
+ if (rsp_pkt.data[3] & 0x80) {
+ log_printf("-%d\n",
+ (int)((uint8_t)~rsp_pkt.data[3] + 1), 0);
+ } else {
+ log_printf(" %d\n", rsp_pkt.data[3], 0);
+ }
+ }
+
+ if (thres_mask & 0x02) {
+ log_printf("Low Shutdown Threshold %11s", PD_BLANK, 0);
+ if (rsp_pkt.data[2] & 0x80) {
+ log_printf("-%d\n",
+ (int)((uint8_t)~rsp_pkt.data[2] + 1), 0);
+ } else {
+ log_printf(" %d\n", rsp_pkt.data[2], 0);
+ }
+ }
+
+ if (thres_mask & 0x01) {
+ log_printf("Low Warning Threshold %12s", PD_BLANK, 0);
+ if (rsp_pkt.data[1] & 0x80) {
+ log_printf("-%d\n",
+ (int)((uint8_t)~rsp_pkt.data[1] + 1), 0);
+ } else {
+ log_printf(" %d\n", rsp_pkt.data[1], 0);
+ }
+ }
+
+ return (PD_SUCCESS);
+
+}
+
+
+
+static uint32_t
+pd_prt_cpci_condition(picl_nodehdl_t nodeh)
+{
+
+ picl_propinfo_t propinfo;
+ picl_prophdl_t proph;
+ char *valbuf;
+
+
+ if (picl_get_prop_by_name(nodeh, PICL_PROP_CONDITION,
+ &proph) != PICL_SUCCESS) {
+ return (PD_FAILURE);
+ }
+
+ if (picl_get_propinfo(proph, &propinfo) != PICL_SUCCESS) {
+ return (PD_FAILURE);
+ }
+
+ valbuf = (char *) malloc(sizeof (char) * (propinfo.size));
+ if (valbuf == NULL) {
+ return (PD_FAILURE);
+ }
+
+ if (picl_get_propval(proph, (void *)valbuf,
+ propinfo.size) != PICL_SUCCESS) {
+ free(valbuf);
+ return (PD_FAILURE);
+ }
+
+
+ log_printf("%29s Condition : %s\n", PD_BLANK, valbuf, 0);
+
+ free(valbuf);
+ return (PD_SUCCESS);
+
+
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/starcat/Makefile b/usr/src/lib/libprtdiag_psr/sparc/starcat/Makefile
new file mode 100644
index 0000000000..a94e6cfc06
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/starcat/Makefile
@@ -0,0 +1,74 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/starcat/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= starcat.o
+
+include ../Makefile.com
+
+IFLAGS = -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+LINTFLAGS += $(IFLAGS)
+
+PLATFORM=SUNW,Sun-Fire-15000
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/starcat; $(MAKE) $(USR_PSM_LIB_DIR)
+
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+#
+# used for message files
+#
+POFILE= libprtdiag_psr_starcat.po
+POFILES= starcat.po
+
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/starcat.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/starcat/common/starcat.c b/usr/src/lib/libprtdiag_psr/sparc/starcat/common/starcat.c
new file mode 100644
index 0000000000..2d33aa2fbe
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/starcat/common/starcat.c
@@ -0,0 +1,1169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Starcat Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_STARCAT
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include <pdevinfo.h>
+#include <display.h>
+#include <pdevinfo_sun4u.h>
+#include <display_sun4u.h>
+#include <libprtdiag.h>
+
+#define HZ_TO_MHZ(x) (((x) + 500000) / 1000000)
+#define PORTID_TO_EXPANDER(p) (((p) >> 5) & 0x1f)
+#define PORTID_TO_SLOT(p) (((p) >> 3) & 0x1)
+#define PORTID_TO_INSTANCE(p) ((p) & 0x3)
+#define SCHIZO_COMPATIBLE "pci108e,8001"
+#define XMITS_COMPATIBLE "pci108e,8002"
+#define SC_BOARD_TYPE(id) (PORTID_TO_SLOT(id) ? "IO" : "SB")
+
+#ifndef TEXT_DOMAIN
+#define TEXT_DOMAIN "SYS_TEST"
+#endif /* TEXT_DOMAIN */
+
+#define DEFAULT_MAX_FREQ 66 /* 66 MHz */
+#define PCIX_MAX_FREQ 90 /* 90 MHz */
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (Starcat systems only)
+ */
+
+int do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag);
+void *get_prop_val(Prop *prop);
+Prop *find_prop(Prom_node *pnode, char *name);
+char *get_node_name(Prom_node *pnode);
+char *get_node_type(Prom_node *pnode);
+void add_node(Sys_tree *, Prom_node *);
+void display_pci(Board_node *);
+void display_ffb(Board_node *, int);
+void display_io_cards(struct io_card *list);
+void display_cpu_devices(Sys_tree *tree);
+void display_cpus(Board_node *board);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+void print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+
+/* Local Functions */
+static void starcat_disp_hw_revisions(Prom_node *root);
+static void display_io_max_bus_speed(struct io_card *p);
+static void display_io_slot_info(struct io_card *p);
+
+/* The bus max freq is determined based on board level in use */
+int board_bus_max_freq = DEFAULT_MAX_FREQ; /* 66MHz default */
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+void
+display_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+ Prom_node *pci;
+ Prom_node *card_node;
+ Prom_node *pci_bridge_node = NULL;
+ char *slot_name_arr[MAX_SLOTS_PER_IO_BD] = {NULL};
+ char *slot_name = NULL;
+ int slot_name_bits;
+ int slot_name_offset = 0;
+ char *child_name;
+ char *name, *type;
+ char buf[MAXSTRLEN];
+ int *int_val;
+ int pci_bus;
+ int pci_bridge = 0;
+ int pci_bridge_dev_no;
+ int child_dev_no;
+ int i;
+ int portid;
+ int version, *pversion;
+
+ if (board == NULL)
+ return;
+
+ /* Initialize all the common information */
+ card.display = TRUE;
+ card.board = board->board_num;
+ card.node_id = board->node_id;
+
+ /*
+ * Search for each schizo, then find/display all nodes under
+ * each schizo node found. Since the model property "SUNW,schizo"
+ * is not supported on Starcat, we must match on the compatible
+ * property "pci108e,8001".
+ */
+ for (pci = dev_find_node_by_compatible(board->nodes, SCHIZO_COMPATIBLE);
+ pci != NULL;
+ pci = dev_next_node_by_compatible(pci, SCHIZO_COMPATIBLE)) {
+
+ /* set max freq for this board */
+ board_bus_max_freq = DEFAULT_MAX_FREQ;
+ /*
+ * Find out if this is a PCI or cPCI IO Board.
+ * If "enum-impl" property exists in pci node => cPCI.
+ */
+ value = get_prop_val(find_prop(pci, "enum-impl"));
+ if (value == NULL) {
+ (void) sprintf(card.bus_type, "PCI");
+ } else {
+ (void) sprintf(card.bus_type, "cPCI");
+ }
+
+ if (strstr((char *)get_prop_val(
+ find_prop(pci, "compatible")), XMITS_COMPATIBLE)) {
+ sprintf(card.notes, "%s", XMITS_COMPATIBLE);
+ /*
+ * With XMITS 3.X and PCI-X mode, the bus speed
+ * can be higher than 66MHZ.
+ */
+ value = (int *)get_prop_val
+ (find_prop(pci, "module-revision#"));
+ if (value) {
+ pversion = (int *)value;
+ version = *pversion;
+ if (version >= 4)
+ board_bus_max_freq = PCIX_MAX_FREQ;
+ }
+ } else if (strstr((char *)get_prop_val(
+ find_prop(pci, "compatible")), SCHIZO_COMPATIBLE))
+ sprintf(card.notes, "%s", SCHIZO_COMPATIBLE);
+ else
+ sprintf(card.notes, " ");
+
+ /*
+ * Get slot-names property from parent node and
+ * store the individual slot names in an array.
+ * This is more general than Starcat requires, but
+ * it is correct, according to the slot-names property.
+ */
+ value = (char *)get_prop_val(find_prop(pci, "slot-names"));
+ if (value == NULL) {
+ /*
+ * No slot_names property. This could be an Xmits
+ * card, so check the child node for slot-names property
+ */
+ value = (char *)get_prop_val(
+ find_prop(pci->child, "slot-names"));
+ }
+
+ if (value != NULL) {
+ /* Get the 4 byte bitmask and pointer to first name */
+ slot_name_bits = *(int *)value;
+ if (slot_name_bits > 0)
+ slot_name_offset = slot_name_bits - 1;
+ slot_name = (char *)value + sizeof (int);
+
+ for (i = 0; i < MAX_SLOTS_PER_IO_BD; i++) {
+ if (! (slot_name_bits & (1 << i))) {
+ slot_name_arr[i] = (char *)NULL;
+ continue;
+ }
+
+ /*
+ * Save the name pointer into the array
+ * and advance it past the end of this
+ * slot name
+ */
+ slot_name_arr[i] = slot_name;
+ slot_name += strlen(slot_name) + 1;
+ }
+ slot_name = (char *)NULL;
+ }
+
+ /*
+ * Search for Children of this node ie. Cards.
+ * Note: any of these cards can be a pci-bridge
+ * that itself has children. If we find a
+ * pci-bridge we need to handle it specially.
+ */
+ card_node = pci->child;
+ while (card_node != NULL) {
+ pci_bridge = 0;
+
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(card_node, "name"));
+ if (name == NULL) {
+ card_node = card_node->sibling;
+ continue;
+ }
+
+ /*
+ * get dev# and func# for this card from the
+ * 'reg' property.
+ */
+ int_val = (int *)get_prop_val(
+ find_prop(card_node, "reg"));
+ if (int_val != NULL) {
+ card.dev_no = (((*int_val) & 0xF800) >> 11);
+ card.func_no = (((*int_val) & 0x700) >> 8);
+ } else {
+ card.dev_no = -1;
+ card.func_no = -1;
+ }
+
+ /*
+ * If this is a pci-bridge, then store it's dev#
+ * as its children nodes need this to get their slot#.
+ * We set the pci_bridge flag so that we know we are
+ * looking at a pci-bridge node. This flag gets reset
+ * every time we enter this while loop.
+ */
+
+ /*
+ * Check for a PCI-PCI Bridge for PCI and cPCI
+ * IO Boards using the name and type properties.
+ */
+ type = (char *)get_prop_val(
+ find_prop(card_node, "device_type"));
+ if ((type != NULL) &&
+ (strncmp(name, "pci", 3) == 0) &&
+ (strcmp(type, "pci") == 0)) {
+ pci_bridge_dev_no = card.dev_no;
+ pci_bridge_node = card_node;
+ pci_bridge = TRUE;
+ }
+
+ /*
+ * Get slot-names property from slot_names_arr.
+ * If we are the child of a pci_bridge we use the
+ * dev# of the pci_bridge as an index to get
+ * the slot number. We know that we are a child of
+ * a pci-bridge if our parent is the same as the last
+ * pci_bridge node found above.
+ */
+ if (card.dev_no != -1) {
+ /*
+ * We compare this card's parent node with the
+ * pci_bridge_node to see if it's a child.
+ */
+ if (card_node->parent == pci_bridge_node) {
+ /* use dev_no of pci_bridge */
+ child_dev_no = pci_bridge_dev_no - 1;
+ } else {
+ /* use card's own dev_no */
+ child_dev_no = card.dev_no - 1;
+ }
+
+ if (child_dev_no < MAX_SLOTS_PER_IO_BD &&
+ child_dev_no >= 0 &&
+ slot_name_arr
+ [child_dev_no + slot_name_offset] != NULL) {
+
+ slot_name = slot_name_arr[
+ child_dev_no + slot_name_offset];
+ } else
+ slot_name = (char *)NULL;
+
+ if (slot_name != NULL && slot_name[0] != '\0') {
+ (void) sprintf(card.slot_str, "%s",
+ slot_name);
+ } else {
+ (void) sprintf(card.slot_str, "-");
+ }
+ } else {
+ (void) sprintf(card.slot_str, "%c", '-');
+ }
+
+ /*
+ * Get the portid of the schizo that this card
+ * lives under.
+ */
+ portid = -1;
+ value = get_prop_val(find_prop(pci, "portid"));
+ if (value != NULL) {
+ portid = *(int *)value;
+ }
+ card.schizo_portid = portid;
+
+#ifdef DEBUG
+ (void) sprintf(card.notes, "%s portid [%d]"
+ " dev_no [%d] slot_name[%s] name_bits[%#x]",
+ card.notes, portid, card.dev_no,
+ ((slot_name != NULL) ? slot_name : "NULL"),
+ slot_name_bits);
+#endif /* DEBUG */
+
+ /*
+ * Find out whether this is PCI bus A or B
+ * using the 'reg' property.
+ */
+ int_val = (int *)get_prop_val
+ (find_prop(pci, "reg"));
+
+ if (int_val != NULL) {
+ int_val ++; /* skip over first integer */
+ pci_bus = ((*int_val) & 0x7f0000);
+ if (pci_bus == 0x600000)
+ card.pci_bus = 'A';
+ else if (pci_bus == 0x700000)
+ card.pci_bus = 'B';
+ else
+ card.pci_bus = '-';
+ } else {
+ card.pci_bus = '-';
+ }
+
+
+ /*
+ * Check for failed status.
+ */
+ if (node_failed(card_node))
+ strcpy(card.status, "fail");
+ else
+ strcpy(card.status, "ok");
+
+ /* Get the model of this card */
+ value = get_prop_val(find_prop(card_node, "model"));
+ if (value == NULL)
+ card.model[0] = '\0';
+ else {
+ (void) sprintf(card.model, "%s", (char *)value);
+ /*
+ * If we wish to exclude onboard devices
+ * (such as SBBC) then this is the place
+ * and here is how to do it:
+ *
+ * if (strcmp(card.model, "SUNW,sbbc") == 0) {
+ * card_node = card_node->sibling;
+ * continue;
+ * }
+ */
+ }
+
+ /*
+ * The card may have a "clock-frequency" but we
+ * are not interested in that. Instead we get the
+ * "clock-frequency" of the PCI Bus that the card
+ * resides on. PCI-A can operate at 33Mhz or 66Mhz
+ * depending on what card is plugged into the Bus.
+ * PCI-B always operates at 33Mhz.
+ *
+ */
+ int_val = get_prop_val(find_prop(pci,
+ "clock-frequency"));
+ if (int_val != NULL) {
+ card.freq = HZ_TO_MHZ(*int_val);
+ } else {
+ card.freq = -1;
+ }
+
+ /*
+ * Figure out how we want to display the name
+ */
+ value = get_prop_val(find_prop(card_node,
+ "compatible"));
+ if (value != NULL) {
+ /* use 'name'-'compatible' */
+ (void) sprintf(buf, "%s-%s", name,
+ (char *)value);
+ } else {
+ /* just use 'name' */
+ (void) sprintf(buf, "%s", name);
+ }
+ name = buf;
+
+ /*
+ * If this node has children, add the device_type
+ * of the child to the name value of this card.
+ */
+ child_name = (char *)get_node_name(card_node->child);
+ if ((card_node->child != NULL) &&
+ (child_name != NULL)) {
+ value = get_prop_val(find_prop(card_node->child,
+ "device_type"));
+ if (value != NULL) {
+ /* add device_type of child to name */
+ (void) sprintf(card.name, "%s/%s (%s)",
+ name, child_name,
+ (char *)value);
+ } else {
+ /* just add child's name */
+ (void) sprintf(card.name, "%s/%s",
+ name, child_name);
+ }
+ } else {
+ /* childless, just the card's name */
+ (void) sprintf(card.name, "%s", (char *)name);
+ }
+
+ /*
+ * If this is a pci-bridge, then add the word
+ * 'pci-bridge' to its model.
+ */
+ if (pci_bridge) {
+ if (card.model[0] == '\0')
+ (void) sprintf(card.model,
+ "%s", "pci-bridge");
+ else
+ (void) strcat(card.model,
+ "/pci-bridge");
+ }
+
+ /* insert this card in the list to be displayed later */
+ card_list = insert_io_card(card_list, &card);
+
+ /*
+ * If we are dealing with a pci-bridge, we need to move
+ * down to the children of this bridge, if there are
+ * any, otherwise its siblings.
+ *
+ * If not a bridge, we are either dealing with a regular
+ * card (in which case we move onto the sibling of this
+ * card) or we are dealing with a child of a pci-bridge
+ * (in which case we move onto the child's siblings or
+ * if there are no more siblings for this child, we
+ * move onto the parent's siblings). I hope you're
+ * getting all this, there will be an exam later.
+ */
+ if (pci_bridge) {
+ if (card_node->child != NULL)
+ card_node = card_node->child;
+ else
+ card_node = card_node->sibling;
+ } else {
+ /*
+ * If our parent is a pci-bridge but there
+ * are no more of its children to process we
+ * move back up to our parent's sibling,
+ * otherwise we move onto our own sibling.
+ */
+ if ((card_node->parent == pci_bridge_node) &&
+ (card_node->sibling == NULL))
+ card_node =
+ pci_bridge_node->sibling;
+ else
+ card_node = card_node->sibling;
+ }
+
+ } /* end while (card_node ...) loop */
+
+ } /* end for (pci ...) loop */
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+/*
+ * display_ffb
+ *
+ * There are no FFB's on a Starcat, however in the generic library,
+ * the display_ffb() function is implemented so we have to define an
+ * empty function here.
+ */
+/*ARGSUSED0*/
+void
+display_ffb(Board_node *board, int table)
+{
+}
+
+/*
+ * add_node
+ *
+ * This function adds a board node to the board structure where that
+ * that node's physical component lives.
+ */
+void
+add_node(Sys_tree *root, Prom_node *pnode)
+{
+ int portid = -1;
+ int nodeid = -1;
+ void *value;
+ Board_node *bnode;
+ Prom_node *p;
+ char *type;
+
+ /* Get the board number of this board from the portid prop */
+ if ((value = get_prop_val(find_prop(pnode, "portid"))) == NULL) {
+ if (type = get_node_type(pnode))
+ if (strcmp(type, "cpu") == 0)
+ value = get_prop_val(find_prop(pnode->parent,
+ "portid"));
+ }
+ if (value != NULL) {
+ portid = *(int *)value;
+ nodeid = PORTID_TO_EXPANDER(portid);
+ }
+
+ /* find the board node with the same board number */
+ if ((bnode = find_board(root, portid)) == NULL) {
+ bnode = insert_board(root, portid);
+ bnode->board_type = UNKNOWN_BOARD;
+ bnode->node_id = nodeid;
+ }
+
+ /* now attach this prom node to the board list */
+ /* Insert this node at the end of the list */
+ pnode->sibling = NULL;
+ if (bnode->nodes == NULL)
+ bnode->nodes = pnode;
+ else {
+ p = bnode->nodes;
+ while (p->sibling != NULL)
+ p = p->sibling;
+ p->sibling = pnode;
+ }
+}
+
+
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ char *hdrfmt = "%-10.10s %-4.4s %-4.4s %-4.4s %-4.4s %-4.4s"
+ " %-4.4s %-5.5s %-32.32s %-22.22s"
+#ifdef DEBUG
+ " %-22.22s"
+#endif /* DEBUG */
+ "\n";
+
+ static int banner = FALSE; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (banner == FALSE) {
+ log_printf(hdrfmt,
+ "", "", "", "",
+ gettext("Bus"),
+ gettext("Max"),
+ "", "", "", "",
+#ifdef DEBUG
+ "",
+#endif /* DEBUG */
+ 0);
+
+ log_printf(hdrfmt,
+ "",
+ gettext("IO"),
+ gettext("Port"),
+ gettext("Bus"),
+ gettext("Freq"),
+ gettext("Bus"),
+ gettext("Dev,"),
+ "", "", "",
+#ifdef DEBUG
+ "",
+#endif /* DEBUG */
+ 0);
+
+ log_printf(hdrfmt,
+ gettext("Slot ID"),
+ gettext("Type"),
+ gettext(" ID"),
+ gettext("Side"),
+ gettext("MHz"),
+ gettext("Freq"),
+ gettext("Func"),
+ gettext("State"),
+ gettext("Name"),
+ gettext("Model"),
+#ifdef DEBUG
+ gettext("Notes"),
+#endif /* DEBUG */
+ 0);
+
+ log_printf(hdrfmt,
+ "----------", "----", "----", "----", "----", "----",
+ "----", "-----", "--------------------------------",
+ "----------------------",
+#ifdef DEBUG
+ "----------------------",
+#endif /* DEBUG */
+ 0);
+
+ banner = TRUE;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+
+ display_io_slot_info(p);
+
+ display_io_max_bus_speed(p);
+
+ log_printf("\n", 0);
+ }
+}
+
+
+static void
+display_io_slot_info(struct io_card *p)
+{
+ /*
+ * Onboard devices are distinguished by Slot IDs that
+ * indicate only the I/O board. Plug-in cards indicate
+ * their leaf and Schizo.
+ */
+
+ if (p->slot_str[0] == '-') {
+ log_printf("/%-2s%02d ",
+ SC_BOARD_TYPE(p->board),
+ PORTID_TO_EXPANDER(p->board), 0);
+ } else {
+ char c;
+ if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
+ log_printf("/%-2s%02d/%s ",
+ SC_BOARD_TYPE(p->board),
+ PORTID_TO_EXPANDER(p->board),
+ p->slot_str, 0);
+ } else {
+ if (p->pci_bus == 'A')
+ c = '3';
+ else if (p->pci_bus == 'B') {
+ c = '5';
+ } else
+ c = '-';
+ log_printf("/%-2s%02d/C%cV%1d ",
+ SC_BOARD_TYPE(p->board),
+ PORTID_TO_EXPANDER(p->board), c,
+ PORTID_TO_INSTANCE(p->schizo_portid),
+ 0);
+ }
+ }
+ log_printf("%-4.4s ", gettext(p->bus_type), 0);
+ log_printf("%3d ", p->schizo_portid, 0);
+ log_printf(" %c ", p->pci_bus, 0);
+ log_printf(" %3d ", p->freq, 0);
+}
+
+#define BUS_SPEED_PRINT(speed) log_printf(" %d ", speed, 0)
+
+static void
+display_io_max_bus_speed(struct io_card *p)
+{
+ int speed = board_bus_max_freq;
+
+ switch (p->pci_bus) {
+ case 'A':
+ BUS_SPEED_PRINT(speed);
+ break;
+ case 'B':
+ if (strcmp(p->notes, XMITS_COMPATIBLE) == 0) {
+ if (PORTID_TO_INSTANCE(p->schizo_portid) == 0)
+ BUS_SPEED_PRINT(33);
+ else
+ BUS_SPEED_PRINT(speed);
+ } else
+ BUS_SPEED_PRINT(33);
+ break;
+ default:
+ log_printf(" - ", 0);
+ break;
+ }
+
+ log_printf("%-1d,%-1d ", p->dev_no, p->func_no, 0);
+ log_printf("%-5.5s ", gettext(p->status), 0);
+ log_printf("%-32.32s%c ", p->name,
+ ((strlen(p->name) > 32) ? '+' : ' '), 0);
+ log_printf("%-22.22s%c", p->model,
+ ((strlen(p->model) > 22) ? '+' : ' '), 0);
+#ifdef DEBUG
+ log_printf(" %s", p->notes, 0);
+#endif /* DEBUG */
+}
+
+void
+display_cpu_devices(Sys_tree *tree)
+{
+ Board_node *bnode;
+ char *hdrfmt = "%-8.8s %-7.7s %-4.4s %-4.4s %-7.7s %-4.4s\n";
+
+ (void) textdomain(TEXT_DOMAIN);
+
+ /*
+ * Display the table header for CPUs . Then display the CPU
+ * frequency, cache size, and processor revision of all cpus.
+ */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(gettext(" CPUs "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n\n", 0);
+
+ log_printf(hdrfmt,
+ "",
+ gettext("CPU "),
+ gettext("Run"),
+ gettext(" E$"),
+ gettext(" CPU"),
+ gettext("CPU"), 0);
+
+ log_printf(hdrfmt,
+ gettext("Slot ID"),
+ gettext("ID "),
+ gettext("MHz"),
+ gettext(" MB"),
+ gettext("Impl."),
+ gettext("Mask"), 0);
+
+ log_printf(hdrfmt,
+ "--------", "-------", "----", "----", "-------", "----", 0);
+
+ /* Now display all of the cpus on each board */
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ display_cpus(bnode);
+ bnode = bnode->next;
+ }
+
+ log_printf("\n", 0);
+}
+
+/*
+ * Display the CPUs present on this board.
+ */
+void
+display_cpus(Board_node *board)
+{
+ Prom_node *cpu;
+ int freq; /* CPU clock frequency */
+ int ecache_size; /* External cache size */
+ int *impl;
+ int *mask;
+ int decoded_mask;
+ int *cpuid;
+ int *coreid;
+ int cpuid_prev = -1;
+ int ecache_size_prev = 0;
+
+ (void) textdomain(TEXT_DOMAIN);
+ /*
+ * display the CPUs' operating frequency, cache size, impl. field
+ * and mask revision.
+ */
+ for (cpu = dev_find_type(board->nodes, "cpu"); cpu != NULL;
+ cpu = dev_next_type(cpu, "cpu")) {
+
+ freq = HZ_TO_MHZ(get_cpu_freq(cpu));
+ ecache_size = get_ecache_size(cpu);
+ impl = (int *)get_prop_val(find_prop(cpu, "implementation#"));
+ mask = (int *)get_prop_val(find_prop(cpu, "mask#"));
+ cpuid = (int *)get_prop_val(find_prop(cpu, "cpuid"));
+ if (cpuid == NULL)
+ cpuid = &board->board_num;
+
+ /* Do not display a failed CPU node */
+ if ((freq == 0) || (impl == 0) || (node_failed(cpu)))
+ continue;
+
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ coreid = (int *)get_prop_val(find_prop(cpu,
+ "reg"));
+ if (coreid == NULL) {
+ continue;
+ }
+
+ /*
+ * The assumption is made that 2 cores will always be
+ * listed together in the device tree. If either core
+ * is "bad" then the FRU will not be listed.
+ */
+ if (cpuid_prev == -1) {
+ cpuid_prev = *cpuid;
+ ecache_size_prev = ecache_size;
+ continue;
+ } else {
+ /*
+ * Jaguar has a split E$, so the size for both
+ * cores must be added together to get the total
+ * size for the entire chip.
+ *
+ * Panther E$ (L3) is logically shared, so the
+ * total size is equal to the core size.
+ */
+ if (IS_JAGUAR(*impl)) {
+ ecache_size += ecache_size_prev;
+ }
+
+ ecache_size_prev = 0;
+ }
+ }
+
+ /*
+ * Print out cpu data.
+ *
+ * Slot ID
+ */
+ log_printf("/%-2s%02d/P%1d ",
+ SC_BOARD_TYPE(*cpuid),
+ PORTID_TO_EXPANDER(*cpuid),
+ PORTID_TO_INSTANCE(*cpuid), 0);
+
+ /* CPU ID */
+ if (CPU_IMPL_IS_CMP(*impl)) {
+ log_printf("%3d,%3d ", cpuid_prev,
+ *cpuid, 0);
+ cpuid_prev = -1;
+ } else
+ log_printf("%3d ", *cpuid, 0);
+
+ /* Running frequency */
+ log_printf("%4d ", freq, 0);
+
+ /* Ecache size */
+ if (ecache_size == 0)
+ log_printf("%-4.4s ", gettext("N/A"), 0);
+ else
+ log_printf("%4.1f ",
+ (float)ecache_size / (float)(1<<20),
+ 0);
+
+ /* Implementation */
+ switch (*impl) {
+ case CHEETAH_IMPL:
+ log_printf("%-7.7s ",
+ gettext("US-III"), 0);
+ break;
+ case CHEETAH_PLUS_IMPL:
+ log_printf("%-7.7s ",
+ gettext("US-III+"), 0);
+ break;
+ case JAGUAR_IMPL:
+ log_printf("%-7.7s ",
+ gettext("US-IV"), 0);
+ break;
+ case PANTHER_IMPL:
+ log_printf("%-7.7s ",
+ gettext("US-IV+"), 0);
+ break;
+ default:
+ log_printf("%-7x ", *impl, 0);
+ break;
+ }
+
+ /* CPU Mask */
+ if (mask == NULL) {
+ log_printf("%-4.4s", gettext("N/A"), 0);
+ } else {
+ if (IS_CHEETAH(*impl))
+ decoded_mask = REMAP_CHEETAH_MASK(*mask);
+ else
+ decoded_mask = *mask;
+
+ log_printf("%d.%d",
+ (decoded_mask >> 4) & 0xf,
+ decoded_mask & 0xf, 0);
+ }
+
+ log_printf("\n", 0);
+ }
+}
+
+
+/*ARGSUSED1*/
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode = tree->bd_list;
+ char *hdrfmt = "\n%-11.11s %-4.4s %-7.7s %-7.7s %-8.8s %-6.6s"
+ " %-10.10s %-10.10s";
+
+ (void) textdomain(TEXT_DOMAIN);
+
+ log_printf("=========================", 0);
+ log_printf(gettext(" Memory Configuration "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+
+ log_printf(hdrfmt,
+ "", "",
+ gettext("Logical"),
+ gettext("Logical"),
+ gettext("Logical"),
+ "", "", "", 0);
+
+ log_printf(hdrfmt,
+ "",
+ gettext("Port"),
+ gettext("Bank"),
+ gettext("Bank"),
+ gettext("Bank"),
+ gettext(" DIMM"),
+ gettext("Interleave"),
+ gettext("Interleave"), 0);
+
+ log_printf(hdrfmt,
+ gettext("Slot ID"),
+ gettext(" ID"),
+ gettext("Number"),
+ gettext("Size"),
+ gettext("Status"),
+ gettext(" Size"),
+ gettext("Factor"),
+ gettext("Segment"), 0);
+
+ log_printf(hdrfmt,
+ "-----------", "----", "-------", "-------", "--------",
+ "------", "----------", "----------", 0);
+
+ while (bnode != NULL) {
+ if (get_us3_mem_regs(bnode)) {
+ log_printf(
+ gettext(
+ "\nFailed to get memory information.\n"),
+ 0);
+ return;
+ }
+ bnode = bnode->next;
+ }
+
+ /* Display what we have found */
+ display_us3_banks();
+}
+
+
+/*
+ * This function provides Starcat's formatting of the memory config
+ * information that get_us3_mem_regs() and display_us3_banks() code has
+ * gathered. It overrides the generic print_us3_memory_line() code
+ * which prints an error message.
+ */
+void
+print_us3_memory_line(int portid, int bank_id, uint64_t bank_size,
+ char *bank_status, uint64_t dimm_size, uint32_t intlv, int seg_id)
+{
+ (void) textdomain(TEXT_DOMAIN);
+
+ /* Slot ID */
+ log_printf("\n/%-2s%02d/P%1d/B%1d ",
+ SC_BOARD_TYPE(portid), PORTID_TO_EXPANDER(portid),
+ PORTID_TO_INSTANCE(portid), (bank_id & 0x1), 0);
+
+ /* Port ID */
+ log_printf("%3d ", portid, 0);
+
+ /* Logical Bank Number */
+ log_printf(" %1d ", (bank_id & 0x3), 0);
+
+ /* Logical Bank Size */
+ log_printf("%4lldMB ", bank_size, 0);
+
+ /* Logical Bank Status */
+ log_printf("%-8.8s ", gettext(bank_status), 0);
+
+ /* DIMM Size */
+ log_printf("%4lldMB ", dimm_size, 0);
+
+ /* Interleave Factor */
+ log_printf(" %2d-%-3.3s ", intlv, gettext("way"), 0);
+
+ /* Interleave Segment */
+ log_printf(" %3d", seg_id, 0);
+}
+
+/*ARGSUSED2*/
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ (void) textdomain(TEXT_DOMAIN);
+
+ /* Print the header */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(gettext(" Diagnostic Information "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n\n", 0);
+ log_printf(gettext("For diagnostic information,"), 0);
+ log_printf("\n", 0);
+ log_printf(gettext(
+ "see /var/opt/SUNWSMS/adm/[A-R]/messages on the SC."),
+ 0);
+ log_printf("\n", 0);
+
+ /* Print the PROM revisions here */
+ starcat_disp_hw_revisions(root);
+ }
+}
+
+/*
+ * local functions - functions that are only needed inside this library
+ */
+
+static void
+starcat_disp_hw_revisions(Prom_node *root)
+{
+ Prom_node *pnode;
+ char *version;
+
+ (void) textdomain(TEXT_DOMAIN);
+
+ /* Print the header */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(gettext(" Hardware Revisions "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n\n", 0);
+
+ /* Display Prom revision header */
+ log_printf(gettext("OpenBoot firmware revision:"), 0);
+ log_printf("\n---------------------------\n", 0);
+
+ /*
+ * Display OBP version info
+ */
+ pnode = dev_find_node(root, "openprom");
+ if (pnode != NULL) {
+ version = (char *)get_prop_val(find_prop(pnode, "version"));
+ log_printf("%s\n\n", version, 0);
+ }
+}
+
+/*
+ * We call do_devinfo() in order to use the libdevinfo device tree
+ * instead of OBP's device tree.
+ */
+int
+do_prominfo(int syserrlog, char *pgname, int log_flag, int prt_flag)
+{
+
+ return (do_devinfo(syserrlog, pgname, log_flag, prt_flag));
+
+}
+
+/*
+ * return the property value for the Prop
+ * passed in. (When using libdevinfo)
+ */
+void *
+get_prop_val(Prop *prop)
+{
+ if (prop == NULL)
+ return (NULL);
+
+ return ((void *)(prop->value.val_ptr));
+}
+
+/*
+ * Search a Prom node and retrieve the property with the correct
+ * name. (When using libdevinfo)
+ */
+Prop *
+find_prop(Prom_node *pnode, char *name)
+{
+ Prop *prop;
+
+ if (pnode == NULL)
+ return (NULL);
+
+ for (prop = pnode->props; prop != NULL; prop = prop->next) {
+ if (prop->name.val_ptr != NULL &&
+ strcmp((char *)(prop->name.val_ptr), name) == 0)
+ break;
+ }
+
+ return (prop);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the name property.
+ * (When using libdevinfo)
+ */
+char *
+get_node_name(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("name", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
+
+/*
+ * This function searches through the properties of the node passed in
+ * and returns a pointer to the value of the device_type property.
+ * (When using libdevinfo)
+ */
+char *
+get_node_type(Prom_node *pnode)
+{
+ Prop *prop;
+
+ if (pnode == NULL) {
+ return (NULL);
+ }
+
+ prop = pnode->props;
+ while (prop != NULL) {
+ if (strcmp("device_type", (char *)prop->name.val_ptr) == 0)
+ return (prop->value.val_ptr);
+ prop = prop->next;
+ }
+ return (NULL);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/starfire/Makefile b/usr/src/lib/libprtdiag_psr/sparc/starfire/Makefile
new file mode 100644
index 0000000000..11714b079e
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/starfire/Makefile
@@ -0,0 +1,70 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/starfire/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= starfire.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+LINTFLAGS += $(IFLAGS)
+
+PLATFORM=SUNW,Ultra-Enterprise-10000
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/starfire; $(MAKE) $(USR_PSM_LIB_DIR)
+
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+POFILE= libprtdiag_psr_starfire.po
+POFILES= starfire.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/starfire.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/starfire/common/starfire.c b/usr/src/lib/libprtdiag_psr/sparc/starfire/common/starfire.c
new file mode 100644
index 0000000000..6620ebbb89
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/starfire/common/starfire.c
@@ -0,0 +1,224 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Starfire Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_STARFIRE
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (starfire systems only)
+ */
+int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_mid(int mid);
+void display_pci(Board_node *);
+Prom_node *find_device(Board_node *, int, char *);
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+#ifdef lint
+ tree = tree;
+ kstats = kstats;
+#endif
+ return (0);
+}
+
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode;
+ char indent_str[] = " ";
+
+#ifdef lint
+ grps = grps;
+#endif
+
+ /* Print the header for the memory section. */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n\n", 0);
+
+ /* Print the header for the memory section. */
+ log_printf(indent_str, 0);
+ log_printf("Memory Units: Size \n", 0);
+ log_printf(indent_str, 0);
+ log_printf("0: MB 1: MB 2: MB 3: MB\n", 0);
+ log_printf(indent_str, 0);
+ log_printf("----- ----- ----- ----- \n", 0);
+
+ /* Run thru the board and display its memory if any */
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ Prom_node *pnode;
+ unsigned int *memsize;
+ unsigned int mbyte = 1024*1024;
+
+ /*
+ * Find the mem-unit of the board.
+ * If the board has memory, a mem-unit pnode should
+ * be there.
+ */
+ pnode = dev_find_node(bnode->nodes, "mem-unit");
+
+ if (pnode != NULL) {
+ /* there is a mem-unit in the board */
+
+ /* Print the board header */
+ log_printf("Board%2d ", bnode->board_num, 0);
+
+ memsize = get_prop_val(find_prop(pnode, "size"));
+
+ log_printf(" %4d %4d %4d %4d \n",
+ memsize[0]/mbyte, memsize[1]/mbyte,
+ memsize[2]/mbyte, memsize[3]/mbyte, 0);
+ }
+ bnode = bnode->next;
+ }
+ log_printf("\n", 0);
+}
+
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+#ifdef lint
+ tree = tree;
+ kstats = kstats;
+#endif
+}
+
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+
+ char hostname[128]; /* used for starfire output */
+ struct utsname uts_buf;
+
+#ifdef lint
+ flag = flag;
+ root = root;
+ tree = tree;
+ kstats = kstats;
+#endif
+
+ /*
+ * Get hostname from system Banner
+ */
+ (void) uname(&uts_buf);
+ strcpy(hostname, uts_buf.nodename);
+
+ /*
+ * We can't display diagnostic/env information for starfire.
+ * The diagnostic information may be displayed through
+ * commands in ssp.
+ */
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\nFor diagnostic information,"), 0);
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN, "see /var/opt/SUNWssp/adm/%s/messages "
+ "on the SSP."), hostname, 0);
+ log_printf("\n", 0);
+}
+
+void
+display_mid(int mid)
+{
+ log_printf(" %2d ", mid % 4, 0);
+}
+
+/*
+ * display_pci
+ * Call the generic psycho version of this function.
+ */
+void
+display_pci(Board_node *board)
+{
+ display_psycho_pci(board);
+}
+
+/*
+ * Find the device on the current board with the requested device ID
+ * and name. If this rountine is passed a NULL pointer, it simply returns
+ * NULL.
+ */
+Prom_node *
+find_device(Board_node *board, int id, char *name)
+{
+ Prom_node *pnode;
+ int mask;
+
+ /* find the first cpu node */
+ pnode = dev_find_node(board->nodes, name);
+
+ mask = 0x7F;
+ while (pnode != NULL) {
+ if ((get_id(pnode) & mask) == id)
+ return (pnode);
+
+ pnode = dev_next_node(pnode, name);
+ }
+ return (NULL);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/sunfire/Makefile b/usr/src/lib/libprtdiag_psr/sparc/sunfire/Makefile
new file mode 100644
index 0000000000..4cc1ed5bfd
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/sunfire/Makefile
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/sunfire/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= sunfire.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+LINTFLAGS += $(IFLAGS)
+
+PLATFORM=SUNW,Ultra-Enterprise
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS)
+
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+
+POFILE= libprtdiag_psr_sunfire.po
+POFILES= sunfire.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/sunfire.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/sunfire/common/sunfire.c b/usr/src/lib/libprtdiag_psr/sparc/sunfire/common/sunfire.c
new file mode 100644
index 0000000000..cfb83f25a0
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/sunfire/common/sunfire.c
@@ -0,0 +1,2284 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Sunfire Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_SUNFIRE
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/* Macros for manipulating UPA IDs and board numbers on Sunfire. */
+#define bd_to_upa(bd) ((bd) << 1)
+#define upa_to_bd(upa) ((upa) >> 1)
+
+#define MAX_MSGS 64
+
+extern int print_flag;
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (sunfire systems only)
+ */
+int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+int disp_fail_parts(Sys_tree *tree);
+void display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats,
+ struct grp_info *grps, struct mem_total *memory_total);
+void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_mid(int mid);
+void display_pci(Board_node *);
+void display_ffb(Board_node *, int);
+void add_node(Sys_tree *, Prom_node *);
+void resolve_board_types(Sys_tree *);
+
+/* local functions */
+static void build_mem_tables(Sys_tree *, struct system_kstat_data *,
+ struct grp_info *);
+static void get_mem_total(struct mem_total *, struct grp_info *);
+static int disp_fault_list(Sys_tree *, struct system_kstat_data *);
+static int disp_err_log(struct system_kstat_data *);
+static int disp_env_status(struct system_kstat_data *);
+static int disp_keysw_and_leds(struct system_kstat_data *);
+static void sunfire_disp_prom_versions(Sys_tree *);
+static void erase_msgs(char **);
+static void display_msgs(char **msgs, int board);
+static void sunfire_disp_asic_revs(Sys_tree *, struct system_kstat_data *);
+static void display_hp_boards(struct system_kstat_data *);
+static int disp_parts(char **, u_longlong_t, int);
+/*
+ * Error analysis routines. These routines decode data from specified
+ * error registers. They are meant to be used for decoding the fatal
+ * hardware reset data passed to the kernel by sun4u POST.
+ */
+static int analyze_cpu(char **, int, u_longlong_t);
+static int analyze_ac(char **, u_longlong_t);
+static int analyze_dc(int, char **, u_longlong_t);
+
+#define RESERVED_STR "Reserved"
+
+#define MAX_PARTS 5
+#define MAX_FRUS 5
+
+#define MAXSTRLEN 256
+
+/* Define special bits */
+#define UPA_PORT_A 0x1
+#define UPA_PORT_B 0x2
+
+
+/*
+ * These defines comne from async.h, but it does not get exported from
+ * uts/sun4u/sys, so they must be redefined.
+ */
+#define P_AFSR_ISAP 0x0000000040000000ULL /* incoming addr. parity err */
+#define P_AFSR_ETP 0x0000000020000000ULL /* ecache tag parity */
+#define P_AFSR_ETS 0x00000000000F0000ULL /* cache tag parity syndrome */
+#define ETS_SHIFT 16
+
+/* List of parts possible */
+#define RSVD_PART 1
+#define UPA_PART 2
+#define UPA_A_PART 3
+#define UPA_B_PART 4
+#define SOFTWARE_PART 5
+#define AC_PART 6
+#define AC_ANY_PART 7
+#define DTAG_PART 8
+#define DTAG_A_PART 9
+#define DTAG_B_PART 10
+#define FHC_PART 11
+#define BOARD_PART 12
+#define BOARD_ANY_PART 13
+#define BOARD_CONN_PART 14
+#define BACK_PIN_PART 15
+#define BACK_TERM_PART 16
+#define CPU_PART 17
+
+/* List of possible parts */
+static char *part_str[] = {
+ "", /* 0, a placeholder for indexing */
+ "", /* 1, reserved strings shouldn't be printed */
+ "UPA devices", /* 2 */
+ "UPA Port A device", /* 3 */
+ "UPA Port B device", /* 4 */
+ "Software error", /* 5 */
+ "Address Controller", /* 6 */
+ "Undetermined Address Controller in system", /* 7 */
+ "Data Tags", /* 8 */
+ "Data Tags for UPA Port A", /* 9 */
+ "Data Tags for UPA Port B", /* 10 */
+ "Firehose Controller", /* 11 */
+ "This Board", /* 12 */
+ "Undetermined Board in system", /* 13 */
+ "Board Connector", /* 14 */
+ "Centerplane pins ", /* 15 */
+ "Centerplane terminators", /* 16 */
+ "CPU", /* 17 */
+};
+
+/* Ecache parity error messages. Tells which bits are bad. */
+static char *ecache_parity[] = {
+ "Bits 7:0 ",
+ "Bits 15:8 ",
+ "Bits 21:16 ",
+ "Bits 24:22 "
+};
+
+
+struct ac_error {
+ char *error;
+ int part[MAX_PARTS];
+};
+
+typedef struct ac_error ac_err;
+
+/*
+ * Hardware error register meanings, failed parts and FRUs. The
+ * following strings are indexed for the bit positions of the
+ * corresponding bits in the hardware. The code checks bit x of
+ * the hardware error register and prints out string[x] if the bit
+ * is turned on.
+ *
+ * This database of parts which are probably failed and which FRU's
+ * to replace was based on knowledge of the Sunfire Programmers Spec.
+ * and discussions with the hardware designers. The order of the part
+ * lists and consequently the FRU lists are in the order of most
+ * likely cause first.
+ */
+static ac_err ac_errors[] = {
+ { /* 0 */
+ "UPA Port A Error",
+ { UPA_A_PART, 0, 0, 0, 0 },
+ },
+ { /* 1 */
+ "UPA Port B Error",
+ { UPA_B_PART, 0, 0, 0, 0 },
+ },
+ { /* 2 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 3 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 4 */
+ "UPA Interrupt to unmapped destination",
+ { BOARD_PART, 0, 0, 0, 0 },
+ },
+ { /* 5 */
+ "UPA Non-cacheable write to unmapped destination",
+ { BOARD_PART, 0, 0, 0, 0 },
+ },
+ { /* 6 */
+ "UPA Cacheable write to unmapped destination",
+ { BOARD_PART, 0, 0, 0, 0 },
+ },
+ { /* 7 */
+ "Illegal Write Received",
+ { BOARD_PART, 0, 0, 0, 0 },
+ },
+ { /* 8 */
+ "Local Writeback match with line in state S",
+ { AC_PART, DTAG_PART, 0, 0, 0 },
+ },
+ { /* 9 */
+ "Local Read match with valid line in Tags",
+ { AC_PART, DTAG_PART, 0, 0, 0 },
+ },
+ { /* 10 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 11 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 12 */
+ "Tag and Victim were valid during lookup",
+ { AC_PART, DTAG_PART, 0, 0, 0 },
+ },
+ { /* 13 */
+ "Local Writeback matches a victim in state S",
+ { AC_PART, CPU_PART, 0, 0, 0 },
+ },
+ { /* 14 */
+ "Local Read matches valid line in victim buffer",
+ { AC_PART, CPU_PART, 0, 0, 0 },
+ },
+ { /* 15 */
+ "Local Read victim bit set and victim is S state",
+ { AC_PART, CPU_PART, 0, 0, 0 },
+ },
+ { /* 16 */
+ "Local Read Victim bit set and Valid Victim Buffer",
+ { AC_PART, CPU_PART, 0, 0, 0 },
+ },
+ { /* 17 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 18 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 19 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 20 */
+ "UPA Transaction received in Sleep mode",
+ { AC_PART, 0, 0, 0, 0 },
+ },
+ { /* 21 */
+ "P_FERR error P_REPLY received from UPA Port",
+ { CPU_PART, AC_PART, 0, 0, 0 },
+ },
+ { /* 22 */
+ "Illegal P_REPLY received from UPA Port",
+ { CPU_PART, AC_PART, 0, 0, 0 },
+ },
+ { /* 23 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 24 */
+ "Timeout on a UPA Master Port",
+ { AC_ANY_PART, BOARD_ANY_PART, 0, 0, 0 },
+ },
+ { /* 25 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 26 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 27 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 28 */
+ "Coherent Transactions Queue Overflow Error",
+ { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, AC_ANY_PART, 0 },
+ },
+ { /* 29 */
+ "Non-cacheable Request Queue Overflow Error",
+ { AC_PART, AC_ANY_PART, 0, 0, 0 },
+ },
+ { /* 30 */
+ "Non-cacheable Reply Queue Overflow Error",
+ { AC_PART, 0, 0, 0, 0 },
+ },
+ { /* 31 */
+ "PREQ Queue Overflow Error",
+ { CPU_PART, AC_PART, 0, 0, 0 },
+ },
+ { /* 32 */
+ "Foreign DID CAM Overflow Error",
+ { AC_PART, AC_ANY_PART, 0, 0, 0 },
+ },
+ { /* 33 */
+ "FT->UPA Queue Overflow Error",
+ { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, AC_ANY_PART, 0 },
+ },
+ { /* 34 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 35 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 36 */
+ "UPA Port B Dtag Parity Error",
+ { DTAG_B_PART, AC_PART, 0, 0, 0 },
+ },
+ { /* 37 */
+ "UPA Port A Dtag Parity Error",
+ { DTAG_A_PART, AC_PART, 0, 0, 0 },
+ },
+ { /* 38 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 39 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 40 */
+ "UPA Bus Parity Error",
+ { UPA_PART, AC_PART, 0, 0, 0 },
+ },
+ { /* 41 */
+ "Data ID Line Mismatch",
+ { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, 0, 0 },
+ },
+ { /* 42 */
+ "Arbitration Line Mismatch",
+ { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, 0, 0 },
+ },
+ { /* 43 */
+ "Shared Line Parity Mismatch",
+ { BACK_PIN_PART, BOARD_CONN_PART, AC_PART, 0, 0 },
+ },
+ { /* 44 */
+ "FireTruck Control Line Parity Error",
+ { AC_PART, BACK_PIN_PART, 0, 0, 0 },
+ },
+ { /* 45 */
+ "FireTruck Address Bus Parity Error",
+ { AC_PART, BACK_PIN_PART, 0, 0, 0 },
+ },
+ { /* 46 */
+ "Internal RAM Parity Error",
+ { AC_PART, 0, 0, 0, 0 },
+ },
+ { /* 47 */
+ NULL,
+ { RSVD_PART, 0, 0, 0, 0 },
+ },
+ { /* 48 */
+ "Internal Hardware Error",
+ { AC_PART, 0, 0, 0, 0 },
+ },
+ { /* 49 */
+ "FHC Communications Error",
+ { FHC_PART, AC_PART, 0, 0, 0 },
+ },
+ /* Bits 50-63 are reserved in this implementation. */
+};
+
+
+#define MAX_BITS (sizeof (ac_errors)/ sizeof (ac_err))
+
+/*
+ * There are only two error bits in the DC shadow chain that are
+ * important. They indicate an overflow error and a parity error,
+ * respectively. The other bits are not error bits and should not
+ * be checked for.
+ */
+#define DC_OVERFLOW 0x2
+#define DC_PARITY 0x4
+
+static char dc_overflow_txt[] = "Board %d DC %d Overflow Error";
+static char dc_parity_txt[] = "Board %d DC %d Parity Error";
+
+/* defines for the sysio */
+#define UPA_APERR 0x4
+
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ int exit_code = 0; /* init to all OK */
+
+ /*
+ * silently check for any types of machine errors
+ */
+ print_flag = 0;
+ if (disp_fail_parts(tree) || disp_fault_list(tree, kstats) ||
+ disp_err_log(kstats) || disp_env_status(kstats)) {
+ /* set exit_code to show failures */
+ exit_code = 1;
+ }
+ print_flag = 1;
+
+ return (exit_code);
+}
+
+/*
+ * disp_fail_parts
+ *
+ * Display the failed parts in the system. This function looks for
+ * the status property in all PROM nodes. On systems where
+ * the PROM does not supports passing diagnostic information
+ * thruogh the device tree, this routine will be silent.
+ */
+int
+disp_fail_parts(Sys_tree *tree)
+{
+ int exit_code;
+ int system_failed = 0;
+ Board_node *bnode = tree->bd_list;
+ Prom_node *pnode;
+
+ exit_code = 0;
+
+ /* go through all of the boards looking for failed units. */
+ while (bnode != NULL) {
+ /* find failed chips */
+ pnode = find_failed_node(bnode->nodes);
+ if ((pnode != NULL) && !system_failed) {
+ system_failed = 1;
+ exit_code = 1;
+ if (print_flag == 0) {
+ return (exit_code);
+ }
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "Failed Field Replaceable Units (FRU) "
+ "in System:\n"), 0);
+ log_printf("=========================="
+ "====================\n", 0);
+ }
+
+ while (pnode != NULL) {
+ void *value;
+ char *name; /* node name string */
+ char *type; /* node type string */
+ char *board_type = NULL;
+
+ value = get_prop_val(find_prop(pnode, "status"));
+ name = get_node_name(pnode);
+
+ /* sanity check of data retreived from PROM */
+ if ((value == NULL) || (name == NULL)) {
+ pnode = next_failed_node(pnode);
+ continue;
+ }
+
+ /* Find the board type of this board */
+ if (bnode->board_type == CPU_BOARD) {
+ board_type = "CPU";
+ } else {
+ board_type = "IO";
+ }
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%s unavailable on %s Board #%d\n"),
+ name, board_type, bnode->board_num, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tPROM fault string: %s\n"), value, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tFailed Field Replaceable Unit is "), 0);
+
+ /*
+ * Determine whether FRU is CPU module, system
+ * board, or SBus card.
+ */
+ if ((name != NULL) && (strstr(name, "sbus"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "SBus Card %d\n"),
+ get_sbus_slot(pnode), 0);
+
+ } else if (((name = get_node_name(pnode->parent)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "PCI Card %d"),
+ get_pci_device(pnode), 0);
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "cpu"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "UltraSPARC module "
+ "Board %d Module %d\n"),
+ get_id(pnode) >> 1,
+ get_id(pnode) & 0x1);
+
+ } else {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "%s board %d\n"), board_type,
+ bnode->board_num, 0);
+ }
+ pnode = next_failed_node(pnode);
+ }
+ bnode = bnode->next;
+ }
+
+ if (!system_failed) {
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "No failures found in System\n"), 0);
+ log_printf("===========================\n", 0);
+ }
+
+ if (system_failed)
+ return (1);
+ else
+ return (0);
+}
+
+void
+display_memorysize(Sys_tree *tree, struct system_kstat_data *kstats,
+ struct grp_info *grps, struct mem_total *memory_total) {
+
+ /* Build the memory group tables and interleave data */
+ build_mem_tables(tree, kstats, grps);
+
+ /* display total usable installed memory */
+ get_mem_total(memory_total, grps);
+ (void) log_printf(dgettext(TEXT_DOMAIN,
+ "Memory size: %4dMb\n"), memory_total->dram, 0);
+
+ /* We display the NVSIMM size totals separately. */
+ if (memory_total->nvsimm != 0) {
+ (void) log_printf(dgettext(TEXT_DOMAIN,
+ "NVSIMM size: %4dMb\n"), memory_total->nvsimm);
+ }
+}
+
+/*
+ * This routine displays the memory configuration for all boards in the
+ * system.
+ */
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ int group;
+ char *status_str[] = { "Unknown", " Empty ", " Failed", " Active",
+ " Spare " };
+ char *cond_str[] = { " Unknown ", " OK ", " Failing ",
+ " Failed ", " Uninit. " };
+
+#ifdef lint
+ tree = tree;
+#endif
+ /* Print the header for the memory section. */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+ log_printf(" Intrlv. "
+ "Intrlv.\n", 0);
+ log_printf("Brd Bank MB Status Condition Speed Factor "
+ " With\n", 0);
+ log_printf("--- ----- ---- ------- ---------- ----- ------- "
+ "-------\n", 0);
+
+ /* Print the Memory groups information. */
+ for (group = 0; group < MAX_GROUPS; group++) {
+ struct grp *grp;
+
+ grp = &grps->grp[group];
+
+ /* If this board is not a CPU or MEM board, skip it. */
+ if ((grp->type != MEM_BOARD) && (grp->type != CPU_BOARD)) {
+ continue;
+ }
+
+ if (grp->valid) {
+ log_printf("%2d ", grp->board, 0);
+ log_printf(" %1d ", grp->group, 0);
+ log_printf("%4d ", grp->size, 0);
+ log_printf("%7s ", status_str[grp->status], 0);
+ log_printf("%10s ", cond_str[grp->condition], 0);
+ log_printf("%3dns ", grp->speed, 0);
+ log_printf("%3d-way ", grp->factor, 0);
+ if (grp->factor > 1) {
+ log_printf("%4c", grp->groupid, 0);
+ }
+ log_printf("\n", 0);
+ }
+ }
+
+}
+
+
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ /* Display Hot plugged, disabled and failed boards */
+ (void) display_hp_boards(kstats);
+
+ /* Display failed units */
+ (void) disp_fail_parts(tree);
+
+ /* Display fault info */
+ (void) disp_fault_list(tree, kstats);
+}
+
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is iof the user
+ * told us to do logging, and we found a system failure.
+ */
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ /* Display system environmental conditions. */
+ (void) disp_env_status(kstats);
+
+ /* Display ASIC Chip revs for all boards. */
+ sunfire_disp_asic_revs(tree, kstats);
+
+ /* Print the PROM revisions here */
+ sunfire_disp_prom_versions(tree);
+
+ /*
+ * Display the latest system fatal hardware
+ * error data, if any. The system holds this
+ * data in SRAM, so it does not persist
+ * across power-on resets.
+ */
+ (void) disp_err_log(kstats);
+ }
+}
+
+void
+display_mid(int mid)
+{
+ log_printf(" %2d ", mid % 2, 0);
+}
+
+/*
+ * display_pci
+ * Call the generic psycho version of this function.
+ */
+void
+display_pci(Board_node *board)
+{
+ display_psycho_pci(board);
+}
+
+/*
+ * display_ffb
+ * Display all FFBs on this board. It can either be in tabular format,
+ * or a more verbose format.
+ */
+void
+display_ffb(Board_node *board, int table)
+{
+ Prom_node *ffb;
+ void *value;
+ struct io_card *card_list = NULL;
+ struct io_card card;
+
+ if (board == NULL)
+ return;
+
+ /* Fill in common information */
+ card.display = 1;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "UPA");
+ card.freq = sys_clk;
+
+ for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
+ ffb = dev_next_node(ffb, FFB_NAME)) {
+ if (table == 1) {
+ /* Print out in table format */
+
+ /* XXX - Get the slot number (hack) */
+ card.slot = get_id(ffb);
+
+ /* Find out if it's single or double buffered */
+ (void) sprintf(card.name, "FFB");
+ value = get_prop_val(find_prop(ffb, "board_type"));
+ if (value != NULL)
+ if ((*(int *)value) & FFB_B_BUFF)
+ (void) sprintf(card.name, "FFB, "
+ "Double Buffered");
+ else
+ (void) sprintf(card.name, "FFB, "
+ "Single Buffered");
+
+ /* Print model number */
+ card.model[0] = '\0';
+ value = get_prop_val(find_prop(ffb, "model"));
+ if (value != NULL)
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+
+ card_list = insert_io_card(card_list, &card);
+ } else {
+ /* print in long format */
+ char device[MAXSTRLEN];
+ int fd = -1;
+ struct dirent *direntp;
+ DIR *dirp;
+ union strap_un strap;
+ struct ffb_sys_info fsi;
+
+ /* Find the device node using upa address */
+ value = get_prop_val(find_prop(ffb, "upa-portid"));
+ if (value == NULL)
+ continue;
+
+ (void) sprintf(device, "%s@%x", FFB_NAME,
+ *(int *)value);
+ if ((dirp = opendir("/devices")) == NULL)
+ continue;
+
+ while ((direntp = readdir(dirp)) != NULL) {
+ if (strstr(direntp->d_name, device) != NULL) {
+ (void) sprintf(device, "/devices/%s",
+ direntp->d_name);
+ fd = open(device, O_RDWR, 0666);
+ break;
+ }
+ }
+ (void) closedir(dirp);
+
+ if (fd == -1)
+ continue;
+
+ if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
+ continue;
+
+ log_printf("Board %d FFB Hardware Configuration:\n",
+ board->board_num, 0);
+ log_printf("-----------------------------------\n", 0);
+
+ strap.ffb_strap_bits = fsi.ffb_strap_bits;
+ log_printf("\tBoard rev: %d\n",
+ (int)strap.fld.board_rev, 0);
+ log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
+ log_printf("\tDAC: %s\n",
+ fmt_manf_id(fsi.dac_version, device), 0);
+ log_printf("\t3DRAM: %s\n",
+ fmt_manf_id(fsi.fbram_version, device), 0);
+ log_printf("\n", 0);
+ }
+ }
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+/*
+ * add_node
+ *
+ * This function adds a board node to the board structure where that
+ * that node's physical component lives.
+ */
+void
+add_node(Sys_tree *root, Prom_node *pnode)
+{
+ int board;
+ Board_node *bnode;
+ char *name = get_node_name(pnode);
+ Prom_node *p;
+
+ /* add this node to the Board list of the appropriate board */
+ if ((board = get_board_num(pnode)) == -1) {
+ void *value;
+
+ /*
+ * if it is a server, pci nodes and ffb nodes never have
+ * board number properties and software can find the board
+ * number from the reg property. It is derived from the
+ * high word of the 'reg' property, which contains the
+ * mid.
+ */
+ if ((name != NULL) &&
+ ((strcmp(name, FFB_NAME) == 0) ||
+ (strcmp(name, "pci") == 0) ||
+ (strcmp(name, "counter-timer") == 0))) {
+ /* extract the board number from the 'reg' prop. */
+ if ((value = get_prop_val(find_prop(pnode,
+ "reg"))) == NULL) {
+ (void) printf("add_node() no reg property\n");
+ exit(2);
+ }
+ board = (*(int *)value - 0x1c0) / 4;
+ }
+ }
+
+ /* find the node with the same board number */
+ if ((bnode = find_board(root, board)) == NULL) {
+ bnode = insert_board(root, board);
+ bnode->board_type = UNKNOWN_BOARD;
+ }
+
+ /* now attach this prom node to the board list */
+ /* Insert this node at the end of the list */
+ pnode->sibling = NULL;
+ if (bnode->nodes == NULL)
+ bnode->nodes = pnode;
+ else {
+ p = bnode->nodes;
+ while (p->sibling != NULL)
+ p = p->sibling;
+ p->sibling = pnode;
+ }
+
+}
+
+/*
+ * Function resolve_board_types
+ *
+ * After the tree is walked and all the information is gathered, this
+ * function is called to resolve the type of each board.
+ */
+void
+resolve_board_types(Sys_tree *tree)
+{
+ Board_node *bnode;
+ Prom_node *pnode;
+ char *type;
+
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ bnode->board_type = UNKNOWN_BOARD;
+
+ pnode = dev_find_node(bnode->nodes, "fhc");
+ type = get_prop_val(find_prop(pnode, "board-type"));
+ if (type == NULL) {
+ bnode = bnode->next;
+ continue;
+ }
+
+ if (strcmp(type, CPU_BD_NAME) == 0) {
+ bnode->board_type = CPU_BOARD;
+ } else if (strcmp(type, MEM_BD_NAME) == 0) {
+ bnode->board_type = MEM_BOARD;
+ } else if (strcmp(type, DISK_BD_NAME) == 0) {
+ bnode->board_type = DISK_BOARD;
+ } else if (strcmp(type, IO_SBUS_FFB_BD_NAME) == 0) {
+ bnode->board_type = IO_SBUS_FFB_BOARD;
+ } else if (strcmp(type, IO_2SBUS_BD_NAME) == 0) {
+ bnode->board_type = IO_2SBUS_BOARD;
+ } else if (strcmp(type, IO_PCI_BD_NAME) == 0) {
+ bnode->board_type = IO_PCI_BOARD;
+ } else if (strcmp(type, IO_2SBUS_SOCPLUS_BD_NAME) == 0) {
+ bnode->board_type = IO_2SBUS_SOCPLUS_BOARD;
+ } else if (strcmp(type, IO_SBUS_FFB_SOCPLUS_BD_NAME) == 0) {
+ bnode->board_type = IO_SBUS_FFB_SOCPLUS_BOARD;
+ }
+
+ bnode = bnode->next;
+ }
+
+}
+
+/*
+ * local functions
+ */
+
+static void
+sunfire_disp_prom_versions(Sys_tree *tree)
+{
+ Board_node *bnode;
+
+ /* Display Prom revision header */
+ log_printf("System Board PROM revisions:\n", 0);
+ log_printf("----------------------------\n", 0);
+
+ /* For each board, print the POST and OBP versions */
+ for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) {
+ Prom_node *flashprom; /* flashprom device node */
+
+ /* find a flashprom node for this board */
+ flashprom = dev_find_node(bnode->nodes, "flashprom");
+
+ /* If no flashprom node found, continue */
+ if (flashprom == NULL)
+ continue;
+
+ /* flashprom node found, display board# */
+ log_printf("Board %2d: ", bnode->board_num, 0);
+
+ disp_prom_version(flashprom);
+ }
+}
+
+
+/*
+ * functions that are only needed inside this library
+ */
+
+/*
+ * build_mem_tables
+ *
+ * This routine builds the memory table which tells how much memory
+ * is present in each SIMM group of each board, what the interleave
+ * factors are, and the group ID of the interleave group.
+ *
+ * The algorithms used are:
+ * First fill in the sizes of groups.
+ * Next build lists of all groups with same physical base.
+ * From #of members in each list, interleave factor is
+ * determined.
+ * All members of a certain list get the same interleave
+ * group ID.
+ */
+static void
+build_mem_tables(Sys_tree *tree,
+ struct system_kstat_data *kstats,
+ struct grp_info *grps)
+{
+ struct mem_inter inter_grps; /* temp structure for interleaves */
+ struct inter_grp *intrp;
+ int group;
+ int i;
+
+ /* initialize the interleave lists */
+ for (i = 0, intrp = &inter_grps.i_grp[0]; i < MAX_GROUPS; i++,
+ intrp++) {
+ intrp->valid = 0;
+ intrp->count = 0;
+ intrp->groupid = '\0';
+ intrp->base = 0;
+ }
+
+ for (group = 0; group < MAX_GROUPS; group++) {
+ int found;
+ int board;
+ struct grp *grp;
+ struct bd_kstat_data *bksp;
+ uchar_t simm_reg;
+ Board_node *bnode;
+
+ board = group/2;
+ bksp = &kstats->bd_ksp_list[board];
+ grp = &grps->grp[group];
+ grp->group = group % 2;
+
+ /*
+ * Copy the board type field into the group record.
+ */
+ if ((bnode = find_board(tree, board)) != NULL) {
+ grp->type = bnode->board_type;
+ } else {
+ grp->type = UNKNOWN_BOARD;
+ continue;
+ }
+
+ /* Make sure we have kstats for this board */
+ if (bksp->ac_kstats_ok == 0) {
+ /* Mark this group as invalid and move to next one */
+ grp->valid = 0;
+ continue;
+ }
+
+ /* Find the bank status property */
+ if (bksp->ac_memstat_ok) {
+ grp->status = bksp->mem_stat[grp->group].status;
+ grp->condition = bksp->mem_stat[grp->group].condition;
+ } else {
+ grp->status = StUnknown;
+ grp->condition = ConUnknown;
+ }
+
+ switch (grp->status) {
+ case StBad:
+ case StActive:
+ case StSpare:
+ break;
+ default:
+ grp->status = StUnknown;
+ break;
+ }
+
+ switch (grp->condition) {
+ case ConOK:
+ case ConFailing:
+ case ConFailed:
+ case ConTest:
+ case ConBad:
+ break;
+ default:
+ grp->condition = ConUnknown;
+ break;
+ }
+
+ /* base the group size off of the simmstat kstat. */
+ if (bksp->simmstat_kstats_ok == 0) {
+ grp->valid = 0;
+ continue;
+ }
+
+ /* Is it bank 0 or bank 1 */
+ if (grp->group == 0) {
+ simm_reg = bksp->simm_status[0];
+ } else {
+ simm_reg = bksp->simm_status[1];
+ }
+
+ /* Now decode the size field. */
+ switch (simm_reg & 0x1f) {
+ case MEM_SIZE_64M:
+ grp->size = 64;
+ break;
+ case MEM_SIZE_256M:
+ grp->size = 256;
+ break;
+ case MEM_SIZE_1G:
+ grp->size = 1024;
+ break;
+ case MEM_SIZE_2G:
+ grp->size = 2048;
+ break;
+ default:
+ grp->valid = 0;
+ continue;
+ }
+
+ /* Decode the speed field */
+ switch ((simm_reg & 0x60) >> 5) {
+ case MEM_SPEED_50ns:
+ grp->speed = 50;
+ break;
+ case MEM_SPEED_60ns:
+ grp->speed = 60;
+ break;
+ case MEM_SPEED_70ns:
+ grp->speed = 70;
+ break;
+ case MEM_SPEED_80ns:
+ grp->speed = 80;
+ break;
+ }
+
+ grp->valid = 1;
+ grp->base = GRP_BASE(bksp->ac_memdecode[grp->group]);
+ grp->board = board;
+ if (grp->group == 0) {
+ grp->factor = INTLV0(bksp->ac_memctl);
+ } else { /* assume it is group 1 */
+ grp->factor = INTLV1(bksp->ac_memctl);
+ }
+ grp->groupid = '\0'; /* Not in a group yet */
+
+ /*
+ * find the interleave list this group belongs on. If the
+ * interleave list corresponding to this base address is
+ * not found, then create a new one.
+ */
+
+ i = 0;
+ intrp = &inter_grps.i_grp[0];
+ found = 0;
+ while ((i < MAX_GROUPS) && !found && (intrp->valid != 0)) {
+ if ((intrp->valid != 0) &&
+ (intrp->base == grp->base)) {
+ grp->groupid = intrp->groupid;
+ intrp->count++;
+ found = 1;
+ }
+ i++;
+ intrp++;
+ }
+ /*
+ * We did not find a matching base. So now i and intrp
+ * now point to the next interleave group in the list.
+ */
+ if (!found) {
+ intrp->count++;
+ intrp->valid = 1;
+ intrp->groupid = 'A' + (char)i;
+ intrp->base = grp->base;
+ grp->groupid = intrp->groupid;
+ }
+ }
+}
+
+
+static void
+get_mem_total(struct mem_total *mem_total, struct grp_info *grps)
+{
+ struct grp *grp;
+ int i;
+
+ /* Start with total of zero */
+ mem_total->dram = 0;
+ mem_total->nvsimm = 0;
+
+ /* For now we ignore NVSIMMs. We might want to fix this later. */
+ for (i = 0, grp = &grps->grp[0]; i < MAX_GROUPS; i++, grp++) {
+ if (grp->valid == 1 && grp->status == StActive) {
+ mem_total->dram += grp->size;
+ }
+ }
+}
+
+static int
+disp_fault_list(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ struct ft_list *ftp;
+ int i;
+ int result = 0;
+ time_t t;
+
+ if (!kstats->ft_kstat_ok) {
+ return (result);
+ }
+
+ for (i = 0, ftp = kstats->ft_array; i < kstats->nfaults; i++, ftp++) {
+ if (!result) {
+ log_printf("\n", 0);
+ log_printf("Detected System Faults\n", 0);
+ log_printf("======================\n", 0);
+ }
+ result = 1;
+ if (ftp->fclass == FT_BOARD) {
+ log_printf("Board %d fault: %s\n", ftp->unit,
+ ftp->msg, 0);
+
+ /*
+ * If the fault on this board is PROM inherited, see
+ * if we can find some failed component information
+ * in the PROM device tree. The general solution
+ * would be to fix the fhc driver and have it put in
+ * more descriptive messages, but that's for another
+ * day.
+ */
+
+ if (ftp->type == FT_PROM) {
+ Board_node *bn;
+ Prom_node *pn;
+ char *str;
+
+ bn = find_board(tree, ftp->unit);
+ /*
+ * If any nodes under this board have a
+ * status containing "fail", print it out.
+ */
+ pn = find_failed_node(bn->nodes);
+ while (pn) {
+ str = get_prop_val(find_prop(pn,
+ "status"));
+ if (str != NULL) {
+ log_printf("Fault: %s\n", str,
+ 0);
+ }
+
+ pn = next_failed_node(pn);
+ }
+ }
+ } else if ((ftp->type == FT_CORE_PS) || (ftp->type == FT_PPS)) {
+ log_printf("Unit %d %s failure\n", ftp->unit,
+ ftp->msg, 0);
+ } else if ((ftp->type == FT_OVERTEMP) &&
+ (ftp->fclass == FT_SYSTEM)) {
+ log_printf("Clock board %s\n", ftp->msg, 0);
+ } else {
+ log_printf("%s failure\n", ftp->msg, 0);
+ }
+
+ t = (time_t)ftp->create_time;
+ log_printf("\tDetected %s",
+ asctime(localtime(&t)), 0);
+ }
+
+ if (!result) {
+ log_printf("\n", 0);
+ log_printf("No System Faults found\n", 0);
+ log_printf("======================\n", 0);
+ }
+
+ log_printf("\n", 0);
+
+ return (result);
+}
+
+
+/*
+ * disp_err_log
+ *
+ * Display the fatal hardware reset system error logs. These logs are
+ * collected by POST and passed up through the kernel to userland.
+ * They will not necessarily be present in all systems. Their form
+ * might also be different in different systems.
+ *
+ * NOTE - We are comparing POST defined board types here. Do not confuse
+ * them with kernel board types. The structure being analyzed in this
+ * function is created by POST. All the defines for it are in reset_info.h,
+ * which was ported from POST header files.
+ */
+static int
+disp_err_log(struct system_kstat_data *kstats)
+{
+ int exit_code = 0;
+ int i;
+ struct reset_info *rst_info;
+ struct board_info *bdp;
+ char *err_msgs[MAX_MSGS]; /* holds all messages for a system board */
+ int msg_idx; /* current msg number */
+ int count; /* number added by last analyze call */
+ char **msgs;
+
+ /* start by initializing the err_msgs array to all NULLs */
+ for (i = 0; i < MAX_MSGS; i++) {
+ err_msgs[i] = NULL;
+ }
+
+ /* First check to see that the reset-info kstats are present. */
+ if (kstats->reset_kstats_ok == 0) {
+ return (exit_code);
+ }
+
+ rst_info = &kstats->reset_info;
+
+ /* Everything is OK, so print out time/date stamp first */
+ log_printf("\n", 0);
+ log_printf(
+ dgettext(TEXT_DOMAIN,
+ "Analysis of most recent Fatal Hardware Watchdog:\n"),
+ 0);
+ log_printf("======================================================\n",
+ 0);
+ log_printf("Log Date: %s\n",
+ get_time(&kstats->reset_info.tod_timestamp[0]), 0);
+
+ /* initialize the vector and the message index. */
+ msgs = err_msgs;
+ msg_idx = 0;
+
+ /* Loop Through all of the boards. */
+ bdp = &rst_info->bd_reset_info[0];
+ for (i = 0; i < MAX_BOARDS; i++, bdp++) {
+
+ /* Is there data for this board? */
+ if ((bdp->board_desc & BD_STATE_MASK) == BD_NOT_PRESENT) {
+ continue;
+ }
+
+ /* If it is a CPU Board, look for CPU data. */
+ if (BOARD_TYPE(bdp->board_desc) == CPU_TYPE) {
+ /* analyze CPU 0 if present */
+ if (bdp->board_desc & CPU0_OK) {
+ count = analyze_cpu(msgs, 0,
+ bdp->cpu[0].afsr);
+ msgs += count;
+ msg_idx += count;
+ }
+
+ /* analyze CPU1 if present. */
+ if (bdp->board_desc & CPU1_OK) {
+ count = analyze_cpu(msgs, 1,
+ bdp->cpu[1].afsr);
+ msgs += count;
+ msg_idx += count;
+ }
+ }
+
+ /* Always Analyze the AC and the DCs on a board. */
+ count = analyze_ac(msgs, bdp->ac_error_status);
+ msgs += count;
+ msg_idx += count;
+
+ count = analyze_dc(i, msgs, bdp->dc_shadow_chain);
+ msgs += count;
+ msg_idx += count;
+
+ if (msg_idx != 0)
+ display_msgs(err_msgs, i);
+
+ erase_msgs(err_msgs);
+
+ /* If any messages are logged, we have errors */
+ if (msg_idx != 0) {
+ exit_code = 1;
+ }
+
+ /* reset the vector and the message index */
+ msg_idx = 0;
+ msgs = &err_msgs[0];
+ }
+
+ return (exit_code);
+}
+
+static void
+erase_msgs(char **msgs)
+{
+ int i;
+
+ for (i = 0; (*msgs != NULL) && (i < MAX_MSGS); i++, msgs++) {
+ free(*msgs);
+ *msgs = NULL;
+ }
+}
+
+
+static void
+display_msgs(char **msgs, int board)
+{
+ int i;
+
+ /* display the header for this board */
+ print_header(board);
+
+ for (i = 0; (*msgs != NULL) && (i < MAX_MSGS); i++, msgs++) {
+ log_printf(*msgs, 0);
+ }
+}
+
+
+
+/*
+ * disp_keysw_and_leds
+ *
+ * This routine displays the position of the keyswitch and the front panel
+ * system LEDs. The keyswitch can be in either normal, diagnostic, or
+ * secure position. The three front panel LEDs are of importance because
+ * the center LED indicates component failure on the system.
+ */
+static int
+disp_keysw_and_leds(struct system_kstat_data *kstats)
+{
+ int board;
+ int diag_mode = 0;
+ int secure_mode = 0;
+ int result = 0;
+
+ /* Check the first valid board to determeine the diag bit */
+ /* Find the first valid board */
+ for (board = 0; board < MAX_BOARDS; board++) {
+ if (kstats->bd_ksp_list[board].fhc_kstats_ok != 0) {
+ /* If this was successful, break out of loop */
+ if ((kstats->bd_ksp_list[board].fhc_bsr &
+ FHC_DIAG_MODE) == 0)
+ diag_mode = 1;
+ break;
+ }
+ }
+
+ /*
+ * Check the register on the clock-board to determine the
+ * secure bit.
+ */
+ if (kstats->sys_kstats_ok) {
+ /* The secure bit is negative logic. */
+ if (kstats->keysw_status == KEY_SECURE) {
+ secure_mode = 1;
+ }
+ }
+
+ /*
+ * The system cannot be in diag and secure mode. This is
+ * illegal.
+ */
+ if (secure_mode && diag_mode) {
+ result = 2;
+ return (result);
+ }
+
+ /* Now print the keyswitch position. */
+ log_printf("Keyswitch position is in ", 0);
+
+ if (diag_mode) {
+ log_printf("Diagnostic Mode\n");
+ } else if (secure_mode) {
+ log_printf("Secure Mode\n", 0);
+ } else {
+ log_printf("Normal Mode\n");
+ }
+
+ /* display the redundant power status */
+ if (kstats->sys_kstats_ok) {
+ log_printf("System Power Status: ", 0);
+
+ switch (kstats->power_state) {
+ case REDUNDANT:
+ log_printf("Redundant\n", 0);
+ break;
+
+ case MINIMUM:
+ log_printf("Minimum Available\n", 0);
+ break;
+
+ case BELOW_MINIMUM:
+ log_printf("Insufficient Power Available\n", 0);
+ break;
+
+ default:
+ log_printf("Unknown\n", 0);
+ break;
+ }
+ }
+
+ if (kstats->sys_kstats_ok) {
+ /*
+ * If the center LED is on, then we return a non-zero
+ * result.
+ */
+ log_printf("System LED Status: GREEN YELLOW "
+ "GREEN\n", 0);
+ if ((kstats->sysctrl & SYS_LED_MID) != 0) {
+ log_printf("WARNING ", 0);
+ } else {
+ log_printf("Normal ", 0);
+ }
+
+ /*
+ * Left LED is negative logic, center and right LEDs
+ * are positive logic.
+ */
+ if ((kstats->sysctrl & SYS_LED_LEFT) == 0) {
+ log_printf("ON ", 0);
+ } else {
+ log_printf("OFF", 0);
+ }
+
+ log_printf(" ", 0);
+ if ((kstats->sysctrl & SYS_LED_MID) != 0) {
+ log_printf("ON ", 0);
+ } else {
+ log_printf("OFF", 0);
+ }
+
+ log_printf(" BLINKING", 0);
+ }
+
+ log_printf("\n", 0);
+ return (result);
+}
+
+/*
+ * disp_env_status
+ *
+ * This routine displays the environmental status passed up from
+ * device drivers via kstats. The kstat names are defined in
+ * kernel header files included by this module.
+ */
+static int
+disp_env_status(struct system_kstat_data *kstats)
+{
+ struct bd_kstat_data *bksp;
+ int exit_code = 0;
+ int i;
+ uchar_t curr_temp;
+ int is4slot = 0;
+
+ /*
+ * Define some message arrays to make life simpler. These
+ * messages correspond to definitions in <sys/fhc.c> for
+ * temperature trend (enum temp_trend) and temperature state
+ * (enum temp_state).
+ */
+ static char *temp_trend_msg[] = { "unknown",
+ "rapidly falling",
+ "falling",
+ "stable",
+ "rising",
+ "rapidly rising",
+ "unknown (noisy)"
+ };
+ static char *temp_state_msg[] = { " OK ",
+ "WARNING ",
+ " DANGER "
+ };
+
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+
+ exit_code = disp_keysw_and_leds(kstats);
+
+ if (!kstats->sys_kstats_ok) {
+ log_printf(dgettext(TEXT_DOMAIN,
+ "*** Error: Unavailable ***\n\n"));
+ return (1);
+ }
+
+ /*
+ * for purposes within this routine,
+ * 5 slot behaves the same as a 4 slot
+ */
+ if (SYS_TYPE(kstats->sysstat1) == SYS_4_SLOT)
+ is4slot = 1;
+
+ log_printf("\n", 0);
+ log_printf("\nFans:\n", 0);
+ log_printf("-----\n", 0);
+
+ log_printf("Unit Status\n", 0);
+ log_printf("---- ------\n", 0);
+
+ log_printf("%-4s ", is4slot ? "Disk" : "Rack", 0);
+ /* Check the status of the Rack Fans */
+ if ((kstats->fan_status & SYS_RACK_FANFAIL) == 0) {
+ log_printf("OK\n", 0);
+ } else {
+ log_printf("FAIL\n", 0);
+ exit_code = 1;
+ }
+
+ if (!is4slot) {
+ /*
+ * keyswitch and ac box are on 8 & 16 slot only
+ */
+ /* Check the status of the Keyswitch Fan assembly. */
+ log_printf("%-4s ", "Key", 0);
+ if ((kstats->fan_status & SYS_KEYSW_FAN_OK) != 0) {
+ log_printf("OK\n", 0);
+ } else {
+ log_printf("FAIL\n", 0);
+ exit_code = 1;
+ }
+
+ log_printf("%-4s ", "AC", 0);
+ if ((kstats->fan_status & SYS_AC_FAN_OK) != 0) {
+ log_printf("OK\n", 0);
+ } else {
+ log_printf("FAIL\n", 0);
+ exit_code = 1;
+ }
+ } else {
+ /*
+ * peripheral fan is on 4 slot only
+ * XXX might want to indicate transient states too
+ */
+ if (kstats->psstat_kstat_ok) {
+ if (kstats->ps_shadow[SYS_P_FAN_INDEX] == PS_OK) {
+ log_printf("PPS OK\n", 0);
+ } else if (kstats->ps_shadow[SYS_P_FAN_INDEX] ==
+ PS_FAIL) {
+ log_printf("PPS FAIL\n", 0);
+ exit_code = 1;
+ }
+ }
+ }
+
+ log_printf("\n", 0);
+
+
+ log_printf("System Temperatures (Celsius):\n", 0);
+ log_printf("------------------------------\n", 0);
+ log_printf("Brd State Current Min Max Trend\n", 0);
+ log_printf("--- ------- ------- --- --- -----\n", 0);
+
+ for (i = 0, bksp = &kstats->bd_ksp_list[0]; i < MAX_BOARDS;
+ i++, bksp++) {
+
+ /* Make sure we have kstats for this board first */
+ if (!bksp->temp_kstat_ok) {
+ continue;
+ }
+ log_printf("%2d ", i, 0);
+
+ /* Print the current state of the temperature */
+ log_printf("%s", temp_state_msg[bksp->tempstat.state], 0);
+ /* Set exit code for WARNING and DANGER */
+ if (bksp->tempstat.state != 0)
+ exit_code = 1;
+
+ /* Print the current temperature */
+ curr_temp = bksp->tempstat.l1[bksp->tempstat.index % L1_SZ];
+ log_printf(" %2d ", curr_temp, 0);
+
+ /* Print the minimum recorded temperature */
+ log_printf(" %2d ", bksp->tempstat.min, 0);
+
+ /* Print the maximum recorded temperature */
+ log_printf(" %2d ", bksp->tempstat.max, 0);
+
+ /* Print the current trend in temperature (if available) */
+ if (bksp->tempstat.version < 2)
+ log_printf("unknown\n", 0);
+ else
+ log_printf("%s\n", temp_trend_msg[bksp->tempstat.trend], 0);
+ }
+ if (kstats->temp_kstat_ok) {
+ log_printf("CLK ", 0);
+
+ /* Print the current state of the temperature */
+ log_printf("%s", temp_state_msg[kstats->tempstat.state], 0);
+ /* Set exit code for WARNING or DANGER */
+ if (kstats->tempstat.state != 0)
+ exit_code = 1;
+
+ /* Print the current temperature */
+ curr_temp = kstats->tempstat.l1[kstats->tempstat.index % L1_SZ];
+ log_printf(" %2d ", curr_temp, 0);
+
+ /* Print the minimum recorded temperature */
+ log_printf(" %2d ", kstats->tempstat.min, 0);
+
+ /* Print the maximum recorded temperature */
+ log_printf(" %2d ", kstats->tempstat.max, 0);
+
+ /* Print the current trend in temperature (if available) */
+ if (kstats->tempstat.version < 2)
+ log_printf("unknown\n\n", 0);
+ else
+ log_printf("%s\n\n",
+ temp_trend_msg[kstats->tempstat.trend], 0);
+ } else {
+ log_printf("\n");
+ }
+
+ log_printf("\n", 0);
+ log_printf("Power Supplies:\n", 0);
+ log_printf("---------------\n", 0);
+ log_printf("Supply Status\n", 0);
+ log_printf("--------- ------\n", 0);
+ if (kstats->psstat_kstat_ok) {
+ for (i = 0; i < SYS_PS_COUNT; i++) {
+ char *ps, *state;
+
+ /* skip core power supplies that are not present */
+ if (i <= SYS_PPS0_INDEX && kstats->ps_shadow[i] ==
+ PS_OUT)
+ continue;
+
+ /* Display the unit Number */
+ switch (i) {
+ case 0: ps = "0"; break;
+ case 1: ps = "1"; break;
+ case 2: ps = "2"; break;
+ case 3: ps = "3"; break;
+ case 4: ps = "4"; break;
+ case 5: ps = "5"; break;
+ case 6: ps = "6"; break;
+ case 7: ps = is4slot ? "2nd PPS" : "7"; break;
+
+ case SYS_PPS0_INDEX: ps = "PPS"; break;
+ case SYS_CLK_33_INDEX: ps = " System 3.3v"; break;
+ case SYS_CLK_50_INDEX: ps = " System 5.0v"; break;
+ case SYS_V5_P_INDEX: ps = " Peripheral 5.0v"; break;
+ case SYS_V12_P_INDEX: ps = " Peripheral 12v"; break;
+ case SYS_V5_AUX_INDEX: ps = " Auxiliary 5.0v"; break;
+ case SYS_V5_P_PCH_INDEX: ps =
+ " Peripheral 5.0v precharge";
+ break;
+ case SYS_V12_P_PCH_INDEX: ps =
+ " Peripheral 12v precharge";
+ break;
+ case SYS_V3_PCH_INDEX: ps =
+ " System 3.3v precharge"; break;
+ case SYS_V5_PCH_INDEX: ps =
+ " System 5.0v precharge"; break;
+
+ /* skip the peripheral fan here */
+ case SYS_P_FAN_INDEX:
+ continue;
+ }
+
+ /* what is the state? */
+ switch (kstats->ps_shadow[i]) {
+ case PS_OK:
+ state = "OK";
+ break;
+
+ case PS_FAIL:
+ state = "FAIL";
+ exit_code = 1;
+ break;
+
+ /* XXX is this an exit_code condition? */
+ case PS_OUT:
+ state = "PPS Out";
+ exit_code = 1;
+ break;
+
+ case PS_UNKNOWN:
+ state = "Unknown";
+ break;
+
+ default:
+ state = "Illegal State";
+ break;
+ }
+
+ log_printf("%-32s %s\n", ps, state, 0);
+ }
+ }
+
+ /* Check status of the system AC Power Source */
+ log_printf("%-32s ", "AC Power", 0);
+ if ((kstats->sysstat2 & SYS_AC_FAIL) == 0) {
+ log_printf("OK\n", 0);
+ } else {
+ log_printf("failed\n", 0);
+ exit_code = 1;
+ }
+ log_printf("\n", 0);
+
+ return (exit_code);
+}
+
+
+/*
+ * Many of the ASICs present in fusion machines have implementation and
+ * version numbers stored in the OBP device tree. These codes are displayed
+ * in this routine in an effort to aid Engineering and Field service
+ * in detecting old ASICs which may have bugs in them.
+ */
+static void
+sunfire_disp_asic_revs(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ Board_node *bnode;
+ Prom_node *pnode;
+ int isplusbrd;
+ char *board_str[] = { "Uninitialized", "Unknown", "CPU",
+ "Memory", "Dual-SBus", "UPA-SBus",
+ "Dual-PCI", "Disk", "Clock",
+ "Dual-SBus-SOC+", "UPA-SBus-SOC+"};
+
+ /* Print the header */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(" HW Revisions ", 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ /* Else this is a Sunfire or campfire */
+ log_printf("ASIC Revisions:\n", 0);
+ log_printf("---------------\n", 0);
+
+ /* Display Firetruck ASIC Revisions first */
+ log_printf("Brd FHC AC SBus0 SBus1 PCI0 PCI1 FEPS", 0);
+ log_printf(" Board Type Attributes", 0);
+ log_printf("\n", 0);
+ log_printf("--- --- -- ----- ----- ---- ---- ----", 0);
+ log_printf(" ---------- ----------", 0);
+ log_printf("\n", 0);
+
+ /*
+ * Display all of the FHC, AC, and chip revisions for the entire
+ * machine. The AC anf FHC chip revs are available from the device
+ * tree that was read out of the PROM, but the DC chip revs will be
+ * read via a kstat. The interfaces for this are not completely
+ * available at this time.
+ */
+ bnode = tree->bd_list;
+ while (bnode != NULL) {
+ int *version;
+ int upa = bd_to_upa(bnode->board_num);
+
+ /* Display the header with the board number */
+ log_printf("%2d ", bnode->board_num, 0);
+
+ /* display the FHC version */
+ if ((pnode = dev_find_node(bnode->nodes, "fhc")) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ if ((version = (int *)get_prop_val(find_prop(pnode,
+ "version#"))) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ log_printf(" %d ", *version, 0);
+ }
+ }
+
+ /* display the AC version */
+ if ((pnode = dev_find_node(bnode->nodes, "ac")) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ if ((version = (int *)get_prop_val(find_prop(pnode,
+ "version#"))) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ log_printf(" %d ", *version, 0);
+ }
+ }
+
+ /* Find sysio 0 on board and print rev */
+ if ((pnode = find_device(bnode, upa, "sbus")) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ if ((version = (int *)get_prop_val(find_prop(pnode,
+ "version#"))) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ log_printf(" %d ", *version, 0);
+ }
+ }
+
+ /* Find sysio 1 on board and print rev */
+ if ((pnode = find_device(bnode, upa+1, "sbus")) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ if ((version = (int *)get_prop_val(find_prop(pnode,
+ "version#"))) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ log_printf(" %d ", *version, 0);
+ }
+ }
+
+ /* Find Psycho 0 on board and print rev */
+ if ((pnode = find_device(bnode, upa, "pci")) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ if ((version = (int *)get_prop_val(find_prop(pnode,
+ "version#"))) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ log_printf(" %d ", *version, 0);
+ }
+ }
+
+ /* Find Psycho 1 on board and print rev */
+ if ((pnode = find_device(bnode, upa+1, "pci")) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ if ((version = (int *)get_prop_val(find_prop(pnode,
+ "version#"))) == NULL) {
+ log_printf(" ", 0);
+ } else {
+ log_printf(" %d ", *version, 0);
+ }
+ }
+
+ /* Find the FEPS on board and print rev */
+ if ((pnode = dev_find_node(bnode->nodes, "SUNW,hme")) != NULL) {
+ if ((version = (int *)get_prop_val(find_prop(pnode,
+ "hm-rev"))) != NULL) {
+ if (*version == 0xa0) {
+ log_printf(" 2.0 ", 0);
+ } else if (*version == 0x20) {
+ log_printf(" 2.1 ", 0);
+ } else {
+ log_printf(" %2x ", *version, 0);
+ }
+ }
+ } else
+ log_printf(" ", 0);
+
+ /* print out the board type */
+ isplusbrd = ISPLUSBRD(kstats->bd_ksp_list
+ [bnode->board_num].fhc_bsr);
+
+ log_printf("%-16s", board_str[bnode->board_type], 0);
+ if (isplusbrd)
+ log_printf("100MHz Capable", 0);
+ else
+ log_printf("84MHz Capable", 0);
+
+ log_printf("\n", 0);
+ bnode = bnode->next;
+ }
+ log_printf("\n", 0);
+
+ /* Now display the FFB board component revisions */
+ for (bnode = tree->bd_list; bnode != NULL; bnode = bnode->next) {
+ display_ffb(bnode, 0);
+ }
+}
+
+static void
+display_hp_boards(struct system_kstat_data *kstats)
+{
+ int i;
+ int j;
+ int hp_found = 0;
+ struct hp_info *hp;
+ char *state;
+
+ for (i = 0, hp = &kstats->hp_info[0]; i < MAX_BOARDS; i++, hp++) {
+ if (!hp->kstat_ok) {
+ continue;
+ }
+
+ hp_found = 1;
+ }
+
+ /* return if there are no hotplug boards in the system. */
+ if (!hp_found) {
+ return;
+ }
+
+ if (hp_found != 0) {
+ log_printf("\n", 0);
+ log_printf("Detached Boards\n", 0);
+ log_printf("===============\n", 0);
+ log_printf(" Slot State Type Info\n", 0);
+ log_printf(" ---- --------- ------ ----"
+ "-------------------------------------\n", 0);
+ }
+
+ /* Display all detached boards */
+ for (i = 0, hp = &kstats->hp_info[0]; i < MAX_BOARDS; i++, hp++) {
+ struct cpu_info *cpu;
+
+ if (hp->kstat_ok == 0) {
+ continue;
+ }
+
+
+ switch (hp->bd_info.state) {
+ case UNKNOWN_STATE:
+ state = "unknown";
+ break;
+
+ case ACTIVE_STATE:
+ state = "active";
+ break;
+
+ case LOWPOWER_STATE:
+ state = "low-power";
+ break;
+
+ case HOTPLUG_STATE:
+ state = "hot-plug";
+ break;
+
+ case DISABLED_STATE:
+ state = "disabled";
+ break;
+
+ case FAILED_STATE:
+ state = "failed";
+ break;
+
+ default:
+ state = "unknown";
+ break;
+ }
+
+ log_printf(" %2d %9s ", i, state, 0);
+
+ switch (hp->bd_info.type) {
+ case MEM_BOARD:
+ log_printf("%-14s ", MEM_BD_NAME, 0);
+ break;
+
+ case CPU_BOARD:
+ log_printf("%-14s ", CPU_BD_NAME, 0);
+
+ /* Cannot display CPU info for disabled boards */
+ if ((hp->bd_info.state == DISABLED_STATE) ||
+ (hp->bd_info.state == FAILED_STATE)) {
+ break;
+ }
+
+ /* Display both CPUs if present */
+ cpu = &hp->bd_info.bd.cpu[0];
+ for (j = 0; j < 2; j++, cpu++) {
+ log_printf("CPU %d: ", j, 0);
+ /* Print the rated speed of the CPU. */
+ if (cpu->cpu_speed > 1) {
+ log_printf("%3d MHz", cpu->cpu_speed,
+ 0);
+ } else {
+ log_printf("no CPU ", 0);
+ continue;
+ }
+
+ /* Display the size of the cache */
+ if (cpu->cache_size != 0) {
+ log_printf(" %0.1fM ",
+ (float)cpu->cache_size /
+ (float)(1024*1024), 0);
+ } else {
+ log_printf(" ", 0);
+ }
+ }
+ break;
+
+ case IO_2SBUS_BOARD:
+ log_printf("%-14s ", IO_2SBUS_BD_NAME, 0);
+ break;
+
+ case IO_2SBUS_SOCPLUS_BOARD:
+ log_printf("%-14s ", IO_2SBUS_SOCPLUS_BD_NAME, 0);
+ break;
+
+ case IO_SBUS_FFB_BOARD:
+ log_printf("%-14s ", IO_SBUS_FFB_BD_NAME, 0);
+ switch (hp->bd_info.bd.io2.ffb_size) {
+ case FFB_SINGLE:
+ log_printf("Single buffered FFB", 0);
+ break;
+
+ case FFB_DOUBLE:
+ log_printf("Double buffered FFB", 0);
+ break;
+
+ case FFB_NOT_FOUND:
+ log_printf("No FFB installed", 0);
+ break;
+
+ default:
+ log_printf("Illegal FFB size", 0);
+ break;
+ }
+ break;
+
+ case IO_SBUS_FFB_SOCPLUS_BOARD:
+ log_printf("%-14s ", IO_SBUS_FFB_SOCPLUS_BD_NAME, 0);
+ switch (hp->bd_info.bd.io2.ffb_size) {
+ case FFB_SINGLE:
+ log_printf("Single buffered FFB", 0);
+ break;
+
+ case FFB_DOUBLE:
+ log_printf("Double buffered FFB", 0);
+ break;
+
+ case FFB_NOT_FOUND:
+ log_printf("No FFB installed", 0);
+ break;
+
+ default:
+ log_printf("Illegal FFB size", 0);
+ break;
+ }
+ break;
+
+ case IO_PCI_BOARD:
+ log_printf("%-14s ", IO_PCI_BD_NAME, 0);
+ break;
+
+ case DISK_BOARD:
+ log_printf("%-14s ", "disk", 0);
+ for (j = 0; j < 2; j++) {
+ log_printf("Disk %d:", j, 0);
+ if (hp->bd_info.bd.dsk.disk_pres[j]) {
+ log_printf(" Target: %2d ",
+ hp->bd_info.bd.dsk.disk_id[j],
+ 0);
+ } else {
+ log_printf(" no disk ", 0);
+ }
+ }
+ break;
+
+ case UNKNOWN_BOARD:
+ case UNINIT_BOARD:
+ default:
+ log_printf("UNKNOWN ", 0);
+ break;
+ }
+ log_printf("\n");
+ }
+}
+
+/*
+ * Analysis functions:
+ *
+ * Most of the Fatal error data analyzed from error registers is not
+ * very complicated. This is because the FRUs for errors detected by
+ * most parts is either a CPU module, a FFB, or the system board
+ * itself.
+ * The analysis of the Address Controller errors is the most complicated.
+ * These errors can be caused by other boards as well as the local board.
+ */
+
+/*
+ * analyze_cpu
+ *
+ * Analyze the CPU MFSR passed in and determine what type of fatal
+ * hardware errors occurred at the time of the crash. This function
+ * returns a pointer to a string to the calling routine.
+ */
+static int
+analyze_cpu(char **msgs, int cpu_id, u_longlong_t afsr)
+{
+ int count = 0;
+ int i;
+ int syndrome;
+ char msgbuf[MAXSTRLEN];
+
+ if (msgs == NULL) {
+ return (count);
+ }
+
+ if (afsr & P_AFSR_ETP) {
+ (void) sprintf(msgbuf, "CPU %d Ecache Tag Parity Error, ",
+ cpu_id);
+
+ /* extract syndrome for afsr */
+ syndrome = (afsr & P_AFSR_ETS) >> ETS_SHIFT;
+
+ /* now concat the parity syndrome msg */
+ for (i = 0; i < 4; i++) {
+ if ((0x1 << i) & syndrome) {
+ (void) strcat(msgbuf, ecache_parity[i]);
+ }
+ }
+ (void) strcat(msgbuf, "\n");
+ *msgs++ = strdup(msgbuf);
+ count++;
+ }
+
+ if (afsr & P_AFSR_ISAP) {
+ (void) sprintf(msgbuf,
+ "CPU %d Incoming System Address Parity Error\n",
+ cpu_id);
+ *msgs++ = strdup(msgbuf);
+ count++;
+ }
+
+ return (count);
+}
+
+/*
+ * analyze_ac
+ *
+ * This function checks the AC error register passed in and checks
+ * for any errors that occured during the fatal hardware reset.
+ */
+static int
+analyze_ac(char **msgs, u_longlong_t ac_error)
+{
+ int i;
+ int count = 0;
+ char msgbuf[MAXSTRLEN];
+ int tmp_cnt;
+
+ if (msgs == NULL) {
+ return (count);
+ }
+
+ for (i = 2; i < MAX_BITS; i++) {
+ if ((((u_longlong_t)0x1 << i) & ac_error) != 0) {
+ if (ac_errors[i].error != NULL) {
+ (void) sprintf(msgbuf, "AC: %s\n",
+ ac_errors[i].error);
+ *msgs++ = strdup(msgbuf);
+ count++;
+
+ /* display the part that might cause this */
+ tmp_cnt = disp_parts(msgs, ac_error, i);
+ count += tmp_cnt;
+ msgs += tmp_cnt;
+ }
+ }
+ }
+
+ return (count);
+}
+
+/*
+ * analyze_dc
+ *
+ * This routine checks the DC shdow chain and tries to determine
+ * what type of error might have caused the fatal hardware reset
+ * error.
+ */
+static int
+analyze_dc(int board, char **msgs, u_longlong_t dc_error)
+{
+ int i;
+ int count = 0;
+ char msgbuf[MAXSTRLEN];
+
+ if (msgs == NULL) {
+ return (count);
+ }
+
+ /*
+ * The DC scan data is contained in 8 bytes, one byte per
+ * DC. There are 8 DCs on a system board.
+ */
+
+ for (i = 0; i < 8; i++) {
+ if (dc_error & DC_OVERFLOW) {
+ (void) sprintf(msgbuf, dc_overflow_txt, board, i);
+ *msgs++ = strdup(msgbuf);
+ count++;
+ }
+
+ if (dc_error & DC_PARITY) {
+ (void) sprintf(msgbuf, dc_parity_txt, board, i);
+ *msgs++ = strdup(msgbuf);
+ count++;
+ }
+ dc_error = dc_error >> 8; /* shift over to next byte */
+ }
+
+ return (count);
+}
+
+static int
+disp_parts(char **msgs, u_longlong_t ac_error, int type)
+{
+ int count = 0;
+ int part;
+ char msgbuf[MAXSTRLEN];
+ int i;
+
+ if (msgs == NULL) {
+ return (count);
+ }
+
+ (void) sprintf(msgbuf, "\tThe error could be caused by:\n");
+ *msgs++ = strdup(msgbuf);
+ count++;
+
+ for (i = 0; (i < MAX_FRUS) && ac_errors[type].part[i]; i++) {
+ part = ac_errors[type].part[i];
+
+ if (part == UPA_PART) {
+ if (ac_error & UPA_PORT_A) {
+ part = UPA_A_PART;
+ } else if (ac_error & UPA_PORT_B) {
+ part = UPA_B_PART;
+ }
+ }
+
+ if (part == DTAG_PART) {
+ if (ac_error & UPA_PORT_A) {
+ part = DTAG_A_PART;
+ } else if (ac_error & UPA_PORT_B) {
+ part = DTAG_B_PART;
+ }
+ }
+
+ (void) sprintf(msgbuf, "\t\t%s\n", part_str[part]);
+
+ *msgs++ = strdup(msgbuf);
+ count++;
+ }
+
+ return (count);
+}
diff --git a/usr/src/lib/libprtdiag_psr/sparc/tazmo/Makefile b/usr/src/lib/libprtdiag_psr/sparc/tazmo/Makefile
new file mode 100644
index 0000000000..4035434901
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/tazmo/Makefile
@@ -0,0 +1,76 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libprtdiag_psr/sparc/tazmo/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= tazmo.o
+
+include ../Makefile.com
+
+IFLAGS += -I$(USR_PLAT_DIR)/sun4u/include -I ../../../libprtdiag/inc
+LINTFLAGS += $(IFLAGS)
+LDLIBS += -lkstat
+
+#
+# Workgroup Server platform library should install into
+# SUNW,Ultra-4. All other desktop platforms can
+# link to /usr/platform/SUNW,Ultra-4/lib/libprtdiag_psr.so
+#
+PLATFORM=SUNW,Ultra-4
+
+.KEEP_STATE:
+
+PLATLIBS= $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+
+install: all $(USR_PSM_LIBS)
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/tazmo; $(MAKE) $(USR_PSM_LIB_DIR)
+
+#
+# install rule
+#
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+POFILE= libprtdiag_psr_tazmo.po
+POFILES= tazmo.po
+
+_msg: $(MSGDOMAIN) $(POFILE)
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ $(CP) $(POFILE) $(MSGDOMAIN)
+
+$(POFILE): $(POFILES)
+ $(RM) $@
+ $(CAT) $(POFILES) > $@
+
+$(POFILES):
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext common/tazmo.c`
+ $(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
+ $(RM) messages.po
diff --git a/usr/src/lib/libprtdiag_psr/sparc/tazmo/common/tazmo.c b/usr/src/lib/libprtdiag_psr/sparc/tazmo/common/tazmo.c
new file mode 100644
index 0000000000..bbeadffea0
--- /dev/null
+++ b/usr/src/lib/libprtdiag_psr/sparc/tazmo/common/tazmo.c
@@ -0,0 +1,1577 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Tazmo Platform specific functions.
+ *
+ * called when :
+ * machine_type == MTYPE_TAZMO
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <kvm.h>
+#include <varargs.h>
+#include <errno.h>
+#include <time.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/openpromio.h>
+#include <kstat.h>
+#include <libintl.h>
+#include <syslog.h>
+#include <sys/dkio.h>
+#include "pdevinfo.h"
+#include "display.h"
+#include "pdevinfo_sun4u.h"
+#include "display_sun4u.h"
+#include "libprtdiag.h"
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+extern int print_flag;
+
+/*
+ * these functions will overlay the symbol table of libprtdiag
+ * at runtime (workgroup server systems only)
+ */
+int error_check(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_memoryconf(Sys_tree *tree, struct grp_info *grps);
+int disp_fail_parts(Sys_tree *tree);
+void display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats);
+void display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats);
+void display_boardnum(int num);
+void display_pci(Board_node *);
+void display_io_cards(struct io_card *list);
+void display_ffb(Board_node *, int);
+void read_platform_kstats(Sys_tree *tree,
+ struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep);
+
+/* local functions */
+static int disp_envctrl_status(Sys_tree *, struct system_kstat_data *);
+static void check_disk_presence(Sys_tree *, int *, int *, int *);
+static void modify_device_path(char *, char *);
+static int disk_present(char *);
+static void tazjav_disp_asic_revs(Sys_tree *);
+static int tazmo_physical_slot(Prom_node *, Prom_node *, int, char *);
+static Prom_node *dev_next_node_sibling(Prom_node *root, char *name);
+
+
+int
+error_check(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+ int exit_code = 0; /* init to all OK */
+
+#ifdef lint
+ kstats = kstats;
+#endif
+ /*
+ * silently check for any types of machine errors
+ */
+ print_flag = 0;
+ if (disp_fail_parts(tree) || disp_envctrl_status(tree, kstats)) {
+ /* set exit_code to show failures */
+ exit_code = 1;
+ }
+ print_flag = 1;
+
+ return (exit_code);
+}
+
+/* Search for and return the node's sibling */
+static Prom_node *
+dev_next_node_sibling(Prom_node *root, char *name)
+{
+ if (root == NULL)
+ return (NULL);
+
+ /* look at your siblings */
+ if (dev_find_node(root->sibling, name) != NULL)
+ return (root->sibling);
+
+ return (NULL); /* not found */
+}
+
+/*
+ * This function displays memory configurations specific to Tazmo/Javelin.
+ * The PROM device tree is read to obtain this information.
+ * Some of the information obtained is memory interleave factor,
+ * DIMM sizes, DIMM socket names.
+ */
+void
+display_memoryconf(Sys_tree *tree, struct grp_info *grps)
+{
+ Board_node *bnode;
+ Prom_node *memory;
+ Prom_node *bank;
+ Prom_node *dimm;
+ uint_t *preg;
+ uint_t interlv;
+ unsigned long size = 0;
+ int bank_count = 0;
+ char *sock_name;
+ char *status;
+ Prop *status_prop;
+ char interleave[8];
+ int total_size = 0;
+#ifdef lint
+ grps = grps;
+#endif
+
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Memory "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+ bnode = tree->bd_list;
+ memory = dev_find_node(bnode->nodes, "memory");
+ preg = (uint_t *)(get_prop_val(find_prop(memory, "interleave")));
+ if (preg) {
+ interlv = preg[4];
+ log_printf("Memory Interleave Factor = %d-way\n\n", interlv, 0);
+ }
+ log_printf(" Interlv. Socket Size\n", 0);
+ log_printf("Bank Group Name (MB) Status\n", 0);
+ log_printf("---- ----- ------ ---- ------\n", 0);
+
+ dimm = bnode->nodes;
+ for (bank = dev_find_node(bnode->nodes, "bank"); bank != NULL;
+ bank = dev_next_node(bank, "bank")) {
+ int bank_size = 0;
+ uint_t *reg_prop;
+
+ preg = (uint_t *)(get_prop_val(
+ find_prop(bank, "bank-interleave")));
+
+ reg_prop = (uint_t *)(get_prop_val(
+ find_prop(bank, "reg")));
+
+ /*
+ * Skip empty banks
+ */
+ if (((reg_prop[2]<<12) + (reg_prop[3]>>20)) == 0) {
+ bank_count++;
+ continue;
+ }
+
+ if (preg) {
+ interlv = preg[2];
+ (void) sprintf(interleave, " %d ", interlv);
+ bank_size = (preg[0]<<12) + (preg[1]>>20);
+ } else {
+ (void) sprintf(interleave, "%s", "none");
+ preg = (uint_t *)(get_prop_val(find_prop(bank, "reg")));
+ if (preg) {
+ bank_size = (preg[2]<<12) + (preg[3]>>20);
+ }
+ }
+ for (dimm = dev_find_node(bank, "dimm"); dimm != NULL;
+ dimm = dev_next_node_sibling(dimm, "dimm")) {
+ char dimm_status[16];
+
+ sock_name = (char *)(get_prop_val(
+ find_prop(dimm, "socket-name")));
+ preg = (uint_t *)(get_prop_val(find_prop(dimm, "reg")));
+ size = (preg[2]<<12) + (preg[3]>>20);
+ if ((status_prop = find_prop(dimm, "status")) == NULL) {
+ (void) sprintf(dimm_status, "%s", "OK");
+ } else {
+ status = (char *)(get_prop_val(status_prop));
+ (void) sprintf(dimm_status, "%s", status);
+ }
+ log_printf("%3d %5s %6s %4d %6s\n",
+ bank_count, interleave, sock_name,
+ size, dimm_status, 0);
+ }
+ total_size += bank_size;
+ bank_count++;
+ }
+ log_printf("\n", 0);
+}
+
+/*
+ * disp_fail_parts
+ *
+ * Display the failed parts in the system. This function looks for
+ * the status property in all PROM nodes. On systems where
+ * the PROM does not supports passing diagnostic information
+ * thruogh the device tree, this routine will be silent.
+ */
+int
+disp_fail_parts(Sys_tree *tree)
+{
+ int exit_code;
+ int system_failed = 0;
+ Board_node *bnode = tree->bd_list;
+ Prom_node *pnode;
+ char *fru;
+ char *sock_name;
+ char slot_str[MAXSTRLEN];
+
+ exit_code = 0;
+
+ /* go through all of the boards looking for failed units. */
+ while (bnode != NULL) {
+ /* find failed chips */
+ pnode = find_failed_node(bnode->nodes);
+ if ((pnode != NULL) && !system_failed) {
+ system_failed = 1;
+ exit_code = 1;
+ if (print_flag == 0) {
+ return (exit_code);
+ }
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Failed Field "
+ "Replaceable Units (FRU) in System:\n"), 0);
+ log_printf("=========================="
+ "====================\n", 0);
+ }
+
+ while (pnode != NULL) {
+ void *value;
+ char *name; /* node name string */
+ char *type; /* node type string */
+
+ value = get_prop_val(find_prop(pnode, "status"));
+ name = get_node_name(pnode);
+
+ /* sanity check of data retreived from PROM */
+ if ((value == NULL) || (name == NULL)) {
+ pnode = next_failed_node(pnode);
+ continue;
+ }
+
+
+ log_printf(dgettext(TEXT_DOMAIN, "%s unavailable :\n"),
+ name, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tPROM fault string: %s\n"),
+ value, 0);
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "\tFailed Field Replaceable Unit is "), 0);
+
+ /*
+ * Determine whether FRU is CPU module, system
+ * board, or SBus card.
+ */
+ if ((name != NULL) && (strstr(name, "sbus"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN, "SBus "
+ "Card %d\n"), get_sbus_slot(pnode), 0);
+
+ } else if (((name = get_node_name(pnode)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "system board\n"), 0);
+
+ } else if (((name = get_node_name(pnode)) !=
+ NULL) && (strstr(name, "ffb"))) {
+
+ log_printf(dgettext(TEXT_DOMAIN,
+ "FFB Card %d\n"),
+ tazmo_physical_slot(
+ dev_find_node(bnode->nodes, "slot2dev"),
+ pnode, -1, slot_str), 0);
+
+ } else if (((name = get_node_name(pnode->parent)) !=
+ NULL) && (strstr(name, "pci"))) {
+
+ (void) tazmo_physical_slot(
+ NULL,
+ pnode->parent,
+ get_pci_device(pnode),
+ slot_str);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "PCI Card in %s\n"), slot_str, 0);
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "cpu"))) {
+
+ log_printf(
+ dgettext(TEXT_DOMAIN,
+ "UltraSPARC module Module %d\n"),
+ get_id(pnode));
+
+ } else if (((type = get_node_type(pnode)) != NULL) &&
+ (strstr(type, "memory-module"))) {
+
+ fru = (char *)(get_prop_val(
+ find_prop(pnode, "fru")));
+ sock_name = (char *)(get_prop_val(
+ find_prop(pnode, "socket-name")));
+ log_printf(
+ dgettext(TEXT_DOMAIN,
+ "%s in socket %s\n"),
+ fru, sock_name, 0);
+ }
+ pnode = next_failed_node(pnode);
+ }
+ bnode = bnode->next;
+ }
+
+ if (!system_failed) {
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN,
+ "No failures found in System\n"), 0);
+ log_printf("===========================\n", 0);
+ }
+
+ if (system_failed)
+ return (1);
+ else
+ return (0);
+}
+
+void
+display_hp_fail_fault(Sys_tree *tree, struct system_kstat_data *kstats)
+{
+#ifdef lint
+ kstats = kstats;
+#endif
+ /* Display failed units */
+ (void) disp_fail_parts(tree);
+}
+
+
+void
+display_diaginfo(int flag, Prom_node *root, Sys_tree *tree,
+ struct system_kstat_data *kstats)
+{
+ /*
+ * Now display the last powerfail time and the fatal hardware
+ * reset information. We do this under a couple of conditions.
+ * First if the user asks for it. The second is iof the user
+ * told us to do logging, and we found a system failure.
+ */
+ if (flag) {
+ /*
+ * display time of latest powerfail. Not all systems
+ * have this capability. For those that do not, this
+ * is just a no-op.
+ */
+ disp_powerfail(root);
+
+ (void) disp_envctrl_status(tree, kstats);
+
+ tazjav_disp_asic_revs(tree);
+
+ platform_disp_prom_version(tree);
+ }
+ return;
+
+}
+
+/* ARGSUSED */
+void
+display_boardnum(int num)
+{
+ log_printf("SYS ", 0);
+}
+
+
+
+/*
+ * display_pci
+ * Display all the PCI IO cards on this board.
+ */
+
+/* ARGSUSED */
+void
+display_pci(Board_node *board)
+{
+ struct io_card *card_list = NULL;
+ struct io_card card;
+ void *value;
+ Prom_node *pci;
+ Prom_node *card_node;
+
+ if (board == NULL)
+ return;
+
+ /* Initialize all the common information */
+ card.display = 1;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "PCI");
+
+ for (pci = dev_find_node(board->nodes, PCI_NAME); pci != NULL;
+ pci = dev_next_node(pci, PCI_NAME)) {
+ char *name;
+ Prom_node *prev_parent = NULL;
+ int prev_device = -1;
+ int pci_pci_bridge = 0;
+
+ /*
+ * If we have reached a pci-to-pci bridge node,
+ * we are one level below the 'pci' nodes level
+ * in the device tree. To get back to that level,
+ * the search should continue with the sibling of
+ * the parent or else the remaining 'pci' cards
+ * will not show up in the output.
+ */
+ if (find_prop(pci, "upa-portid") == NULL) {
+ if ((pci->parent->sibling != NULL) &&
+ (strcmp(get_prop_val(
+ find_prop(pci->parent->sibling,
+ "name")), PCI_NAME) == 0))
+ pci = pci->parent->sibling;
+ else {
+ pci = pci->parent->sibling;
+ continue;
+ }
+ }
+
+ /* Skip all failed nodes for now */
+ if (node_failed(pci))
+ continue;
+
+ /* Fill in frequency */
+ value = get_prop_val(find_prop(pci, "clock-frequency"));
+ if (value == NULL)
+ card.freq = -1;
+ else
+ card.freq = ((*(int *)value) + 500000) / 1000000;
+
+ /* Walk through the PSYCHO children */
+ card_node = pci->child;
+ while (card_node != NULL) {
+ Prop *compat = NULL;
+
+ /* If it doesn't have a name, skip it */
+ name = (char *)get_prop_val(
+ find_prop(card_node, "name"));
+ if (name == NULL) {
+ card_node = card_node->sibling;
+ continue;
+ }
+
+ /*
+ * If this is a PCI bridge, then display its
+ * children.
+ */
+ if (strcmp(name, "pci") == 0) {
+ card_node = card_node->child;
+ pci_pci_bridge = 1;
+ continue;
+ }
+
+ /* Get the slot number for this card */
+ if (pci_pci_bridge) {
+ card.slot = tazmo_physical_slot(
+ dev_find_node(board->nodes, "slot2dev"),
+ pci,
+ get_pci_to_pci_device(
+ card_node->parent),
+ card.slot_str);
+ } else
+ card.slot = tazmo_physical_slot(
+ dev_find_node(board->nodes,
+ "slot2dev"),
+ pci,
+ get_pci_device(card_node),
+ card.slot_str);
+
+ /*
+ * Check that duplicate devices are not reported
+ * on Tazmo.
+ */
+ if ((card_node->parent == prev_parent) &&
+ (get_pci_device(card_node) == prev_device) &&
+ (pci_pci_bridge == 0))
+ card.slot = -1;
+ prev_parent = card_node->parent;
+ prev_device = get_pci_device(card_node);
+
+
+ if (card.slot == -1 || strstr(name, "ebus")) {
+ card_node = card_node->sibling;
+ continue;
+ }
+
+ /* XXX - Don't know how to get status for PCI cards */
+ card.status[0] = '\0';
+
+ /* Get the model of this card */
+ value = get_prop_val(find_prop(card_node, "model"));
+ if (value == NULL)
+ card.model[0] = '\0';
+ else
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+
+ /*
+ * Check if further processing is necessary to display
+ * this card uniquely.
+ */
+ distinguish_identical_io_cards(name, card_node, &card);
+
+ /*
+ * If we haven't figured out the frequency yet,
+ * try and get it from the card.
+ */
+ value = get_prop_val(find_prop(pci, "clock-frequency"));
+ if (value != NULL && card.freq == -1)
+ card.freq = ((*(int *)value) + 500000)
+ / 1000000;
+
+
+ value = get_prop_val(find_prop(card_node,
+ "compatible"));
+
+ /*
+ * On Tazmo, we would like to print out the last
+ * string of the "compatible" property if it exists.
+ * The IEEE 1275 spec. states that this last string
+ * will be the classcode name.
+ */
+ if (value != NULL) {
+ char *tval;
+ int index;
+ const int always = 1;
+
+ tval = (char *)value;
+ index = 0;
+ compat = find_prop(card_node, "compatible");
+ while (always) {
+ if ((strlen(tval) + 1) ==
+ (compat->size - index))
+ break;
+ index += strlen(tval) + 1;
+ tval += strlen(tval) + 1;
+ }
+ value = (void *)tval;
+ }
+
+ if (value != NULL)
+ (void) sprintf(card.name, "%s-%s",
+ (char *)name, (char *)value);
+ else
+ (void) sprintf(card.name, "%s",
+ (char *)name);
+
+ if (card.freq != -1)
+ card_list = insert_io_card(card_list, &card);
+
+ /*
+ * If we are done with the children of the pci bridge,
+ * we must continue with the remaining siblings of
+ * the pci-to-pci bridge.
+ */
+ if ((card_node->sibling == NULL) && pci_pci_bridge) {
+ card_node = card_node->parent->sibling;
+ pci_pci_bridge = 0;
+ } else
+ card_node = card_node->sibling;
+ }
+ }
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+
+/*
+ * Print out all the io cards in the list. Also print the column
+ * headers if told to do so.
+ */
+void
+display_io_cards(struct io_card *list)
+{
+ static int banner = 0; /* Have we printed the column headings? */
+ struct io_card *p;
+
+ if (list == NULL)
+ return;
+
+ if (banner == 0) {
+ log_printf(" Bus Freq\n", 0);
+ log_printf("Brd Type MHz Slot "
+ "Name Model", 0);
+ log_printf("\n", 0);
+ log_printf("--- ---- ---- ---- "
+ "-------------------------------- "
+ "----------------------", 0);
+ log_printf("\n", 0);
+ banner = 1;
+ }
+
+ for (p = list; p != NULL; p = p -> next) {
+ log_printf("SYS ", p->board, 0);
+ log_printf("%-4s ", p->bus_type, 0);
+ log_printf("%3d ", p->freq, 0);
+ log_printf("%3d ", p->slot, 0);
+ log_printf("%-32.32s", p->name, 0);
+ if (strlen(p->name) > 32)
+ log_printf("+ ", 0);
+ else
+ log_printf(" ", 0);
+ log_printf("%-22.22s", p->model, 0);
+ if (strlen(p->model) > 22)
+ log_printf("+", 0);
+ log_printf("\n", 0);
+ }
+}
+
+/*
+ * display_ffb
+ * Display all FFBs on this board. It can either be in tabular format,
+ * or a more verbose format.
+ */
+void
+display_ffb(Board_node *board, int table)
+{
+ Prom_node *ffb;
+ void *value;
+ struct io_card *card_list = NULL;
+ struct io_card card;
+
+ if (board == NULL)
+ return;
+
+ /* Fill in common information */
+ card.display = 1;
+ card.board = board->board_num;
+ (void) sprintf(card.bus_type, "UPA");
+ card.freq = sys_clk;
+
+ for (ffb = dev_find_node(board->nodes, FFB_NAME); ffb != NULL;
+ ffb = dev_next_node(ffb, FFB_NAME)) {
+ if (table == 1) {
+ /* Print out in table format */
+
+ /* XXX - Get the slot number (hack) */
+ card.slot = tazmo_physical_slot(
+ dev_find_node(board->nodes, "slot2dev"),
+ ffb,
+ -1,
+ card.slot_str);
+
+ /* Find out if it's single or double buffered */
+ (void) sprintf(card.name, "FFB");
+ value = get_prop_val(find_prop(ffb, "board_type"));
+ if (value != NULL)
+ if ((*(int *)value) & FFB_B_BUFF)
+ (void) sprintf(card.name,
+ "FFB, Double Buffered");
+ else
+ (void) sprintf(card.name,
+ "FFB, Single Buffered");
+
+ /* Print model number */
+ card.model[0] = '\0';
+ value = get_prop_val(find_prop(ffb, "model"));
+ if (value != NULL)
+ (void) sprintf(card.model, "%s",
+ (char *)value);
+
+ card_list = insert_io_card(card_list, &card);
+ } else {
+ /* print in long format */
+ char device[MAXSTRLEN];
+ int fd = -1;
+ struct dirent *direntp;
+ DIR *dirp;
+ union strap_un strap;
+ struct ffb_sys_info fsi;
+
+ /* Find the device node using upa address */
+ value = get_prop_val(find_prop(ffb, "upa-portid"));
+ if (value == NULL)
+ continue;
+
+ (void) sprintf(device, "%s@%x", FFB_NAME,
+ *(int *)value);
+ if ((dirp = opendir("/devices")) == NULL)
+ continue;
+
+ while ((direntp = readdir(dirp)) != NULL) {
+ if (strstr(direntp->d_name, device) != NULL) {
+ (void) sprintf(device, "/devices/%s",
+ direntp->d_name);
+ fd = open(device, O_RDWR, 0666);
+ break;
+ }
+ }
+ (void) closedir(dirp);
+
+ if (fd == -1)
+ continue;
+
+ if (ioctl(fd, FFB_SYS_INFO, &fsi) < 0)
+ continue;
+
+ log_printf("FFB Hardware Configuration:\n", 0);
+ log_printf("-----------------------------------\n", 0);
+
+ strap.ffb_strap_bits = fsi.ffb_strap_bits;
+ log_printf("\tBoard rev: %d\n",
+ (int)strap.fld.board_rev, 0);
+ log_printf("\tFBC version: 0x%x\n", fsi.fbc_version, 0);
+ log_printf("\tDAC: %s\n",
+ fmt_manf_id(fsi.dac_version, device), 0);
+ log_printf("\t3DRAM: %s\n",
+ fmt_manf_id(fsi.fbram_version, device), 0);
+ log_printf("\n", 0);
+ }
+ }
+
+ display_io_cards(card_list);
+ free_io_cards(card_list);
+}
+
+/*
+ * This module does the reading and interpreting of tazmo system
+ * kstats. These kstats are created by the environ driver:
+ */
+void
+read_platform_kstats(Sys_tree *tree, struct system_kstat_data *sys_kstat,
+ struct bd_kstat_data *bdp, struct envctrl_kstat_data *ep)
+{
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+
+ if ((kc = kstat_open()) == NULL) {
+ return;
+ }
+#ifdef lint
+ tree = tree;
+ bdp = bdp;
+#endif
+
+ ep = &sys_kstat->env_data;
+
+ /* Read the power supply kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_PSNAME);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ep->ps_kstats, ksp->ks_data,
+ MAX_DEVS * sizeof (envctrl_ps_t));
+ } else {
+ sys_kstat->envctrl_kstat_ok = B_FALSE;
+ return;
+ }
+
+ /* Read the fan status kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_FANSTAT);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ep->fan_kstats, ksp->ks_data,
+ ksp->ks_ndata * sizeof (envctrl_fan_t));
+ } else {
+ sys_kstat->envctrl_kstat_ok = B_FALSE;
+ return;
+ }
+
+ /* Read the enclosure kstats */
+ ksp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, INSTANCE_0,
+ ENVCTRL_KSTAT_ENCL);
+
+ if (ksp != NULL && (kstat_read(kc, ksp, NULL) != -1)) {
+ (void) memcpy(ep->encl_kstats, ksp->ks_data,
+ ksp->ks_ndata * sizeof (envctrl_encl_t));
+ } else {
+ sys_kstat->envctrl_kstat_ok = B_FALSE;
+ return;
+ }
+
+ sys_kstat->envctrl_kstat_ok = B_TRUE;
+}
+
+/*
+ * Walk the PROM device tree and build the system tree and root tree.
+ * Nodes that have a board number property are placed in the board
+ * structures for easier processing later. Child nodes are placed
+ * under their parents. ffb (Fusion Frame Buffer) nodes are handled
+ * specially, because they do not contain board number properties.
+ * This was requested from OBP, but was not granted. So this code
+ * must parse the MID of the FFB to find the board#.
+ */
+Prom_node *
+walk(Sys_tree *tree, Prom_node *root, int id)
+{
+ register int curnode;
+ Prom_node *pnode;
+ char *name;
+ char *type;
+ char *model;
+ int board_node = 0;
+
+ /* allocate a node for this level */
+ if ((pnode = (Prom_node *) malloc(sizeof (struct prom_node))) ==
+ NULL) {
+ perror("malloc");
+ exit(2); /* program errors cause exit 2 */
+ }
+
+ /* assign parent Prom_node */
+ pnode->parent = root;
+ pnode->sibling = NULL;
+ pnode->child = NULL;
+
+ /* read properties for this node */
+ dump_node(pnode);
+
+ /*
+ * Place a node in a 'board' if it has 'board'-ness. The definition
+ * is that all nodes that are children of root should have a
+ * board# property. But the PROM tree does not exactly follow
+ * this. This is where we start hacking. The name 'ffb' can
+ * change, so watch out for this.
+ *
+ * The UltraSPARC, sbus, pci and ffb nodes will exit in
+ * the desktops and will not have board# properties. These
+ * cases must be handled here.
+ *
+ * PCI to PCI bridges also have the name "pci", but with different
+ * model property values. They should not be put under 'board'.
+ */
+ name = get_node_name(pnode);
+ type = get_node_type(pnode);
+ model = (char *)get_prop_val(find_prop(pnode, "model"));
+#ifdef DEBUG
+ if (name != NULL)
+ printf("name=%s ", name);
+ if (type != NULL)
+ printf("type=%s ", type);
+ if (model != NULL)
+ printf("model=%s", model);
+ printf("\n");
+
+ if (model == NULL)
+ model = "";
+#endif
+ if (type == NULL)
+ type = "";
+ if (name != NULL) {
+ if (has_board_num(pnode)) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s model=%s\n",
+ name, type, model);
+#endif
+ } else if ((strcmp(name, FFB_NAME) == 0) ||
+ (strcmp(type, "cpu") == 0) ||
+
+ ((strcmp(name, "pci") == 0) && (model != NULL) &&
+ (strcmp(model, "SUNW,psycho") == 0)) ||
+
+ ((strcmp(name, "pci") == 0) && (model != NULL) &&
+ (strcmp(model, "SUNW,sabre") == 0)) ||
+
+ (strcmp(name, "counter-timer") == 0) ||
+ (strcmp(name, "sbus") == 0) ||
+ (strcmp(name, "memory") == 0) ||
+ (strcmp(name, "mc") == 0) ||
+ (strcmp(name, "associations") == 0)) {
+ add_node(tree, pnode);
+ board_node = 1;
+#ifdef DEBUG
+ printf("ADDED BOARD name=%s type=%s model=%s\n",
+ name, type, model);
+#endif
+ }
+#ifdef DEBUG
+ else
+ printf("node not added: name=%s type=%s\n", name, type);
+#endif
+ }
+
+ if (curnode = child(id)) {
+ pnode->child = walk(tree, pnode, curnode);
+ }
+
+ if (curnode = next(id)) {
+ if (board_node) {
+ return (walk(tree, root, curnode));
+ } else {
+ pnode->sibling = walk(tree, root, curnode);
+ }
+ }
+
+ if (board_node) {
+ return (NULL);
+ } else {
+ return (pnode);
+ }
+}
+
+/*
+ * local functions
+ */
+
+/*
+ * disp_envctrl_status
+ *
+ * This routine displays the environmental status passed up from
+ * device drivers via kstats. The kstat names are defined in
+ * kernel header files included by this module.
+ */
+static int
+disp_envctrl_status(Sys_tree *tree, struct system_kstat_data *sys_kstats)
+{
+ int exit_code = 0;
+ int possible_failure;
+ int i;
+ uchar_t val;
+ char fan_type[16];
+ char state[48];
+ char name[16];
+ envctrl_ps_t ps;
+ envctrl_fan_t fan;
+ envctrl_encl_t encl;
+ struct envctrl_kstat_data *ep;
+ uchar_t fsp_value;
+ int i4slot_backplane_value = -1;
+ int i8slot_backplane_value = -1;
+ int j8slot_backplane_value = -1;
+ static int first_8disk_bp = 0;
+ static int second_8disk_bp = 0;
+ static int first_4disk_bp = 0;
+
+ if (sys_kstats->envctrl_kstat_ok == 0) {
+ log_printf("\n", 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Environmental information "
+ "is not available\n"), 0);
+ log_printf(dgettext(TEXT_DOMAIN, "Environmental driver may "
+ "not be installed\n"), 0);
+ log_printf("\n", 0);
+ return (1);
+ }
+
+ ep = &sys_kstats->env_data;
+
+ check_disk_presence(tree, &first_4disk_bp, &first_8disk_bp,
+ &second_8disk_bp);
+
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " Environmental Status "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ log_printf("System Temperatures (Celsius):\n", 0);
+ log_printf("------------------------------\n", 0);
+ for (i = 0; i < MAX_DEVS; i++) {
+ encl = ep->encl_kstats[i];
+ switch (encl.type) {
+ case ENVCTRL_ENCL_AMBTEMPR:
+ if (encl.instance == I2C_NODEV)
+ continue;
+ (void) sprintf(name, "%s", "AMBIENT");
+ log_printf("%s %d", name, encl.value);
+ if (encl.value > MAX_AMB_TEMP) {
+ log_printf(" WARNING\n", 0);
+ exit_code = 1;
+ } else
+ log_printf("\n", 0);
+ break;
+ case ENVCTRL_ENCL_CPUTEMPR:
+ if (encl.instance == I2C_NODEV)
+ continue;
+ (void) sprintf(name, "%s %d", "CPU", encl.instance);
+ log_printf("%s %d", name, encl.value);
+ if (encl.value > MAX_CPU_TEMP) {
+ log_printf(" WARNING\n", 0);
+ exit_code = 1;
+ } else
+ log_printf("\n", 0);
+ break;
+ case ENVCTRL_ENCL_FSP:
+ if (encl.instance == I2C_NODEV)
+ continue;
+ val = encl.value & ENVCTRL_FSP_KEYMASK;
+ fsp_value = encl.value;
+ switch (val) {
+ case ENVCTRL_FSP_KEYOFF:
+ (void) sprintf(state, "%s", "Off");
+ break;
+ case ENVCTRL_FSP_KEYON:
+ (void) sprintf(state, "%s", "On");
+ break;
+ case ENVCTRL_FSP_KEYDIAG:
+ (void) sprintf(state, "%s", "Diagnostic");
+ break;
+ case ENVCTRL_FSP_KEYLOCKED:
+ (void) sprintf(state, "%s", "Secure");
+ break;
+ default:
+ (void) sprintf(state, "%s", "Broken!");
+ exit_code = 1;
+ break;
+ }
+ break;
+ case ENVCTRL_ENCL_BACKPLANE4:
+ case ENVCTRL_ENCL_BACKPLANE8:
+ if (encl.instance == I2C_NODEV)
+ continue;
+ switch (encl.instance) {
+ case 0:
+ i4slot_backplane_value =
+ encl.value & ENVCTRL_4SLOT_BACKPLANE;
+ break;
+ case 1:
+ i8slot_backplane_value =
+ encl.value & ENVCTRL_8SLOT_BACKPLANE;
+ break;
+ case 2:
+ j8slot_backplane_value =
+ encl.value & ENVCTRL_8SLOT_BACKPLANE;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ log_printf("=================================\n\n", 0);
+ log_printf("Front Status Panel:\n", 0);
+ log_printf("-------------------\n", 0);
+ log_printf("Keyswitch position is in %s mode.\n", state);
+ log_printf("\n", 0);
+ val = fsp_value & (ENVCTRL_FSP_DISK_ERR | ENVCTRL_FSP_PS_ERR |
+ ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_GEN_ERR |
+ ENVCTRL_FSP_ACTIVE);
+ log_printf("System LED Status: POWER GENERAL ERROR "
+ " ACTIVITY\n", 0);
+ log_printf(" [ ON] [%3s] "
+ " [%3s]\n", val & ENVCTRL_FSP_GEN_ERR ? "ON" : "OFF",
+ val & ENVCTRL_FSP_ACTIVE ? "ON" : "OFF");
+ log_printf(" DISK ERROR "
+ "THERMAL ERROR POWER SUPPLY ERROR\n", 0);
+ log_printf(" [%3s] [%3s] "
+ " [%3s]\n", val & ENVCTRL_FSP_DISK_ERR ? "ON" : "OFF",
+ val & ENVCTRL_FSP_TEMP_ERR ? "ON" : "OFF",
+ val & ENVCTRL_FSP_PS_ERR ? "ON" : "OFF");
+ log_printf("\n", 0);
+ /* record error conditions */
+ if (val & (ENVCTRL_FSP_GEN_ERR | ENVCTRL_FSP_DISK_ERR |
+ ENVCTRL_FSP_TEMP_ERR | ENVCTRL_FSP_PS_ERR)) {
+ exit_code = 1;
+ }
+
+
+ log_printf("Disk LED Status: OK = GREEN ERROR = YELLOW\n", 0);
+
+ if (j8slot_backplane_value != -1) {
+ log_printf(" DISK 18: %7s DISK 19: %7s\n",
+ second_8disk_bp & ENVCTRL_DISK_6 ?
+ j8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_7 ?
+ j8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ log_printf(" DISK 16: %7s DISK 17: %7s\n",
+ second_8disk_bp & ENVCTRL_DISK_4 ?
+ j8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_5 ?
+ j8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ log_printf(" DISK 14: %7s DISK 15: %7s\n",
+ second_8disk_bp & ENVCTRL_DISK_2 ?
+ j8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_3 ?
+ j8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ log_printf(" DISK 12: %7s DISK 13: %7s\n",
+ second_8disk_bp & ENVCTRL_DISK_0 ?
+ j8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", second_8disk_bp & ENVCTRL_DISK_1 ?
+ j8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ }
+ if (i8slot_backplane_value != -1) {
+ log_printf(" DISK 10: %7s DISK 11: %7s\n",
+ first_8disk_bp & ENVCTRL_DISK_6 ?
+ i8slot_backplane_value & ENVCTRL_DISK_6 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_7 ?
+ i8slot_backplane_value & ENVCTRL_DISK_7 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ log_printf(" DISK 8: %7s DISK 9: %7s\n",
+ first_8disk_bp & ENVCTRL_DISK_4 ?
+ i8slot_backplane_value & ENVCTRL_DISK_4 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_5 ?
+ i8slot_backplane_value & ENVCTRL_DISK_5 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ log_printf(" DISK 6: %7s DISK 7: %7s\n",
+ first_8disk_bp & ENVCTRL_DISK_2 ?
+ i8slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_3 ?
+ i8slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ log_printf(" DISK 4: %7s DISK 5: %7s\n",
+ first_8disk_bp & ENVCTRL_DISK_0 ?
+ i8slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", first_8disk_bp & ENVCTRL_DISK_1 ?
+ i8slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ }
+ if (i4slot_backplane_value != -1) {
+ log_printf(" DISK 2: %7s DISK 3: %7s\n",
+ first_4disk_bp & ENVCTRL_DISK_2 ?
+ i4slot_backplane_value & ENVCTRL_DISK_2 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_3 ?
+ i4slot_backplane_value & ENVCTRL_DISK_3 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ log_printf(" DISK 0: %7s DISK 1: %7s\n",
+ first_4disk_bp & ENVCTRL_DISK_0 ?
+ i4slot_backplane_value & ENVCTRL_DISK_0 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]", first_4disk_bp & ENVCTRL_DISK_1 ?
+ i4slot_backplane_value & ENVCTRL_DISK_1 ? "[ERROR]" : "[OK]"
+ : "[EMPTY]");
+ }
+
+ log_printf("=================================\n", 0);
+ log_printf("\n", 0);
+
+ log_printf("Fans:\n", 0);
+ log_printf("-----\n", 0);
+
+ log_printf("Fan Bank Speed Status\n", 0);
+ log_printf("-------- ----- ------\n", 0);
+
+ for (i = 0; i < MAX_DEVS; i++) {
+ fan = ep->fan_kstats[i];
+
+ if (fan.instance == I2C_NODEV)
+ continue;
+
+ switch (fan.type) {
+ case ENVCTRL_FAN_TYPE_CPU:
+ (void) sprintf(fan_type, "%s", "CPU");
+ break;
+ case ENVCTRL_FAN_TYPE_PS:
+ (void) sprintf(fan_type, "%s", "PWR");
+ break;
+ case ENVCTRL_FAN_TYPE_AFB:
+ (void) sprintf(fan_type, "%s", "AFB");
+ break;
+ }
+ if (fan.fans_ok == B_TRUE) {
+ (void) sprintf(state, "%s", " OK ");
+ } else {
+ (void) sprintf(state, "FAILED (FAN# %d)",
+ fan.fanflt_num);
+ /* we know fan.instance != I2C_NODEV */
+ exit_code = 1;
+ }
+ if (fan.instance != I2C_NODEV)
+ log_printf("%s %d %s\n", fan_type,
+ fan.fanspeed, state);
+ }
+
+
+ log_printf("\n", 0);
+
+ log_printf("\n", 0);
+ log_printf("Power Supplies:\n", 0);
+ log_printf("---------------\n", 0);
+ log_printf("Supply Rating Temp Status\n", 0);
+ log_printf("------ ------ ---- ------\n", 0);
+ for (i = 0; i < MAX_DEVS; i++) {
+ ps = ep->ps_kstats[i];
+ if (ps.curr_share_ok == B_TRUE &&
+ ps.limit_ok == B_TRUE && ps.ps_ok == B_TRUE) {
+ (void) sprintf(state, "%s", " OK ");
+ possible_failure = 0;
+ } else {
+ if (ps.ps_ok != B_TRUE) {
+ (void) sprintf(state, "%s",
+ "FAILED: DC Power Failure");
+ possible_failure = 1;
+ } else if (ps.curr_share_ok != B_TRUE) {
+ (void) sprintf(state, "%s",
+ "WARNING: Current Share Imbalance");
+ possible_failure = 1;
+ } else if (ps.limit_ok != B_TRUE) {
+ (void) sprintf(state, "%s",
+ "WARNING: Current Overload");
+ possible_failure = 1;
+ }
+ }
+
+ if (ps.instance != I2C_NODEV && ps.ps_rating != 0) {
+ log_printf(" %2d %4d W %2d %s\n",
+ ps.instance, ps.ps_rating, ps.ps_tempr, state);
+ if (possible_failure)
+ exit_code = 1;
+ }
+ }
+
+ return (exit_code);
+}
+
+/*
+ * This function will return a bitmask for each of the 4 disk backplane
+ * and the two 8 disk backplanes. It creates this mask by first obtaining
+ * the PROM path of the controller for each slot using the "slot2dev"
+ * node in the PROM tree. It then modifies the PROM path to obtain a
+ * physical device path to the controller. The presence of the controller
+ * is determined by trying to open the controller device and reading
+ * some information from the device. Currently only supported on Tazmo.
+ */
+static void
+check_disk_presence(Sys_tree *tree, int *i4disk, int *i8disk, int *j8disk)
+{
+ Board_node *bnode;
+ Prom_node *slot2disk = NULL;
+ Prop *slotprop;
+ char *devpath_p;
+ char devpath[MAXSTRLEN];
+ char slotx[16] = "";
+ int slot;
+ int slot_ptr = 0;
+
+ bnode = tree->bd_list;
+ *i4disk = *i8disk, *j8disk = 0;
+
+ slot2disk = dev_find_node(bnode->nodes, "slot2disk");
+
+ for (slot = 0; slot < 20; slot++) {
+ (void) sprintf(slotx, "slot#%d", slot);
+ if ((slotprop = find_prop(slot2disk, slotx)) != NULL)
+ if ((devpath_p = (char *)(get_prop_val(slotprop)))
+ != NULL) {
+ modify_device_path(devpath_p, devpath);
+ if (disk_present(devpath)) {
+ if (slot < 4)
+ *i4disk |= 1 << slot_ptr;
+ else if (slot < 12)
+ *i8disk |= 1 << slot_ptr;
+ else if (slot < 20)
+ *j8disk |= 1 << slot_ptr;
+ }
+ }
+ if ((slot == 3) || (slot == 11))
+ slot_ptr = 0;
+ else
+ slot_ptr++;
+ }
+}
+
+
+
+/*
+ * modify_device_path
+ *
+ * This function modifies a string from the slot2disk association
+ * PROM node to a physical device path name. For example if the
+ * slot2disk association value is "/pci@1f,4000/scsi@3/disk@1",
+ * the equivalent physical device path will be
+ * "/devices/pci@1f,4000/scsi@3/sd@1,0:c,raw".
+ * We use this path to attempt to probe the disk to check for its
+ * presence in the enclosure. We access the 'c' partition
+ * which represents the entire disk.
+ */
+static void
+modify_device_path(char *oldpath, char *newpath)
+{
+ char *changeptr;
+ long target;
+ char targetstr[16];
+
+ (void) strcpy(newpath, "/devices");
+ changeptr = strstr(oldpath, "disk@");
+ /*
+ * The assumption here is that nothing but the
+ * target id follows the disk@ substring.
+ */
+ target = strtol(changeptr+5, NULL, 16);
+ (void) strncat(newpath, oldpath, changeptr - oldpath);
+ (void) sprintf(targetstr, "sd@%ld,0:c,raw", target);
+ (void) strcat(newpath, targetstr);
+}
+
+/*
+ * Returns 0 if the device at devpath is not *physically* present. If it is,
+ * then info on that device is placed in the dkinfop buffer, and 1 is returned.
+ * Keep in mind that ioctl(DKIOCINFO)'s CDROMs owned by vold fail, so only
+ * the dki_ctype field is set in that case.
+ */
+static int
+disk_present(char *devpath)
+{
+ int search_file;
+ struct stat stbuf;
+ struct dk_cinfo dkinfo;
+
+ /*
+ * Attempt to open the disk. If it fails, skip it.
+ */
+ if ((search_file = open(devpath, O_RDONLY | O_NDELAY)) < 0)
+ return (0);
+
+ /*
+ * Must be a character device
+ */
+ if (fstat(search_file, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
+ (void) close(search_file);
+ return (0);
+ }
+
+ /*
+ * Attempt to read the configuration info on the disk.
+ * If it fails, we assume the disk's not there.
+ * Note we must close the file for the disk before we
+ * continue.
+ */
+ if (ioctl(search_file, DKIOCINFO, &dkinfo) < 0) {
+ (void) close(search_file);
+ return (0);
+ }
+ (void) close(search_file);
+ return (1);
+}
+
+void
+tazjav_disp_asic_revs(Sys_tree *tree)
+{
+ Board_node *bnode;
+ Prom_node *pnode;
+ char *name;
+ int *version;
+ char *model;
+
+ /* Print the header */
+ log_printf("\n", 0);
+ log_printf("=========================", 0);
+ log_printf(dgettext(TEXT_DOMAIN, " HW Revisions "), 0);
+ log_printf("=========================", 0);
+ log_printf("\n", 0);
+ log_printf("\n", 0);
+
+ bnode = tree->bd_list;
+
+ log_printf("ASIC Revisions:\n", 0);
+ log_printf("---------------\n", 0);
+
+ /* Find sysio and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "sbus"); pnode != NULL;
+ pnode = dev_next_node(pnode, "sbus")) {
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ log_printf("SBus: %s Rev %d\n",
+ name, *version, 0);
+ }
+ }
+
+ /* Find Psycho and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "pci"); pnode != NULL;
+ pnode = dev_next_node(pnode, "pci")) {
+ Prom_node *parsib = pnode->parent->sibling;
+
+ if (find_prop(pnode, "upa-portid") == NULL) {
+ if ((parsib != NULL) &&
+ (strcmp(get_prop_val(
+ find_prop(parsib, "name")),
+ PCI_NAME) == 0))
+ pnode = parsib;
+ else {
+ pnode = parsib;
+ continue;
+ }
+ }
+
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL))
+ if (get_pci_bus(pnode) == 0)
+ log_printf("STP2223BGA: Rev %d\n", *version, 0);
+ }
+
+ /* Find Cheerio and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "ebus"); pnode != NULL;
+ pnode = dev_next_node(pnode, "ebus")) {
+ version = (int *)get_prop_val(find_prop(pnode, "revision-id"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL))
+ log_printf("STP2003QFP: Rev %d\n", *version, 0);
+ }
+
+ /* Find System Controller and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "sc"); pnode != NULL;
+ pnode = dev_next_node(pnode, "sc")) {
+ version = (int *)get_prop_val(find_prop(pnode, "version#"));
+ model = (char *)get_prop_val(find_prop(pnode, "model"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ if ((strcmp(model, "SUNW,sc-marvin") == 0))
+ log_printf("STP2205BGA: Rev %d\n", *version, 0);
+ }
+ }
+
+ /* Find the FEPS and print rev */
+ for (pnode = dev_find_node(bnode->nodes, "SUNW,hme"); pnode != NULL;
+ pnode = dev_next_node(pnode, "SUNW,hme")) {
+ version = (int *)get_prop_val(find_prop(pnode, "hm-rev"));
+ name = get_prop_val(find_prop(pnode, "name"));
+
+ if ((version != NULL) && (name != NULL)) {
+ log_printf("FEPS: %s Rev ", name);
+ if (*version == 0xa0) {
+ log_printf("2.0\n", 0);
+ } else if (*version == 0x20) {
+ log_printf("2.1\n", 0);
+ } else {
+ log_printf("%x\n", *version, 0);
+ }
+ }
+ }
+ log_printf("\n", 0);
+
+ if (dev_find_node(bnode->nodes, FFB_NAME) != NULL) {
+ display_ffb(bnode, 0);
+ }
+}
+
+
+/*
+ * Determine the physical PCI slot based on which Psycho is the parent
+ * of the PCI card.
+ */
+static int
+tazmo_physical_slot(Prom_node *slotd, Prom_node *parent, int device, char *str)
+{
+ int *upa_id = NULL;
+ int *reg = NULL;
+ int offset;
+ char controller[MAXSTRLEN];
+ char *name;
+ Prop *prop;
+ char *devpath_p;
+ char slotx[16] = "";
+ int *slot_names_mask;
+ char *slot_names;
+ int shift = 0;
+ int slot;
+ int slots, start_slot;
+
+ /*
+ * If slotd != NULL, then we must return the physical PCI slot
+ * number based on the information in the slot2dev associations
+ * node. This routine is called from display_pci() with slotd
+ * != NULL. If so, we return without obtaining the slot name.
+ * If slotd == NULL, we look for the slot name through the
+ * slot-names property in the bus node.
+ */
+
+ if (slotd != NULL) {
+ (void) strcpy(str, "");
+ if ((prop = find_prop(parent, "upa-portid")) != NULL)
+ upa_id = (int *)(get_prop_val(prop));
+ if ((prop = find_prop(parent, "reg")) != NULL)
+ reg = (int *)(get_prop_val(prop));
+ if ((prop = find_prop(parent, "name")) != NULL)
+ name = (char *)(get_prop_val(prop));
+ if ((upa_id == NULL) || (reg == NULL)) {
+ return (-1);
+ }
+ offset = reg[1];
+ if (strcmp(name, "pci") == 0) {
+ (void) sprintf(controller, "/pci@%x,%x/*@%x,*",
+ *upa_id, offset, device);
+ slots = 20;
+ } else if (strcmp(name, "SUNW,ffb") == 0) {
+ (void) sprintf(controller, "/*@%x,0", *upa_id);
+ slots = 2;
+ }
+
+ start_slot = 1;
+ for (slot = start_slot; slot <= slots; slot++) {
+ if (strcmp(name, "pci") == 0)
+ (void) sprintf(slotx, "pci-slot#%d", slot);
+ else if (strcmp(name, "SUNW,ffb") == 0)
+ (void) sprintf(slotx, "graphics#%d", slot);
+ if ((prop = find_prop(slotd, slotx)) != NULL)
+ if ((devpath_p = (char *)(get_prop_val
+ (prop))) != NULL)
+ if (strcmp(devpath_p, controller) ==
+ NULL)
+ return (slot);
+ }
+ return (-1);
+ }
+
+ /*
+ * Get slot-names property from parent node.
+ * This property consists of a 32 bit mask indicating which
+ * devices are relevant to this bus node. Following are a
+ * number of strings depending on how many bits are set in the
+ * bit mask; the first string gives the label that is printed
+ * on the chassis for the smallest device number, and so on.
+ */
+
+ prop = find_prop(parent, "slot-names");
+ if (prop == NULL) {
+ (void) strcpy(str, "");
+ return (-1);
+ }
+ slot_names_mask = (int *)(get_prop_val(prop));
+ slot_names = (char *)slot_names_mask;
+
+ slot = 1;
+ slot_names += 4; /* Skip the 4 byte bitmask */
+
+ while (shift < 32) {
+ /*
+ * Shift through the bitmask looking to see if the
+ * bit corresponding to "device" is set. If so, copy
+ * the correcsponding string to the provided pointer.
+ */
+ if (*slot_names_mask & slot) {
+ if (shift == device) {
+ (void) strcpy(str, slot_names);
+ return (0);
+ }
+ slot_names += strlen(slot_names)+1;
+ }
+ shift++;
+ slot = slot << 1;
+ }
+ return (-1);
+}
diff --git a/usr/src/lib/librsc/Makefile b/usr/src/lib/librsc/Makefile
new file mode 100644
index 0000000000..52b7a6ffec
--- /dev/null
+++ b/usr/src/lib/librsc/Makefile
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/librsc/Makefile
+
+SUBDIRS= $(MACH)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint : $(SUBDIRS)
+
+$(MACH): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/librsc/Makefile.com b/usr/src/lib/librsc/Makefile.com
new file mode 100644
index 0000000000..f5f08298fd
--- /dev/null
+++ b/usr/src/lib/librsc/Makefile.com
@@ -0,0 +1,97 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/librsc/Makefile.com
+#
+
+LIBRARY= librsc.a
+VERS= .1
+
+# PLATFORM_OBJECTS is defined in platform Makefile
+OBJECTS= $(PLATFORM_OBJECTS)
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/Makefile.psm
+
+CPPFLAGS += $(PLATINCS)
+
+LINKED_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%)
+LINKED_LIB_DIRS = $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib)
+LINKED_LIBRSC_DIR = \
+ $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/librsc.so)
+LINKED_LIBRSC1_DIR = \
+ $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/librsc.so.1)
+LINKED_LLIBLRSC_DIR = \
+ $(LINKED_PLATFORMS:%=$(USR_PLAT_DIR)/%/lib/llib-lrsc.ln)
+
+SRCDIR = common
+LIBS = $(DYNLIB) $(LINTLIB)
+CFLAGS += $(CCVERBOSE)
+LDLIBS += -lc
+PLATLIBS = $(USR_PLAT_DIR)/$(PLATFORM)/lib/
+INS.slink6= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/librsc.so.1 $@ $(CHOWNLINK) $(CHGRPLINK)
+INS.slink7= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/librsc.so $@ $(CHOWNLINK) $(CHGRPLINK)
+INS.slink8= $(RM) -r $@; $(SYMLINK) ../../$(PLATFORM)/lib/llib-lrsc.ln $@ $(CHOWNLINK) $(CHGRPLINK)
+
+.KEEP_STATE:
+
+#
+# build/lint rules
+#
+all: $(LIBS)
+lint: lintcheck
+
+#
+# install rules
+#
+$(PLATLIBS)/librsc.so:
+ $(RM) -r $@; $(SYMLINK) librsc.so.1 $@ $(CHOWNLINK) $(CHGRPLINK)
+
+install: all $(USR_PSM_LIBS) $(PLATLIBS)/librsc.so \
+ $(LINKED_DIRS) $(LINKED_LIB_DIRS) \
+ $(LINKED_LIBRSC_DIR) $(LINKED_LIBRSC1_DIR) \
+ $(LINKED_LLIBLRSC_DIR)
+
+$(USR_PSM_LIB_DIR)/%: % $(USR_PSM_LIB_DIR)
+ $(INS.file)
+
+$(LINKED_DIRS): $(USR_PLAT_DIR)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIB_DIRS): $(LINKED_DIRS)
+ -$(INS.dir.root.sys)
+
+$(LINKED_LIBRSC_DIR): $(USR_PLAT_DIR)
+ -$(INS.slink7)
+
+$(LINKED_LIBRSC1_DIR): $(USR_PLAT_DIR)
+ -$(INS.slink6)
+
+$(LINKED_LLIBLRSC_DIR): $(USR_PLAT_DIR)
+ -$(INS.slink8)
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/librsc/sparc/Makefile b/usr/src/lib/librsc/sparc/Makefile
new file mode 100644
index 0000000000..a971eee1d6
--- /dev/null
+++ b/usr/src/lib/librsc/sparc/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/librsc/sparc/Makefile
+#
+
+SUBDIRS = mpxu
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+all clean clobber install lint : $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/lib/librsc/sparc/Makefile.com b/usr/src/lib/librsc/sparc/Makefile.com
new file mode 100644
index 0000000000..bf0be53755
--- /dev/null
+++ b/usr/src/lib/librsc/sparc/Makefile.com
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/librsc/sparc/Makefile.com
+#
+
+PLATINCS += -I$(USR_PLAT_DIR)/sun4u/include -I$(UTSBASE)/sun4u
+
+include ../../Makefile.com
diff --git a/usr/src/lib/librsc/sparc/mpxu/Makefile b/usr/src/lib/librsc/sparc/mpxu/Makefile
new file mode 100644
index 0000000000..9860f91dd3
--- /dev/null
+++ b/usr/src/lib/librsc/sparc/mpxu/Makefile
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# lib/librsc/sparc/mpxu/Makefile
+
+UTSBASE = ../../../../uts
+
+PLATFORM_OBJECTS= librsc.o
+
+#
+# platform library directory (/usr/platform/SUNW,Sun-Fire-V240/lib)
+#
+PLATFORM=SUNW,Sun-Fire-V240
+LINKED_PLATFORMS = SUNW,Sun-Fire-V250
+LINKED_PLATFORMS += SUNW,Sun-Fire-V440
+LINKED_PLATFORMS += SUNW,Sun-Fire-V445
+LINKED_PLATFORMS += SUNW,Sun-Fire-V215
+
+include ../Makefile.com
+
+$(USR_PSM_LIB_DIR):
+ cd $(UTSBASE)/sun4u/mpxu; pwd; $(MAKE) $(USR_PSM_LIB_DIR)
diff --git a/usr/src/lib/librsc/sparc/mpxu/common/librsc.c b/usr/src/lib/librsc/sparc/mpxu/common/librsc.c
new file mode 100644
index 0000000000..863c304fcc
--- /dev/null
+++ b/usr/src/lib/librsc/sparc/mpxu/common/librsc.c
@@ -0,0 +1,711 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * ENXS platform-specific functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "librsc.h"
+
+/* rmcadm driver file descriptor */
+static int rsc_fd = -1;
+
+/*
+ * librsc receive buffer - it is used as temporary buffer to store replies
+ * from the remote side
+ */
+
+static uchar_t rsc_rx_buffer[RSC_MAX_RX_BUFFER];
+static int rsc_rx_resp_len = 0;
+static int rsc_rx_error = 0;
+static rsci8 rsc_rx_resp_type = 0;
+
+/*
+ * Registered boot-protocol message callback routine. This routine will be
+ * called whenever a boot protocol message is received.
+ */
+static rscp_bpmsg_cb_t *bpmsg_cb;
+
+
+
+/* lookup table to match request and response . This is in order to support */
+/* obsolete functions (rscp_send, rscp_recv) */
+
+static req_resp_table_t rr_table[] = {
+
+ { DP_GET_DATE_TIME, DP_GET_DATE_TIME_R,
+ sizeof (dp_get_date_time_r_t), RR_TIMEOUT },
+ { DP_SET_DATE_TIME, DP_SET_DATE_TIME_R,
+ sizeof (dp_set_date_time_r_t), RR_TIMEOUT },
+ { DP_GET_EVENT_LOG, DP_GET_EVENT_LOG_R,
+ sizeof (dp_get_event_log_r_t), RR_TIMEOUT },
+ { DP_MODEM_CONNECT, DP_MODEM_CONNECT_R,
+ sizeof (dp_modem_connect_r_t), RR_TIMEOUT },
+ { DP_MODEM_DISCONNECT, DP_MODEM_DISCONNECT_R,
+ sizeof (dp_modem_disconnect_r_t), RR_TIMEOUT },
+ { DP_SEND_ALERT, DP_SEND_ALERT_R,
+ sizeof (dp_send_alert_r_t), RR_TIMEOUT },
+ { DP_SET_CFGVAR, DP_SET_CFGVAR_R,
+ sizeof (dp_set_cfgvar_r_t), RR_TIMEOUT },
+ { DP_GET_CFGVAR, DP_GET_CFGVAR_R,
+ sizeof (dp_get_cfgvar_r_t), RR_TIMEOUT },
+ { DP_GET_CFGVAR_NAME, DP_GET_CFGVAR_NAME_R,
+ sizeof (dp_get_cfgvar_name_r_t), RR_TIMEOUT },
+ { DP_GET_NETWORK_CFG, DP_GET_NETWORK_CFG_R,
+ sizeof (dp_get_network_cfg_r_t), RR_TIMEOUT },
+ { DP_RSC_STATUS, DP_RSC_STATUS_R,
+ sizeof (dp_rsc_status_r_t), RR_TIMEOUT },
+ { DP_USER_ADM, DP_USER_ADM_R,
+ sizeof (dp_user_adm_r_t), RR_SEPROM_TIMEOUT},
+ { DP_RESET_RSC, DP_NULL_MSG,
+ 0, 1 },
+ { DP_GET_CONSOLE_LOG, DP_GET_CONSOLE_LOG_R,
+ sizeof (dp_get_console_log_r_t), RR_TIMEOUT },
+ { DP_GET_CONFIG_LOG, DP_GET_CONFIG_LOG_R,
+ sizeof (dp_get_config_log_r_t), RR_TIMEOUT },
+ { DP_GET_EVENT_LOG2, DP_GET_EVENT_LOG2_R,
+ sizeof (dp_get_event_log2_r_t), RR_TIMEOUT },
+};
+
+static const int rr_table_cnt = sizeof (rr_table) / sizeof (rr_table[0]);
+
+
+/* lookup table to get timeout value for BP cmd reply. This is in order to */
+/* support obsolete functions (rscp_send_bpmsg, rsc_raw_write) */
+
+static req_resp_table_t rr_bp_table[] = {
+
+ { BP_OBP_BOOTINIT, NULL, sizeof (bp_msg_t),
+ RR_BOOT_INIT_TIMEOUT },
+ { BP_OBP_RESET, NULL, sizeof (bp_msg_t),
+ RR_BOOT_RESET_TIMEOUT }
+};
+
+static const int rr_bp_table_cnt =
+ sizeof (rr_bp_table) / sizeof (rr_bp_table[0]);
+
+static rsci8 unsupported_cmds[] = { DP_SET_DATE_TIME };
+
+static int unsupported_cmds_cnt = sizeof (unsupported_cmds) /
+ sizeof (unsupported_cmds[0]);
+
+/*
+ * Protocol version number, used to determine whether ALOM will
+ * time out on unknown commands.
+ */
+static int sdp_version = -1;
+
+/* function prototypes */
+
+static req_resp_table_t *rsc_lookup_rr_table(req_resp_table_t *, int, rsci8);
+
+static int rsc_check_unsupported_cmd(rsci8);
+
+static int rsc_cmd_response_guaranteed(rsci8);
+
+/*
+ * Initialize the generic librsc data protocol routines. basically, it
+ * open the rmcadm (pseudo) device and initialize data
+ */
+int
+rscp_init(void)
+{
+ rscp_msg_t request, response;
+ dp_get_sdp_version_r_t version_msg;
+
+ /*
+ * 'erase' the rx buffer
+ */
+ (void) memset(rsc_rx_buffer, 0, sizeof (RSC_MAX_RX_BUFFER));
+ rsc_rx_resp_len = 0;
+ rsc_rx_error = 0;
+ rsc_rx_resp_type = DP_NULL_MSG;
+
+ /*
+ * open rmcadm driver
+ */
+ if ((rsc_fd = open(RSC_RMCADM_DRV, O_RDWR)) < 0) {
+#ifdef DEBUG
+ printf("rscp_init: Error opening %s, error code = %d\n",
+ RSC_RMCADM_DRV, errno);
+#endif
+ return (errno);
+ }
+
+ /*
+ * Fetch the protocol version number in use between the host
+ * and ALOM.
+ */
+ request.type = DP_GET_SDP_VERSION;
+ request.len = 0;
+ request.data = 0;
+
+ response.type = DP_GET_SDP_VERSION_R;
+ response.len = sizeof (version_msg);
+ response.data = (caddr_t)&version_msg;
+
+ if ((errno = rscp_send_recv(&request, &response, 0)) != 0)
+ return (errno);
+
+ sdp_version = version_msg.version;
+
+#ifdef DEBUG
+ printf("rscp_init: sdp version number is %d\n", sdp_version);
+#endif
+
+ return (0);
+}
+
+/*
+ * send/receive interface: this is the new interface where application
+ * (currently scadm, SunVTS) send a request and wait for a reply in a
+ * single call. If a response is not required (resp=NULL), the function
+ * will only return the status of the request (whether it has been successfully
+ * or not).
+ */
+int
+rscp_send_recv(rscp_msg_t *req, rscp_msg_t *resp, struct timespec *timeout)
+{
+ rmcadm_request_response_t rr;
+ rmcadm_msg_t *rr_req = &rr.req;
+ rmcadm_msg_t *rr_resp = &rr.resp;
+
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ /*
+ * the request is required, it should not be NULL!
+ */
+ if (req == NULL)
+ return (EINVAL);
+
+ /*
+ * Check if the command is actually supported
+ * if not, return an error
+ */
+ if (rsc_check_unsupported_cmd(req->type) != 0)
+ return (ENOTSUP);
+
+ /*
+ * Check if this command will generate a response and if it will not,
+ * return an error.
+ */
+ if (!rsc_cmd_response_guaranteed(req->type))
+ return (ENOTSUP);
+
+ rr_req->msg_type = req->type;
+ rr_req->msg_len = req->len;
+ rr_req->msg_buf = (caddr_t)req->data;
+
+ if (resp != NULL) {
+ rr_resp->msg_type = resp->type;
+ rr_resp->msg_len = resp->len;
+ rr_resp->msg_buf = (caddr_t)resp->data;
+ rr_resp->msg_bytes = 0;
+ } else {
+ rr_resp->msg_type = DP_NULL_MSG;
+ rr_resp->msg_buf = (caddr_t)NULL;
+ rr_resp->msg_len = 0;
+ rr_resp->msg_bytes = 0;
+ }
+
+ if (timeout == NULL) {
+ rr.wait_time = RR_TIMEOUT;
+ } else {
+ rr.wait_time = timeout->tv_sec * 1000 +
+ timeout->tv_nsec / 1000000;
+ }
+ rr.status = 0;
+
+ if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
+#ifdef DEBUG
+ printf("rscp_send_recv: req. failed, status=%d errno=%d\n",
+ rr_req->msg_type, rr.status, errno);
+#endif
+ return (errno);
+ }
+
+ return (0);
+}
+
+/*
+ * function used to look up at the request/response table. Given a request
+ * type, will return a record which provides the following information:
+ * response expected and a timeout value
+ */
+static req_resp_table_t *
+rsc_lookup_rr_table(req_resp_table_t *rr_table, int cnt, rsci8 type)
+{
+ int i;
+
+#ifdef DEBUG
+ printf("lookup for type %x, count %d\n", type, cnt);
+#endif
+
+ for (i = 0; i < cnt; i++)
+ if (rr_table[i].req_type == type) {
+ return (rr_table + i);
+ }
+
+ return (NULL);
+}
+
+/*
+ * function to check if a message type is in the list of unsupported commands
+ * If so, will return 1.
+ */
+static int
+rsc_check_unsupported_cmd(rsci8 type)
+{
+ int i;
+
+ for (i = 0; i < unsupported_cmds_cnt; i++)
+ if (unsupported_cmds[i] == type) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Returns 1 if ALOM will generate a response to the given command code,
+ * otherwise it returns 0. If a command is not in the following list,
+ * and the protocol version is 2 or less, then ALOM will not generate
+ * a response to the command. This causes the driver to time out,
+ * and we want to avoid that situation.
+ */
+static int
+rsc_cmd_response_guaranteed(rsci8 type)
+{
+ switch (type) {
+ case DP_GET_ALARM_STATE:
+ case DP_GET_CFGVAR:
+ case DP_GET_CFGVAR_NAME:
+ case DP_GET_CIRCUIT_BRKS:
+ case DP_GET_DATE_TIME:
+ case DP_GET_DEVICE:
+ case DP_GET_EVENT_LOG:
+ case DP_GET_FAN_STATUS:
+ case DP_GET_FRU_STATUS:
+ case DP_GET_HANDLE:
+ case DP_GET_HANDLE_NAME:
+ case DP_GET_LED_STATE:
+ case DP_GET_NETWORK_CFG:
+ case DP_GET_PCMCIA_INFO:
+ case DP_GET_PSU_STATUS:
+ case DP_GET_SDP_VERSION:
+ case DP_GET_SYSINFO:
+ case DP_GET_TEMP:
+ case DP_GET_TEMPERATURES:
+ case DP_GET_TICKCNT:
+ case DP_GET_TOD_CLOCK:
+ case DP_GET_USER_WATCHDOG:
+ case DP_GET_VOLTS:
+ case DP_MODEM_CONNECT:
+ case DP_MODEM_DATA:
+ case DP_MODEM_DISCONNECT:
+ case DP_RESET_RSC:
+ case DP_RMC_EVENTS:
+ case DP_RSC_STATUS:
+ case DP_RUN_TEST:
+ case DP_SEND_ALERT:
+ case DP_SET_ALARM_STATE:
+ case DP_SET_CFGVAR:
+ case DP_SET_CPU_SIGNATURE:
+ case DP_SET_DATE_TIME:
+ case DP_SET_DEFAULT_CFG:
+ case DP_SET_HOST_WATCHDOG:
+ case DP_SET_LED_STATE:
+ case DP_SET_USER_WATCHDOG:
+ case DP_UPDATE_FLASH:
+ case DP_USER_ADM:
+ return (1);
+ default:
+ return (sdp_version >= SDP_RESPONDS_TO_ALL_CMDS);
+ }
+}
+
+/*
+ * RSC hard reset. Returns 0 on success, non-zero on error.
+ */
+int
+rsc_nmi(void)
+{
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ if (ioctl(rsc_fd, RMCADM_RESET_SP, NULL) < 0)
+ return (errno);
+
+ return (0);
+}
+
+/*
+ * functions used (exclusively) for the firmware download
+ */
+
+/*
+ * Call this routine to register a callback that will be called by the
+ * generic data protocol routines when a boot protocol message is
+ * received. Only one of these routines may be registered at a time.
+ * Note that receiving a boot protocol message has the effect of
+ * re-initializing the data protocol. Returns 0 on success, or non-
+ * zero on failure.
+ */
+int
+rscp_register_bpmsg_cb(rscp_bpmsg_cb_t *cb)
+{
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ if (bpmsg_cb == NULL) {
+ bpmsg_cb = cb;
+ return (0);
+ } else {
+ return (EALREADY);
+ }
+}
+
+/*
+ * This routine un-registers a boot protocol message callback.
+ */
+int
+rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t *cb)
+{
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ if (bpmsg_cb == cb) {
+ bpmsg_cb = NULL;
+ return (0);
+ } else {
+ return (EINPROGRESS);
+ }
+}
+
+/*
+ * Call this routine to send a boot protocol message.
+ */
+void
+rscp_send_bpmsg(bp_msg_t *bpmsg)
+{
+ rmcadm_request_response_t rr_bp;
+ rmcadm_msg_t *req_bp = &rr_bp.req;
+ rmcadm_msg_t *resp_bp = &rr_bp.resp;
+ req_resp_table_t *rr_bp_item;
+ bp_msg_t bpmsg_reply;
+
+ if (rsc_fd < 0 || bpmsg == NULL)
+ return;
+
+ /*
+ * get the timeout value
+ */
+ if ((rr_bp_item = rsc_lookup_rr_table(rr_bp_table, rr_bp_table_cnt,
+ bpmsg->cmd)) != NULL) {
+
+ rr_bp.wait_time = rr_bp_item->timeout;
+
+ } else {
+
+ rr_bp.wait_time = RR_BP_TIMEOUT;
+ }
+
+ rr_bp.status = 0;
+
+ req_bp->msg_len = sizeof (bp_msg_t);
+ req_bp->msg_buf = (caddr_t)bpmsg;
+
+ if (rr_bp.wait_time == 0) {
+ resp_bp->msg_buf = (caddr_t)NULL;
+ } else {
+ resp_bp->msg_len = sizeof (bp_msg_t);
+ resp_bp->msg_buf = (caddr_t)&bpmsg_reply;
+ }
+
+#ifdef DEBUG
+ printf("send BP cmd %x, expect reply %x/%d\n",
+ bpmsg->cmd, resp_bp->msg_buf, resp_bp->msg_len);
+#endif
+ if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE_BP, &rr_bp) < 0) {
+#ifdef DEBUG
+ printf("rscp_send_bpmsg: BP cmd %x failed status=%d "
+ "errno=%d\n", bpmsg->cmd, rr_bp.status, errno);
+#endif
+ return;
+ }
+
+#ifdef DEBUG
+ printf("got BP reply type=%x,%x,%x\n",
+ bpmsg_reply.cmd, bpmsg_reply.dat1, bpmsg_reply.dat2);
+#endif
+
+ /*
+ * reply received. call the registered callback (if any)
+ */
+ if (bpmsg_cb != NULL && resp_bp->msg_buf != NULL)
+ bpmsg_cb(&bpmsg_reply);
+}
+
+/*
+ * Write raw characters to the RSC control device. Returns 0 on success,
+ * non-zero on error.
+ */
+int
+rsc_raw_write(char *buf, int nbytes)
+{
+ rmcadm_send_srecord_bp_t srec_bp;
+ bp_msg_t bpmsg_reply;
+
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ srec_bp.data_len = (uint_t)nbytes;
+ srec_bp.data_buf = (caddr_t)buf;
+ srec_bp.resp_bp.msg_len = sizeof (bp_msg_t);
+ srec_bp.resp_bp.msg_buf = (caddr_t)&bpmsg_reply;
+ srec_bp.wait_time = RR_BOOT_LOAD_TIMEOUT;
+ srec_bp.status = 0;
+
+#ifdef DEBUG
+ printf("send srecord BP len=%d\n", nbytes);
+#endif
+ if (ioctl(rsc_fd, RMCADM_SEND_SRECORD_BP, &srec_bp) < 0) {
+#ifdef DEBUG
+ printf("rsc_raw_write: failed. status=%d ioctl error=%d\n",
+ srec_bp.status, errno);
+#endif
+ return (errno);
+ }
+
+#ifdef DEBUG
+ printf("got BP reply type=%x\n", bpmsg_reply.cmd);
+#endif
+
+ /*
+ * reply received. call the registered callback (if any)
+ */
+ if (bpmsg_cb != NULL)
+ bpmsg_cb(&bpmsg_reply);
+
+ return (0);
+}
+
+/*
+ * obsolete functions provided for backward compatibility
+ */
+
+/*
+ * This function is obsolete and it is provided for backward compatibility.
+ * (no-op function). It was used to start up the data protocol. low-level
+ * protocol has moved to the kernel and the rmc_comm driver is responsible
+ * for setting up the data protocol.
+ * (obsolete)
+ */
+int
+rscp_start(void)
+{
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ return (0);
+}
+
+/*
+ * This function is obsolete and it is provided for backward compatibility.
+ * Previously, rscp_send() and rscp_recv() where used to send a request and
+ * read a reply respectively. Now, rscp_send_recv() should be used instead
+ * (request/response in one call).
+ *
+ * This is used to send a message by making an RMCADM_REQUEST_RESPONSE ioctl
+ * call. A lookup table (rr_table) is used to find out the expected reply
+ * (if any) and the timeout value for a message to be sent. The reply is then
+ * stored in a buffer (rsc_rx_buffer) to be returned by calling rscp_recv()
+ */
+int
+rscp_send(rscp_msg_t *msgp)
+{
+ rmcadm_request_response_t rr;
+ rmcadm_msg_t *req = &rr.req;
+ rmcadm_msg_t *resp = &rr.resp;
+ req_resp_table_t *rr_item;
+
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ /*
+ * sanity check
+ */
+ if (msgp == NULL)
+ return (EINVAL);
+
+ /*
+ * Check if the command is actually supported
+ * if not, return an error
+ */
+ if (rsc_check_unsupported_cmd(msgp->type) != 0)
+ return (ENOTSUP);
+
+ /*
+ * Check if this command will generate a response and if it will not,
+ * return an error.
+ */
+ if (!rsc_cmd_response_guaranteed(msgp->type))
+ return (ENOTSUP);
+
+ /*
+ * init rx buffer
+ */
+ rsc_rx_resp_len = 0;
+ rsc_rx_error = 0;
+
+ req->msg_type = msgp->type;
+ req->msg_len = msgp->len;
+ req->msg_buf = msgp->data;
+
+ if ((rr_item = rsc_lookup_rr_table(rr_table, rr_table_cnt,
+ msgp->type)) != NULL) {
+ resp->msg_type = rr_item->resp_type;
+ if (rr_item->resp_type == DP_NULL_MSG) {
+ /*
+ * no reply expected. so, no reply buffer needed
+ * (set to NULL)
+ */
+ resp->msg_len = 0;
+ resp->msg_buf = (caddr_t)NULL;
+ } else {
+ resp->msg_len = RSC_MAX_RX_BUFFER;
+ resp->msg_buf = (caddr_t)rsc_rx_buffer;
+ }
+
+ rr.wait_time = rr_item->timeout;
+ rsc_rx_resp_type = rr_item->resp_type;
+ } else {
+ return (ENOTSUP);
+ }
+ rr.status = 0;
+
+#ifdef DEBUG
+ printf("request/response %x/%x\n", req->msg_type, resp->msg_type);
+#endif
+ if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
+#ifdef DEBUG
+ printf("rscp_send: req %x failed, status=%d errno=%d\n",
+ rr.req.msg_type, rr.status, errno);
+#endif
+ rsc_rx_error = errno;
+
+ return (errno);
+ }
+
+ /*
+ * reply received. get the number of bytes effectively returned
+ */
+ rsc_rx_resp_len = resp->msg_bytes;
+ rsc_rx_resp_type = resp->msg_type;
+
+#ifdef DEBUG
+ printf("got reply type=%x len=%d\n", rsc_rx_resp_type, rsc_rx_resp_len);
+#endif
+
+ return (0);
+}
+
+/*
+ * This function is obsolete and it is provided for backward compatibility
+ * Previously, rscp_send() and rscp_recv() where used to send a request and
+ * read a reply repectively. Now, rscp_send_recv() should be used instead
+ * (request/response in one call).
+ *
+ * This function returns the reply received when a request was previously sent
+ * using the rscp_send() function (stored in the rsc_rx_buffer buffer). If a
+ * reply was not received, then an error is returned.
+ *
+ * timeout parameter is declared for backward compatibility but it is not used.
+ */
+/*ARGSUSED*/
+int
+rscp_recv(rscp_msg_t *msgp, struct timespec *timeout)
+{
+ int err = 0;
+
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ /*
+ * sanity check
+ */
+ if (msgp == NULL)
+ return (EINVAL);
+
+ if (rsc_rx_error < 0) {
+ msgp->type = DP_NULL_MSG;
+ msgp->len = 0;
+ msgp->data = NULL;
+
+ err = rsc_rx_error;
+
+ } else {
+ msgp->type = rsc_rx_resp_type;
+ msgp->len = rsc_rx_resp_len;
+ msgp->data = rsc_rx_buffer;
+ }
+
+#ifdef DEBUG
+ printf("read reply. type=%x, err=%d\n", msgp->type, err);
+#endif
+
+ rsc_rx_resp_len = 0;
+ rsc_rx_error = 0;
+ rsc_rx_resp_type = DP_NULL_MSG;
+
+ return (err);
+}
+
+/*
+ * used to free up a (received) message. no-op function
+ */
+/*ARGSUSED*/
+int
+rscp_free_msg(rscp_msg_t *msgp)
+{
+ if (rsc_fd < 0)
+ return (EBADF);
+
+ return (0);
+}
diff --git a/usr/src/lib/librsc/sparc/mpxu/common/librsc.h b/usr/src/lib/librsc/sparc/mpxu/common/librsc.h
new file mode 100644
index 0000000000..05b92f62c9
--- /dev/null
+++ b/usr/src/lib/librsc/sparc/mpxu/common/librsc.h
@@ -0,0 +1,118 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBRSC_H
+#define _LIBRSC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/rmc_comm_lproto.h>
+#include <sys/rmc_comm_hproto.h>
+#include <sys/rmc_comm_dp_boot.h>
+#include <sys/rmcadm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The structure used to pass messages into and out of this layer.
+ */
+typedef struct rscp_msg {
+ rsci8 type;
+ rsci32 len;
+ void *data;
+ void *private;
+} rscp_msg_t;
+
+typedef void rscp_bpmsg_cb_t(bp_msg_t *msg);
+
+#define RSC_RMCADM_DRV "/devices/pseudo/rmcadm@0:rmcadm"
+
+#define RSC_MAX_RX_BUFFER DP_MAX_MSGLEN
+
+
+/*
+ * this table is used to match request/response in order to provide
+ * backward compatibility to obsolete functions: rscp_send(), rscp_recv(),
+ *
+ * in the old way, send and receive were decoupled: applications sent a
+ * request (rscp_send) and waited for a reply (rscp_recv) using two different
+ * calls.
+ * As the ioctl to the communication driver is a single call, send and receive
+ * cannot be decoupled. So, when the rscp_send is called, this table will tell
+ * which reply is expected and in what time. The reply is then stored in a
+ * temporary buffer. When the rscp_recv is called, it will return the
+ * content of the temporary buffer (if a reply was received) or an error
+ */
+typedef struct req_resp_table {
+
+ uint8_t req_type;
+ uint8_t resp_type;
+ uint16_t resp_size;
+ uint_t timeout;
+
+} req_resp_table_t;
+
+
+/* timeout value (millisecs) for request/response sessions */
+
+#define RR_TIMEOUT 10000
+#define RR_SEPROM_TIMEOUT 10000
+
+#define RR_BOOT_INIT_TIMEOUT 1000
+#define RR_BOOT_LOAD_TIMEOUT 10000
+#define RR_BOOT_RESET_TIMEOUT 0
+#define RR_BP_TIMEOUT 1000
+
+
+/* function prototypes */
+
+int rscp_init(void);
+int rscp_send_recv(rscp_msg_t *, rscp_msg_t *, struct timespec *);
+int rsc_nmi(void);
+
+
+/* function prototypes for firmware download */
+
+int rscp_register_bpmsg_cb(rscp_bpmsg_cb_t *);
+int rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t *);
+void rscp_send_bpmsg(bp_msg_t *);
+int rsc_raw_write(char *, int);
+
+
+/* prototypes of obsolete functions */
+
+int rscp_send(rscp_msg_t *);
+int rscp_recv(rscp_msg_t *, struct timespec *);
+int rscp_start(void);
+int rscp_free_msg(rscp_msg_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBRSC_H */