summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorrobj <none@none>2008-02-22 15:04:09 -0800
committerrobj <none@none>2008-02-22 15:04:09 -0800
commit2eeaed14a5e2ed9bd811643ad5bffc3510ca0310 (patch)
treec67130267b295fc81a2bfe2dbc26ce790c5c3bed /usr/src
parent387214a609155b1c9d15e8e68043b80bd549b92b (diff)
downloadillumos-joyent-2eeaed14a5e2ed9bd811643ad5bffc3510ca0310.tar.gz
PSARC 2008/091 Libtopo enumeration of fans and power supplies via IPMI
6614956 libimpi: add interfaces for accessing/decoding full and compact sensor data records 6641742 IPMI based libtopo enumeration of power supplies and fans 6643681 libtopo: need mechanism to register module methods on statically enumerated nodes 6653942 ::fmtopo prints garbage when dumping prop methods 6654386 libtopo: hc_enum double-populates authority pgroup on non-root nodes 6659015 ::topo_module dcmd can sigsegv 6661750 libtopo: need generic method to restrict both range/propgroup defs to specific platform in topo maps 6666459 libipmi: ILOM check could be more strict 6666469 libipmi should support reading SEL records 6666479 libipmi: need interface to get SP firmware version
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fm/Makefile8
-rw-r--r--usr/src/cmd/fm/ipmitopo/Makefile29
-rw-r--r--usr/src/cmd/fm/ipmitopo/Makefile.com83
-rw-r--r--usr/src/cmd/fm/ipmitopo/common/ipmitopo.c147
-rw-r--r--usr/src/cmd/fm/ipmitopo/i386/Makefile28
-rw-r--r--usr/src/cmd/fm/ipmitopo/sparc/Makefile28
-rw-r--r--usr/src/cmd/mdb/common/modules/libtopo/libtopo.c19
-rw-r--r--usr/src/lib/Makefile5
-rw-r--r--usr/src/lib/fm/topo/libtopo/Makefile.com4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/hc.c18
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/mapfile-vers3
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_hc.h6
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.c18
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_mod.h4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_parse.h4
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_prop.c35
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_snap.c13
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_tree.h5
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/topo_xml.c217
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen110
-rw-r--r--usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen114
-rw-r--r--usr/src/lib/fm/topo/maps/common/topology.dtd.127
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/Makefile9
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml54
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/fan-hc-topology.xmlgen269
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml47
-rw-r--r--usr/src/lib/fm/topo/maps/i86pc/psu-hc-topology.xml87
-rw-r--r--usr/src/lib/fm/topo/modules/common/Makefile7
-rw-r--r--usr/src/lib/fm/topo/modules/common/ipmi/Makefile34
-rw-r--r--usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c471
-rw-r--r--usr/src/lib/fm/topo/modules/common/ipmi/ipmi_methods.c208
-rw-r--r--usr/src/lib/libipmi/Makefile.com10
-rw-r--r--usr/src/lib/libipmi/common/ipmi_entity.c754
-rw-r--r--usr/src/lib/libipmi/common/ipmi_fru.c136
-rw-r--r--usr/src/lib/libipmi/common/ipmi_hash.c298
-rw-r--r--usr/src/lib/libipmi/common/ipmi_impl.h111
-rw-r--r--usr/src/lib/libipmi/common/ipmi_list.c128
-rw-r--r--usr/src/lib/libipmi/common/ipmi_misc.c74
-rw-r--r--usr/src/lib/libipmi/common/ipmi_sdr.c386
-rw-r--r--usr/src/lib/libipmi/common/ipmi_sel.c196
-rw-r--r--usr/src/lib/libipmi/common/ipmi_sunoem.c11
-rw-r--r--usr/src/lib/libipmi/common/ipmi_user.c32
-rw-r--r--usr/src/lib/libipmi/common/ipmi_util.c205
-rw-r--r--usr/src/lib/libipmi/common/libipmi.c16
-rw-r--r--usr/src/lib/libipmi/common/libipmi.h1224
-rw-r--r--usr/src/lib/libipmi/common/mapfile-vers26
-rw-r--r--usr/src/lib/libipmi/common/mktables.sh109
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_com4
-rw-r--r--usr/src/pkgdefs/SUNWfmd/prototype_i3864
49 files changed, 5288 insertions, 547 deletions
diff --git a/usr/src/cmd/fm/Makefile b/usr/src/cmd/fm/Makefile
index e4861dd8ed..58e8be48fe 100644
--- a/usr/src/cmd/fm/Makefile
+++ b/usr/src/cmd/fm/Makefile
@@ -2,9 +2,8 @@
# 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.
+# 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.
@@ -20,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -32,6 +31,7 @@ SUBDIRS = \
fminject \
fmstat \
fmtopo \
+ ipmitopo \
schemes \
scripts \
modules \
diff --git a/usr/src/cmd/fm/ipmitopo/Makefile b/usr/src/cmd/fm/ipmitopo/Makefile
new file mode 100644
index 0000000000..d53cbbfdbf
--- /dev/null
+++ b/usr/src/cmd/fm/ipmitopo/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+SUBDIRS = $(MACH)
+
+include ../Makefile.subdirs
diff --git a/usr/src/cmd/fm/ipmitopo/Makefile.com b/usr/src/cmd/fm/ipmitopo/Makefile.com
new file mode 100644
index 0000000000..068ce92355
--- /dev/null
+++ b/usr/src/cmd/fm/ipmitopo/Makefile.com
@@ -0,0 +1,83 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+.KEEP_STATE:
+.SUFFIXES:
+
+SRCS += ipmitopo.c
+OBJS = $(SRCS:%.c=%.o)
+LINTFILES = $(SRCS:%.c=%.ln)
+
+PROG = ipmitopo
+ROOTLIBFM = $(ROOT)/usr/lib/fm
+ROOTLIBFMD = $(ROOT)/usr/lib/fm/fmd
+ROOTPROG = $(ROOTLIBFMD)/$(PROG)
+
+$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
+CPPFLAGS += -I. -I../common
+CFLAGS += $(CTF_FLAGS) $(CCVERBOSE) $(XSTRCONST)
+LDLIBS += -lipmi
+LINTFLAGS += -mnu
+
+.NO_PARALLEL:
+.PARALLEL: $(OBJS) $(LINTFILES)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(CTFMERGE) -L VERSION -o $@ $(OBJS)
+ $(POST_PROCESS)
+
+%.o: ../common/%.c
+ $(COMPILE.c) $<
+ $(CTFCONVERT_O)
+
+%.o: %.c
+ $(COMPILE.c) $<
+ $(CTFCONVERT_O)
+
+clean:
+ $(RM) $(OBJS) $(LINTFILES)
+
+clobber: clean
+ $(RM) $(PROG)
+
+%.ln: ../common/%.c
+ $(LINT.c) -c $<
+
+%.ln: %.c
+ $(LINT.c) -c $<
+
+lint: $(LINTFILES)
+ $(LINT) $(LINTFLAGS) $(LINTFILES)
+
+$(ROOTLIBFMD)/%: %
+ $(INS.file)
+
+install_h:
+
+install: all $(ROOTPROG)
diff --git a/usr/src/cmd/fm/ipmitopo/common/ipmitopo.c b/usr/src/cmd/fm/ipmitopo/common/ipmitopo.c
new file mode 100644
index 0000000000..4ab3d6853b
--- /dev/null
+++ b/usr/src/cmd/fm/ipmitopo/common/ipmitopo.c
@@ -0,0 +1,147 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libipmi.h>
+#include <stdio.h>
+#include <string.h>
+
+/*ARGSUSED*/
+static int
+sdr_print(ipmi_handle_t *ihp, ipmi_entity_t *ep, const char *name,
+ ipmi_sdr_t *sdrp, void *data)
+{
+ int indentation = (uintptr_t)data;
+ ipmi_sdr_compact_sensor_t *csp;
+ ipmi_sdr_full_sensor_t *fsp;
+ uint8_t sensor_number, sensor_type, reading_type;
+ boolean_t get_reading = B_FALSE;
+ ipmi_sensor_reading_t *srp;
+ char sensor_name[128];
+ char reading_name[128];
+
+ if (name == NULL)
+ return (0);
+
+ switch (sdrp->is_type) {
+ case IPMI_SDR_TYPE_COMPACT_SENSOR:
+ csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record;
+ sensor_number = csp->is_cs_number;
+ sensor_type = csp->is_cs_type;
+ reading_type = csp->is_cs_reading_type;
+ get_reading = B_TRUE;
+ break;
+
+ case IPMI_SDR_TYPE_FULL_SENSOR:
+ fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record;
+ sensor_number = fsp->is_fs_number;
+ sensor_type = fsp->is_fs_type;
+ reading_type = fsp->is_fs_reading_type;
+ get_reading = B_TRUE;
+ break;
+ }
+
+ (void) printf("%*s%-*s", indentation, "",
+ 36 - indentation, name);
+
+ if (get_reading) {
+ ipmi_sensor_type_name(sensor_type, sensor_name,
+ sizeof (sensor_name));
+ ipmi_sensor_reading_name(sensor_type, reading_type,
+ reading_name, sizeof (reading_name));
+ (void) printf("%12s %12s", sensor_name, reading_name);
+ if ((srp = ipmi_get_sensor_reading(ihp,
+ sensor_number)) == NULL) {
+ if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) {
+ (void) printf(" -\n");
+ } else {
+ (void) printf("\n");
+ return (-1);
+ }
+ } else {
+ (void) printf(" %04x\n", srp->isr_state);
+ }
+ } else {
+ (void) printf("\n");
+ }
+
+ return (0);
+}
+
+static int
+entity_print(ipmi_handle_t *ihp, ipmi_entity_t *ep, void *data)
+{
+ int indentation = (uintptr_t)data;
+ char name[128];
+ boolean_t present;
+
+ ipmi_entity_name(ep->ie_type, name, sizeof (name));
+ (void) snprintf(name + strlen(name), sizeof (name) - strlen(name),
+ " %d", ep->ie_instance);
+
+ if (ipmi_entity_present(ihp, ep, &present) != 0) {
+ (void) printf("%*s%-*s %s (%s)\n", indentation, "",
+ 24 - indentation, name, "unknown", ipmi_errmsg(ihp));
+ } else {
+ (void) printf("%*s%-*s %s\n", indentation, "",
+ 24 - indentation, name, present ? "present" : "absent");
+ }
+ ipmi_entity_iter_sdr(ihp, ep, sdr_print, (void *)(indentation + 2));
+
+ if (ep->ie_children != 0)
+ (void) ipmi_entity_iter_children(ihp, ep, entity_print,
+ (void *)(indentation + 2));
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+main(int argc, char **argv)
+{
+ ipmi_handle_t *ihp;
+ char *errmsg;
+ int err;
+
+ if ((ihp = ipmi_open(&err, &errmsg)) == NULL) {
+ (void) fprintf(stderr, "failed to open libipmi: %s\n",
+ errmsg);
+ return (1);
+ }
+
+ (void) printf("%-24s %-8s %12s %12s %5s\n",
+ "ENTITY/SENSOR", "PRESENT", "SENSOR", "READING", "STATE");
+ (void) printf("----------------------- -------- ------------- "
+ "------------ -----\n");
+ if (ipmi_entity_iter(ihp, entity_print, NULL) != 0) {
+ (void) fprintf(stderr, "failed to iterate entities: %s\n",
+ ipmi_errmsg(ihp));
+ return (1);
+ }
+
+ ipmi_close(ihp);
+
+ return (0);
+}
diff --git a/usr/src/cmd/fm/ipmitopo/i386/Makefile b/usr/src/cmd/fm/ipmitopo/i386/Makefile
new file mode 100644
index 0000000000..16356f9dd8
--- /dev/null
+++ b/usr/src/cmd/fm/ipmitopo/i386/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+include ../../../Makefile.cmd
+include ../Makefile.com
diff --git a/usr/src/cmd/fm/ipmitopo/sparc/Makefile b/usr/src/cmd/fm/ipmitopo/sparc/Makefile
new file mode 100644
index 0000000000..16356f9dd8
--- /dev/null
+++ b/usr/src/cmd/fm/ipmitopo/sparc/Makefile
@@ -0,0 +1,28 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+include ../../../Makefile.cmd
+include ../Makefile.com
diff --git a/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c b/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c
index efb6154c85..362f222197 100644
--- a/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c
+++ b/usr/src/cmd/mdb/common/modules/libtopo/libtopo.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -187,8 +187,13 @@ topo_module(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
mdb_printf("%-12s 0x%-34p %-30s\n", "tm_cv",
addr + offsetof(topo_mod_t, tm_cv),
"Module condition variable");
- mdb_printf("%-12s %-36s %-30s\n", "tm_busy", tm.tm_busy,
- "Busy indicator");
+ if (tm.tm_busy)
+ mdb_printf("%-12s %-36s %-30s\n", "tm_busy", "TRUE",
+ "Busy indicator");
+ else
+ mdb_printf("%-12s %-36s %-30s\n", "tm_busy", "FALSE",
+ "Busy indicator");
+
mdb_printf("%-12s 0x%-34p %-30s\n", "tm_next", tm.tm_next,
"Next module in hash chain");
mdb_printf("%-12s 0x%-34p %-30s\n", "tm_hdl", tm.tm_hdl,
@@ -339,14 +344,18 @@ static void
dump_propmethod(uintptr_t addr)
{
topo_propmethod_t pm;
+ char mname[32];
if (mdb_vread(&pm, sizeof (pm), addr) != sizeof (pm)) {
mdb_warn("failed to read topo_propmethod at %p", addr);
return;
}
+ if (mdb_readstr(mname, sizeof (mname), (uintptr_t)pm.tpm_name) < 0) {
+ (void) mdb_snprintf(mname, sizeof (mname), "<%p>", pm.tpm_name);
+ }
- mdb_printf(" method: %-32s version: %-16s args: %p\n",
- pm.tpm_name, pm.tpm_version, pm.tpm_args);
+ mdb_printf(" method: %-32s version: %-16d args: %p\n",
+ mname, pm.tpm_version, pm.tpm_args);
}
/*
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index d601981471..f7acd48612 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -256,7 +256,10 @@ sparc_SUBDIRS= .WAIT \
FM_sparc_DEPLIBS= libpri
-fm: libexacct $(FM_$(MACH)_DEPLIBS)
+fm: \
+ libexacct \
+ libipmi \
+ $(FM_$(MACH)_DEPLIBS)
#
# Create a special version of $(SUBDIRS) with no .WAIT's, for use with the
diff --git a/usr/src/lib/fm/topo/libtopo/Makefile.com b/usr/src/lib/fm/topo/libtopo/Makefile.com
index d9d09adf4b..295f33d885 100644
--- a/usr/src/lib/fm/topo/libtopo/Makefile.com
+++ b/usr/src/lib/fm/topo/libtopo/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -81,7 +81,7 @@ LINTFLAGS64 = -msux -Xarch=$(MACH64:sparcv9=v9)
$(DYNLIB) := LDLIBS += \
-lnvpair -lelf -lumem -lxml2 -lkstat -luuid -ldevinfo \
- -lsmbios -lc -ldevid
+ -lsmbios -lc -ldevid -lipmi
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
$(LINTLIB) := LINTFLAGS = -nsvx
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c
index ca7e067880..21a3637d81 100644
--- a/usr/src/lib/fm/topo/libtopo/common/hc.c
+++ b/usr/src/lib/fm/topo/libtopo/common/hc.c
@@ -21,7 +21,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -118,6 +118,8 @@ static const hcc_t hc_canon[] = {
{ DIMM, TOPO_STABILITY_PRIVATE },
{ DISK, TOPO_STABILITY_PRIVATE },
{ DRAMCHANNEL, TOPO_STABILITY_PRIVATE },
+ { FAN, TOPO_STABILITY_PRIVATE },
+ { FANMODULE, TOPO_STABILITY_PRIVATE },
{ HOSTBRIDGE, TOPO_STABILITY_PRIVATE },
{ INTERCONNECT, TOPO_STABILITY_PRIVATE },
{ IOBOARD, TOPO_STABILITY_PRIVATE },
@@ -135,6 +137,8 @@ static const hcc_t hc_canon[] = {
{ PCIEX_ROOT, TOPO_STABILITY_PRIVATE },
{ PCIEX_SWUP, TOPO_STABILITY_PRIVATE },
{ PCIEX_SWDWN, TOPO_STABILITY_PRIVATE },
+ { POWERMODULE, TOPO_STABILITY_PRIVATE },
+ { PSU, TOPO_STABILITY_PRIVATE },
{ RANK, TOPO_STABILITY_PRIVATE },
{ SYSTEMBOARD, TOPO_STABILITY_PRIVATE },
{ XAUI, TOPO_STABILITY_PRIVATE },
@@ -206,23 +210,23 @@ hc_prop_set(tnode_t *node, nvlist_t *auth)
/*
* Inherit if we can, it saves memory
*/
- if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT,
- &err) != 0) {
+ if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT,
+ &err) != 0) && (err != ETOPO_PROP_DEFD)) {
if (nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, &prod)
== 0)
(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod,
&err);
}
- if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS,
- &err) != 0) {
+ if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS,
+ &err) != 0) && (err != ETOPO_PROP_DEFD)) {
if (nvlist_lookup_string(auth, FM_FMRI_AUTH_CHASSIS, &csn) == 0)
(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
FM_FMRI_AUTH_CHASSIS, TOPO_PROP_IMMUTABLE, csn,
&err);
}
- if (topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER,
- &err) != 0) {
+ if ((topo_prop_inherit(node, FM_FMRI_AUTHORITY, FM_FMRI_AUTH_SERVER,
+ &err) != 0) && (err != ETOPO_PROP_DEFD)) {
if (nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, &server)
== 0)
(void) topo_prop_set_string(node, FM_FMRI_AUTHORITY,
diff --git a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
index b0319e18cc..f488b2c0cf 100644
--- a/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
+++ b/usr/src/lib/fm/topo/libtopo/common/mapfile-vers
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -72,6 +72,7 @@ SUNWprivate {
topo_mod_free;
topo_mod_getspecific;
topo_mod_hcfmri;
+ topo_mod_ipmi;
topo_mod_load;
topo_mod_memfmri;
topo_mod_modfmri;
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
index 7f31359d9a..83eeb991e8 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -48,6 +48,8 @@ extern "C" {
#define DIMM "dimm"
#define DISK "disk"
#define DRAMCHANNEL "dram-channel"
+#define FAN "fan"
+#define FANMODULE "fanmodule"
#define HOSTBRIDGE "hostbridge"
#define INTERCONNECT "interconnect"
#define IOBOARD "ioboard"
@@ -65,6 +67,8 @@ extern "C" {
#define PCIEX_ROOT "pciexrc"
#define PCIEX_SWUP "pciexswu"
#define PCIEX_SWDWN "pciexswd"
+#define POWERMODULE "powermodule"
+#define PSU "psu"
#define RANK "rank"
#define SYSTEMBOARD "systemboard"
#define XAUI "xaui"
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
index b46f9c9b11..4140fc0ed2 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -600,6 +600,22 @@ topo_mod_devinfo(topo_mod_t *mod)
return (thp->th_di);
}
+ipmi_handle_t *
+topo_mod_ipmi(topo_mod_t *mod)
+{
+ topo_hdl_t *thp = mod->tm_hdl;
+ int err;
+ char *errmsg;
+
+ if (thp->th_ipmi == NULL)
+ if ((thp->th_ipmi = ipmi_open(&err, &errmsg)) == NULL)
+ topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR,
+ "ipmi_open() failed: %s (ipmi errno=%d)", errmsg,
+ err);
+
+ return (thp->th_ipmi);
+}
+
di_prom_handle_t
topo_mod_prominfo(topo_mod_t *mod)
{
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
index d3f46d1b51..fdcdb2fd34 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_mod.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,6 +31,7 @@
#include <fm/libtopo.h>
#include <fm/topo_hc.h>
+#include <libipmi.h>
#include <libnvpair.h>
#include <libdevinfo.h>
@@ -115,6 +116,7 @@ extern void topo_method_unregister(topo_mod_t *, tnode_t *, const char *);
extern void topo_method_unregister_all(topo_mod_t *, tnode_t *);
extern di_node_t topo_mod_devinfo(topo_mod_t *);
+extern ipmi_handle_t *topo_mod_ipmi(topo_mod_t *);
extern di_prom_handle_t topo_mod_prominfo(topo_mod_t *);
extern nvlist_t *topo_mod_auth(topo_mod_t *, tnode_t *);
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_parse.h b/usr/src/lib/fm/topo/libtopo/common/topo_parse.h
index fdd0a08492..f60bf6ec21 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_parse.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_parse.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -148,6 +148,7 @@ typedef struct tf_info {
#define Range "range"
#define Scheme "scheme"
#define Set "set"
+#define Setlist "setlist"
#define Siblings "siblings"
#define Static "static"
#define String "string"
@@ -165,7 +166,6 @@ typedef struct tf_info {
#define Prop_meth "propmethod"
#define Propgrp "propgroup"
#define Propval "propval"
-#define Propset "propset"
#define Propmap "propmap"
#define Node "node"
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_prop.c b/usr/src/lib/fm/topo/libtopo/common/topo_prop.c
index 3473a7372a..7b9a005c1a 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_prop.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_prop.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -872,17 +872,27 @@ prop_method_register(tnode_t *node, const char *pgname, const char *pname,
return (register_methoderror(node, pm, err, 1,
ETOPO_PROP_NOMEM));
- if ((pv = prop_create(node, pgname, pname, ptype, TOPO_PROP_MUTABLE,
- err)) == NULL) {
- /* node unlocked */
- return (register_methoderror(node, pm, err, 0, *err));
- }
+ /*
+ * It's possible the property may already exist. However we still want
+ * to allow the method to be registered. This is to handle the case
+ * where we specify an prop method in an xml map to override the value
+ * that was set by the enumerator.
+ */
+ if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL)
+ if ((pv = prop_create(node, pgname, pname, ptype,
+ TOPO_PROP_MUTABLE, err)) == NULL) {
+ /* node unlocked */
+ return (register_methoderror(node, pm, err, 0, *err));
+ }
if (pv->tp_method != NULL)
return (register_methoderror(node, pm, err, 1,
ETOPO_METHOD_DEFD));
- pv->tp_val = NULL;
+ if (pv->tp_val != NULL) {
+ nvlist_free(pv->tp_val);
+ pv->tp_val = NULL;
+ }
pv->tp_method = pm;
topo_node_unlock(node);
@@ -994,8 +1004,17 @@ topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err)
topo_node_lock(pnode);
topo_node_lock(node);
+
+ /*
+ * Check if the requested property group and prop val are already set
+ * on the node.
+ */
+ if (propval_get(pgroup_get(node, pgname), name) != NULL)
+ return (inherit_seterror(node, err, ETOPO_PROP_DEFD));
+
/*
- * Check for an existing property group and prop val
+ * Check if the requested property group and prop val exists on the
+ * parent node
*/
if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL)
return (inherit_seterror(node, err, ETOPO_PROP_NOENT));
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
index 957e73c041..c18b256194 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_snap.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -232,6 +232,8 @@ topo_close(topo_hdl_t *thp)
topo_hdl_strfree(thp, thp->th_product);
if (thp->th_rootdir != NULL)
topo_hdl_strfree(thp, thp->th_rootdir);
+ if (thp->th_ipmi != NULL)
+ ipmi_close(thp->th_ipmi);
/*
* Clean-up snapshot
@@ -295,6 +297,14 @@ topo_snap_create(topo_hdl_t *thp, int *errp)
}
}
+ if (thp->th_ipmi != NULL &&
+ ipmi_sdr_changed(thp->th_ipmi) &&
+ ipmi_sdr_refresh(thp->th_ipmi) != 0) {
+ topo_dprintf(thp, TOPO_DBG_ERR,
+ "failed to refresh IPMI sdr repository: %s\n",
+ ipmi_errmsg(thp->th_ipmi));
+ }
+
if ((ustr = topo_hdl_strdup(thp, thp->th_uuid)) == NULL)
*errp = ETOPO_NOMEM;
@@ -403,7 +413,6 @@ topo_snap_release(topo_hdl_t *thp)
topo_hdl_lock(thp);
topo_snap_destroy(thp);
topo_hdl_unlock(thp);
-
}
topo_walk_t *
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_tree.h b/usr/src/lib/fm/topo/libtopo/common/topo_tree.h
index 00620afa84..c3ef9b3ea2 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_tree.h
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_tree.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,6 +31,8 @@
#include <fm/topo_mod.h>
+#include <libipmi.h>
+
#include <topo_list.h>
#include <topo_prop.h>
#include <topo_method.h>
@@ -119,6 +121,7 @@ struct topo_hdl {
int th_errno; /* errno */
int th_debug; /* Debug mask */
int th_dbout; /* Debug channel */
+ ipmi_handle_t *th_ipmi; /* IPMI handle */
};
#define TOPO_UUID_SIZE 37 /* libuuid limit + 1 */
diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
index dd8f0d29d6..93faaf7e3d 100644
--- a/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
+++ b/usr/src/lib/fm/topo/libtopo/common/topo_xml.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -46,11 +46,13 @@
#include <topo_parse.h>
#include <topo_error.h>
-static tf_rdata_t *topo_xml_walk(topo_mod_t *,
- tf_info_t *, xmlNodePtr, tnode_t *);
+static tf_rdata_t *topo_xml_walk(topo_mod_t *, tf_info_t *, xmlNodePtr,
+ tnode_t *);
+static tf_edata_t *enum_attributes_process(topo_mod_t *, xmlNodePtr);
+static int enum_run(topo_mod_t *, tf_rdata_t *);
+static int decorate_nodes(topo_mod_t *, tf_rdata_t *, xmlNodePtr, tnode_t *,
+ tf_pad_t **);
-static int decorate_nodes(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn,
- tnode_t *ptn, char *name, tf_pad_t **rpad);
int
xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname,
@@ -577,8 +579,9 @@ register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth)
meth->arg_nvl, &err) != 0) {
topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register "
- "propmethod %s for property %s on node %s=%d (%s)\n",
- meth->meth_name, meth->prop_name,
+ "propmethod %s for property \"%s\" in propgrp %s on node "
+ "%s=%d (%s)\n",
+ meth->meth_name, meth->prop_name, meth->pg_name,
topo_node_name(ptn), topo_node_instance(ptn),
topo_strerror(err));
return (-1);
@@ -840,20 +843,20 @@ pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
}
/*
- * psn: pointer to a "propset" XML node
- * key: string to search the propset for
+ * psn: pointer to a "set" XML node
+ * key: string to search the set for
*
- * returns: 1, if the propset contains key
+ * returns: 1, if the set contains key
* 0, otherwise
*/
static int
-propset_contains(topo_mod_t *mp, char *key, char *set)
+set_contains(topo_mod_t *mp, char *key, char *set)
{
char *prod;
int rv = 0;
- topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "propset_contains(key = %s, "
- "set = %s)\n", key, set);
+ topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "set_contains(key = %s, "
+ "setlist = %s)\n", key, set);
prod = strtok((char *)set, "|");
if (prod && (strcmp(key, prod) == 0))
@@ -872,15 +875,17 @@ propset_contains(topo_mod_t *mp, char *key, char *set)
* parent xmlNode pxn.
*/
static int
-pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
- tf_pad_t **rpad, const char *rname)
+pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
+ tf_pad_t **rpad)
{
- xmlNodePtr cn, gcn, psn;
- xmlNodePtr def_propset = NULL;
+ xmlNodePtr cn, gcn, psn, ecn;
+ xmlNodePtr def_set = NULL;
tf_pad_t *new = *rpad;
+ tf_rdata_t tmp_rd;
int pgcnt = 0;
int dcnt = 0;
- int joined_propset = 0;
+ int ecnt = 0;
+ int joined_set = 0;
xmlChar *set;
char *key;
@@ -892,17 +897,25 @@ pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
"cn->name is %s \n", (char *)cn->name);
/*
* We're iterating through the XML children looking for
- * three types of elements:
+ * four types of elements:
* 1) dependents elements
* 2) unconstrained pgroup elements
- * 3) pgroup elements constrained by propset elements
+ * 3) pgroup elements constrained by set elements
+ * 4) enum-method elements for the case that we want
+ * to post-process a statically defined node
*/
if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0)
dcnt++;
else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0)
pgcnt++;
- else if (xmlStrcmp(cn->name, (xmlChar *)Propset) == 0) {
- set = xmlGetProp(cn, (xmlChar *)Set);
+ else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth)
+ == 0) {
+ ecn = cn;
+ ecnt++;
+ } else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) {
+ if (joined_set)
+ continue;
+ set = xmlGetProp(cn, (xmlChar *)Setlist);
if (mp->tm_hdl->th_product)
key = mp->tm_hdl->th_product;
@@ -910,17 +923,16 @@ pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
key = mp->tm_hdl->th_platform;
/*
- * If it's the default propset then we'll store
+ * If it's the default set then we'll store
* a pointer to it so that if none of the other
- * propsets apply to our product we can fall
+ * sets apply to our product we can fall
* back to this one.
*/
if (strcmp((char *)set, "default") == 0)
- def_propset = cn;
- else if (propset_contains(mp, key,
- (char *)set)) {
+ def_set = cn;
+ else if (set_contains(mp, key, (char *)set)) {
psn = cn;
- joined_propset = 1;
+ joined_set = 1;
for (gcn = cn->xmlChildrenNode;
gcn != NULL; gcn = gcn->next) {
if (xmlStrcmp(gcn->name,
@@ -932,14 +944,14 @@ pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
}
}
/*
- * If we haven't found a propset that contains our product AND
- * a default propset exists, then we'll process it.
+ * If we haven't found a set that contains our product AND
+ * a default set exists, then we'll process it.
*/
- if (!joined_propset && def_propset) {
+ if (!joined_set && def_set) {
topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
- "Falling back to default propset\n");
- joined_propset = 1;
- psn = def_propset;
+ "Falling back to default set\n");
+ joined_set = 1;
+ psn = def_set;
for (gcn = psn->xmlChildrenNode; gcn != NULL;
gcn = gcn->next) {
if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp)
@@ -948,8 +960,31 @@ pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
}
}
topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
- "pad_process: dcnt=%d, pgcnt=%d, joined_propset=%d\n",
- dcnt, pgcnt, joined_propset);
+ "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
+ dcnt, pgcnt, ecnt, joined_set);
+ /*
+ * If an enum-method element was found, AND we're a child of a
+ * node element, then we invoke the enumerator so that it can do
+ * post-processing of the node.
+ */
+ if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) {
+ if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn))
+ == NULL)
+ return (-1);
+ tmp_rd.rd_mod = mp;
+ tmp_rd.rd_name = rd->rd_name;
+ tmp_rd.rd_min = rd->rd_min;
+ tmp_rd.rd_max = rd->rd_max;
+ tmp_rd.rd_pn = ptn;
+ if (enum_run(mp, &tmp_rd) < 0) {
+ /*
+ * Note the failure but continue on
+ */
+ topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
+ "pad_process: enumeration failed.\n");
+ }
+ topo_mod_free(mp, tmp_rd.rd_einfo, sizeof (tf_edata_t));
+ }
/*
* Here we allocate an element in an intermediate data structure
* which keeps track property groups and dependents of the range
@@ -973,20 +1008,20 @@ pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
return (-1);
}
- if (joined_propset) {
+ if (joined_set) {
/*
* If the property groups are contained within a
- * propset then they will be one level lower in
+ * set then they will be one level lower in
* the XML tree.
*/
- if (pgroups_record(mp, psn, ptn, rname, new,
- (const char *)pxn->name) < 0) {
+ if (pgroups_record(mp, psn, ptn, rd->rd_name,
+ new, (const char *)pxn->name) < 0) {
tf_pad_free(mp, new);
return (-1);
}
} else {
- if (pgroups_record(mp, pxn, ptn, rname, new,
- (const char *)pxn->name) < 0) {
+ if (pgroups_record(mp, pxn, ptn, rd->rd_name,
+ new, (const char *)pxn->name) < 0) {
tf_pad_free(mp, new);
return (-1);
}
@@ -996,7 +1031,7 @@ pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
}
if (new->tpad_dcnt > 0)
- if (dependents_create(mp, xinfo, new, pxn, ptn) < 0)
+ if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
return (-1);
if (new->tpad_pgcnt > 0)
@@ -1006,6 +1041,7 @@ pad_process(topo_mod_t *mp, tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn,
return (0);
}
+
static int
node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
{
@@ -1037,6 +1073,7 @@ node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
goto nodedone;
}
ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst);
+
if (ntn == NULL) {
/*
@@ -1049,7 +1086,6 @@ node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
rv = 0;
goto nodedone;
}
-
if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) {
topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
"node_process: tf_idata_new failed.\n");
@@ -1060,8 +1096,7 @@ node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
"node_process: tf_idata_insert failed.\n");
goto nodedone;
}
- if (pad_process(mp, rd->rd_finfo, nn, ntn, &newi->ti_pad, rd->rd_name)
- < 0)
+ if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0)
goto nodedone;
rv = 0;
nodedone:
@@ -1108,6 +1143,7 @@ enum_attributes_process(topo_mod_t *mp, xmlNodePtr en)
enodedone:
if (einfo->te_name != NULL)
xmlFree(einfo->te_name);
+ topo_mod_free(mp, einfo, sizeof (tf_edata_t));
return (NULL);
}
@@ -1157,21 +1193,21 @@ enum_run(topo_mod_t *mp, tf_rdata_t *rd)
int
-decorate_nodes(topo_mod_t *mp,
- tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn, char *name, tf_pad_t **rpad)
+decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
+ tf_pad_t **rpad)
{
tnode_t *ctn;
ctn = topo_child_first(ptn);
while (ctn != NULL) {
/* Only care about instances within the range */
- if (strcmp(topo_node_name(ctn), name) != 0) {
+ if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) {
ctn = topo_child_next(ptn, ctn);
continue;
}
- if (pad_process(mp, xinfo, pxn, ctn, rpad, name) < 0)
+ if (pad_process(mp, rd, pxn, ctn, rpad) < 0)
return (-1);
- if (decorate_nodes(mp, xinfo, pxn, ctn, name, rpad) < 0)
+ if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0)
return (-1);
ctn = topo_child_next(ptn, ctn);
}
@@ -1194,6 +1230,7 @@ topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n"
"process %s range beneath %s\n", rd->rd_name,
topo_node_name(rd->rd_pn));
+
e = topo_node_range_create(mp,
rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max);
if (e != 0 && topo_mod_errno(mp) != ETOPO_NODE_DUP) {
@@ -1256,7 +1293,7 @@ topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
/* Now look for nodes, i.e., hard instances */
for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) {
- if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0)
+ if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) {
if (node_process(mp, cn, rd) < 0) {
topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
"node processing failed: %s.\n",
@@ -1265,6 +1302,7 @@ topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
EMOD_PARTIAL_ENUM));
}
ccnt++;
+ }
}
/*
@@ -1276,8 +1314,7 @@ topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
* to all of nodes in this range
*/
if (rd->rd_finfo->tf_flags & TF_PROPMAP)
- (void) decorate_nodes(mp, rd->rd_finfo, rn, rd->rd_pn,
- rd->rd_name, &rd->rd_pad);
+ (void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad);
else {
ct = topo_child_first(rd->rd_pn);
while (ct != NULL) {
@@ -1286,8 +1323,8 @@ topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
ct = topo_child_next(rd->rd_pn, ct);
continue;
}
- if (pad_process(mp, rd->rd_finfo, rn, ct, &rd->rd_pad,
- rd->rd_name) < 0)
+ if (pad_process(mp, rd, rn, ct, &rd->rd_pad)
+ < 0)
return (-1);
ct = topo_child_next(rd->rd_pn, ct);
ccnt++;
@@ -1310,16 +1347,76 @@ static tf_rdata_t *
topo_xml_walk(topo_mod_t *mp,
tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot)
{
- xmlNodePtr curr;
+ xmlNodePtr curr, def_set = NULL;
tf_rdata_t *rr, *pr, *rdp;
+ xmlChar *set;
+ char *key;
+ int joined_set = 0;
+
+ topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n");
+ rr = pr = NULL;
+ /*
+ * First iterate through all the XML nodes at this level to look for
+ * set nodes.
+ */
+ for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
+ if (curr->name == NULL) {
+ topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+ "topo_xml_walk: Ignoring nameless xmlnode\n");
+ continue;
+ }
+ if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) {
+ if (joined_set)
+ continue;
+
+ set = xmlGetProp(curr, (xmlChar *)Setlist);
+
+ if (mp->tm_hdl->th_product)
+ key = mp->tm_hdl->th_product;
+ else
+ key = mp->tm_hdl->th_platform;
+
+ /*
+ * If it's the default set then we'll store
+ * a pointer to it so that if none of the other
+ * sets apply to our product we can fall
+ * back to this one.
+ */
+ if (strcmp((char *)set, "default") == 0)
+ def_set = curr;
+ else if (set_contains(mp, key, (char *)set)) {
+ joined_set = 1;
+ if ((rdp = topo_xml_walk(mp, xinfo, curr,
+ troot)) == NULL) {
+ topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+ "topo_xml_walk: failed1\n");
+ }
+ if (pr == NULL) {
+ rr = pr = rdp;
+ } else {
+ pr->rd_next = rdp;
+ pr = rdp;
+ }
+ rr->rd_cnt++;
+ }
+ xmlFree(set);
+ }
+ }
+ /*
+ * If we haven't found a set that contains our product AND a default set
+ * exists, then we'll process it.
+ */
+ if (!joined_set && def_set)
+ if (topo_xml_walk(mp, xinfo, def_set, troot) == NULL) {
+ topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
+ "topo_xml_walk: failed2\n");
+ }
/*
- * What we're interested in are children xmlNodes of croot tagged
+ * Now we're interested in children xmlNodes of croot tagged
* as 'ranges'. These define what topology nodes may exist, and need
* to be verified.
*/
- topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n");
- rr = pr = NULL;
for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
if (curr->name == NULL) {
topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen
index 9d697226b6..afb5b1c879 100644
--- a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4500/Sun-Fire-X4500-hc-topology.xmlgen
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -48,70 +48,70 @@ sub calc_sfx_prop
my $hdd = shift;
my $sid = shift;
printf OFILE "\n";
- printf OFILE " <propgroup name='%s-properties'", $name;
+ printf OFILE " <propgroup name='%s-properties'", $name;
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='fru-update-action'";
+ printf OFILE " <propval name='fru-update-action'";
printf OFILE " type='string' value='ipmi:fru gid=3 hdd=%d' />\n", $hdd;
- printf OFILE " <propval name='indicator-name-0'";
+ printf OFILE " <propval name='indicator-name-0'";
printf OFILE " type='string' value='+PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-0'";
+ printf OFILE " <propval name='indicator-action-0'";
printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0001' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-1'";
+ printf OFILE " <propval name='indicator-name-1'";
printf OFILE " type='string' value='-PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-1'";
+ printf OFILE " <propval name='indicator-action-1'";
printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0001' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-2'";
+ printf OFILE " <propval name='indicator-name-2'";
printf OFILE " type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-2'";
+ printf OFILE " <propval name='indicator-action-2'";
printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0008' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-3'";
+ printf OFILE " <propval name='indicator-name-3'";
printf OFILE " type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-3'";
+ printf OFILE " <propval name='indicator-action-3'";
printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0008' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-4'";
+ printf OFILE " <propval name='indicator-name-4'";
printf OFILE " type='string' value='+FAULT' />\n";
- printf OFILE " <propval name='indicator-action-4'";
+ printf OFILE " <propval name='indicator-action-4'";
printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0002' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-5'";
+ printf OFILE " <propval name='indicator-name-5'";
printf OFILE " type='string' value='-FAULT' />\n";
- printf OFILE " <propval name='indicator-action-5'";
+ printf OFILE " <propval name='indicator-action-5'";
printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0002' />\n",
$sid;
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-0' type='string' value='absent>present' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-0' type='string' value='+PRSNT&amp;+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-1' type='string' value='present>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-1' type='string' value='+PRSNT&amp;-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-2' type='string' value='configured>unconfigured' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-2' type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-3' type='string' value='unconfigured>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-3' type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-4' type='string' value='unconfigured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-4' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-5' type='string' value='configured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-5' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-6' type='string' value='present>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-6' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
printf OFILE "\n";
}
@@ -129,39 +129,39 @@ sub calc_nodes
$index = (($cnt >> 1) % 6);
$p1 = $pci1[$index];
printf OFILE "\n";
- printf OFILE " <node instance='%d'>\n", $cnt;
+ printf OFILE " <node instance='%d'>\n", $cnt;
printf OFILE "\n";
- printf OFILE " <propgroup name='protocol'";
+ printf OFILE " <propgroup name='protocol'";
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ASRU' ";
+ printf OFILE " <propval name='ASRU' ";
printf OFILE "type='fmri' value=";
printf OFILE "'dev:////pci@%d,0/pci1022,7458@%d", $p0, $p1;
printf OFILE "/pci11ab,11ab\@1' />\n";
- printf OFILE " <propval name='label'";
+ printf OFILE " <propval name='label'";
printf OFILE " type='string' value='bay%d' />\n", $cnt;
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
- printf OFILE " <propgroup name='io'";
+ printf OFILE " <propgroup name='io'";
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ap-path'";
+ printf OFILE " <propval name='ap-path'";
printf OFILE " type='string'";
printf OFILE " value='/devices/pci@%d,0/pci1022,7458@%d", $p0, $p1;
printf OFILE "/pci11ab,11ab\@1:%d' />\n", $d;
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
calc_sfx_prop($sys_supported->{"prop_name"}, $hdd, $sid);
- printf OFILE " <propgroup name='binding'";
+ printf OFILE " <propgroup name='binding'";
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='occupant-path'";
+ printf OFILE " <propval name='occupant-path'";
printf OFILE " type='string'";
printf OFILE " value='/pci@%d,0/pci1022,7458@%d", $p0, $p1;
printf OFILE "/pci11ab,11ab\@1/disk@%d,0' />\n", $d;
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
printf OFILE "\n";
- printf OFILE " </node>\n";
+ printf OFILE " </node>\n";
printf OFILE "\n";
}
}
@@ -183,27 +183,31 @@ if (!$platform || !$input_file || !$output_file) {
open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
+my $in_chassis_range = 0;
while ($line = <IFILE>) {
chomp($line);
- if ($line ne "</topology>") {
- print OFILE "$line\n";
- } else {
+ if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) {
+ $in_chassis_range = 1;
+ }
+ if ($in_chassis_range && ($line =~ /<\/dependents>/)) {
last;
+ } else {
+ print OFILE "$line\n";
}
}
-print OFILE " <!--xml-gen internal storage-->\n";
-printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"};
+print OFILE " <!--xml-gen internal storage-->\n";
+printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"};
calc_nodes(0);
-printf OFILE " <dependents grouping='children'>\n";
-printf OFILE " <range name='disk' min='0'";
+printf OFILE " <dependents grouping='children'>\n";
+printf OFILE " <range name='disk' min='0'";
printf OFILE " max='1'>\n";
-printf OFILE " <enum-method name='disk'";
+printf OFILE " <enum-method name='disk'";
printf OFILE " version='1' />\n";
-printf OFILE " </range>\n";
-printf OFILE " </dependents>\n";
+printf OFILE " </range>\n";
+printf OFILE " </dependents>\n";
printf OFILE "\n";
-printf OFILE " </range>\n";
+printf OFILE " </range>\n";
print OFILE "$line\n";
while ($line = <IFILE>) {
print OFILE $line;
diff --git a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen
index b25986447b..0d49a3c83a 100644
--- a/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen
+++ b/usr/src/lib/fm/topo/maps/SUNW,Sun-Fire-X4540/Sun-Fire-X4540-hc-topology.xmlgen
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -48,74 +48,74 @@ sub calc_sfx_prop
my $hdd = shift;
my $sid = shift;
printf OFILE "\n";
- printf OFILE " <propgroup name='%s-properties'", $name;
+ printf OFILE " <propgroup name='%s-properties'", $name;
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='fru-update-action'";
+ printf OFILE " <propval name='fru-update-action'";
printf OFILE " type='string' value='ipmi:fru gid=3 hdd=%d' />\n", $hdd;
- printf OFILE " <propval name='indicator-name-0'";
+ printf OFILE " <propval name='indicator-name-0'";
printf OFILE " type='string' value='+PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-0'";
+ printf OFILE " <propval name='indicator-action-0'";
printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0001' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-1'";
+ printf OFILE " <propval name='indicator-name-1'";
printf OFILE " type='string' value='-PRSNT' />\n";
- printf OFILE " <propval name='indicator-action-1'";
+ printf OFILE " <propval name='indicator-action-1'";
printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0001' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-2'";
+ printf OFILE " <propval name='indicator-name-2'";
printf OFILE " type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-2'";
+ printf OFILE " <propval name='indicator-action-2'";
printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0008' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-3'";
+ printf OFILE " <propval name='indicator-name-3'";
printf OFILE " type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-action-3'";
+ printf OFILE " <propval name='indicator-action-3'";
printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0008' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-4'";
+ printf OFILE " <propval name='indicator-name-4'";
printf OFILE " type='string' value='+FAULT' />\n";
- printf OFILE " <propval name='indicator-action-4'";
+ printf OFILE " <propval name='indicator-action-4'";
printf OFILE " type='string' value='ipmi:state sid=%d amask=0x0002' />\n",
$sid;
- printf OFILE " <propval name='indicator-name-5'";
+ printf OFILE " <propval name='indicator-name-5'";
printf OFILE " type='string' value='-FAULT' />\n";
- printf OFILE " <propval name='indicator-action-5'";
+ printf OFILE " <propval name='indicator-action-5'";
printf OFILE " type='string' value='ipmi:state sid=%d dmask=0x0002' />\n",
$sid;
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-0' type='string' value='absent>present' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-0' type='string' value='+PRSNT&amp;+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-1' type='string' value='present>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-1' type='string' value='+PRSNT&amp;-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-2' type='string' value='configured>unconfigured' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-2' type='string' value='+OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-3' type='string' value='unconfigured>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-3' type='string' value='-OK2RM' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-4' type='string' value='unconfigured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-4' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-5' type='string' value='configured>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-5' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-6' type='string' value='present>absent' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-6' type='string' value='-OK2RM&amp;-PRSNT' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "states-7' type='string' value='absent>configured' />\n";
- printf OFILE " <propval name='indicator-rule-";
+ printf OFILE " <propval name='indicator-rule-";
printf OFILE "actions-7' type='string' value='-OK2RM&amp;+PRSNT' />\n";
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
printf OFILE "\n";
}
@@ -137,39 +137,39 @@ sub calc_nodes
"/pci1000,1000\@0";
printf OFILE "\n";
- printf OFILE " <node instance='%d'>\n", $bay;
+ printf OFILE " <node instance='%d'>\n", $bay;
printf OFILE "\n";
- printf OFILE " <propgroup name='protocol'";
+ printf OFILE " <propgroup name='protocol'";
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ASRU' ";
+ printf OFILE " <propval name='ASRU' ";
printf OFILE "type='fmri' value=";
printf OFILE "'dev:///" . $physdev . "' />\n";
- printf OFILE " <propval name='label'";
+ printf OFILE " <propval name='label'";
printf OFILE " type='string' value='bay%d' />\n", $bay;
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
- printf OFILE " <propgroup name='io'";
+ printf OFILE " <propgroup name='io'";
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='ap-path'";
+ printf OFILE " <propval name='ap-path'";
printf OFILE " type='string'";
printf OFILE " value='/devices" . $physdev;
printf OFILE ":scsi::dsk/c%dt%dd0", $controller + 1, $target;
printf OFILE "' />\n";
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
calc_sfx_prop($sys_supported->{"prop_name"}, $bay, $sid);
- printf OFILE " <propgroup name='binding'";
+ printf OFILE " <propgroup name='binding'";
printf OFILE " version='1' name-stability='Private'";
printf OFILE " data-stability='Private' >\n";
- printf OFILE " <propval name='occupant-path'";
+ printf OFILE " <propval name='occupant-path'";
printf OFILE " type='string'";
printf OFILE " value='" . $physdev . "/sd\@%d,0", $target;
printf OFILE "' />\n";
- printf OFILE " </propgroup>\n";
+ printf OFILE " </propgroup>\n";
printf OFILE "\n";
- printf OFILE " </node>\n";
+ printf OFILE " </node>\n";
printf OFILE "\n";
}
}
@@ -191,27 +191,31 @@ if (!$platform || !$input_file || !$output_file) {
open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
+my $in_chassis_range = 0;
while ($line = <IFILE>) {
chomp($line);
- if ($line ne "</topology>") {
- print OFILE "$line\n";
- } else {
+ if ($line =~ /range\s+name\s?=\s?\Wchassis\W/) {
+ $in_chassis_range = 1;
+ }
+ if ($in_chassis_range && ($line =~ /\/dependents/)) {
last;
+ } else {
+ print OFILE "$line\n";
}
}
-print OFILE " <!--xml-gen internal storage-->\n";
-printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"};
+print OFILE " <!--xml-gen internal storage-->\n";
+printf OFILE " <range name='bay' min='0' max='%d'>\n", $sys_supported->{"num_bays"};
calc_nodes(0);
-printf OFILE " <dependents grouping='children'>\n";
-printf OFILE " <range name='disk' min='0'";
+printf OFILE " <dependents grouping='children'>\n";
+printf OFILE " <range name='disk' min='0'";
printf OFILE " max='1'>\n";
-printf OFILE " <enum-method name='disk'";
+printf OFILE " <enum-method name='disk'";
printf OFILE " version='1' />\n";
-printf OFILE " </range>\n";
-printf OFILE " </dependents>\n";
+printf OFILE " </range>\n";
+printf OFILE " </dependents>\n";
printf OFILE "\n";
-printf OFILE " </range>\n";
+printf OFILE " </range>\n";
print OFILE "$line\n";
while ($line = <IFILE>) {
print OFILE $line;
diff --git a/usr/src/lib/fm/topo/maps/common/topology.dtd.1 b/usr/src/lib/fm/topo/maps/common/topology.dtd.1
index ff80979cc0..baffea45f5 100644
--- a/usr/src/lib/fm/topo/maps/common/topology.dtd.1
+++ b/usr/src/lib/fm/topo/maps/common/topology.dtd.1
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ Copyright 2008 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
CDDL HEADER START
@@ -112,23 +112,24 @@
External | Obsolete ) #REQUIRED >
<!--
- propset
- This element is for associating property groups according to a set type.
+ set
+ This element is for associating ranges, nodes or property groups
+ according to a set type.
Its attributes are
type The type of this property group set. 'product' is the
only set type currently supported.
- set The list of set types.
+ setlist The list of set types.
-->
-<!ELEMENT propset
- ( propgroup* ) >
+<!ELEMENT set
+ ( range*, propgroup* ) >
-<!ATTLIST propset
+<!ATTLIST set
type ( product ) #REQUIRED
- set CDATA #REQUIRED >
+ setlist CDATA #REQUIRED >
<!--
propmap
@@ -206,7 +207,6 @@
name CDATA #REQUIRED
version CDATA #REQUIRED >
-
<!--
node
@@ -219,7 +219,7 @@
-->
<!ELEMENT node
- ( propgroup*, dependents*, propset* ) >
+ ( propgroup*, dependents*, set*, enum-method* ) >
<!ATTLIST node
instance CDATA #REQUIRED >
@@ -235,7 +235,7 @@
-->
<!ELEMENT dependents
- ( range | xi:include )+ >
+ (( range | xi:include )+, set) >
<!ATTLIST dependents
grouping ( children | siblings ) "children" #REQUIRED >
@@ -254,12 +254,11 @@
max The largest allowed instance number for an
actual topo node.
-
-->
<!ELEMENT range
( enum-method?, propmap?, node*, propgroup*, dependents*,
- propset* ) >
+ set? ) >
<!ATTLIST range
name CDATA #REQUIRED
@@ -277,7 +276,7 @@
-->
<!ELEMENT topology
- (range* | xi:include*)>
+ ((range* | xi:include*), set)>
<!ATTLIST topology
name CDATA #REQUIRED
diff --git a/usr/src/lib/fm/topo/maps/i86pc/Makefile b/usr/src/lib/fm/topo/maps/i86pc/Makefile
index 7877583987..cf14447082 100644
--- a/usr/src/lib/fm/topo/maps/i86pc/Makefile
+++ b/usr/src/lib/fm/topo/maps/i86pc/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -27,7 +27,12 @@
ARCH = i86pc
CLASS = arch
DTDFILE = topology.dtd.1
-TOPOFILE = i86pc-hc-topology.xml chip-hc-topology.xml
+TOPOFILE = i86pc-hc-topology.xml chip-hc-topology.xml psu-hc-topology.xml \
+fan-hc-topology.xml
+
SRCDIR = ../i86pc
+PLATFORM = unused
+TOPOBASE = i86pc-hc-topology.xml
+
include ../Makefile.map
diff --git a/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml b/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml
index 8e9a794b57..4ca2831ab9 100644
--- a/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml
+++ b/usr/src/lib/fm/topo/maps/i86pc/chip-hc-topology.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1">
<!--
- Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ Copyright 2008 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
CDDL HEADER START
@@ -30,8 +30,8 @@
<range name='chip' min='0' max='100'>
- <propset type='product'
- set='Sun-Fire-V20z|Sun-Fire-V40z|W1100z-2100z|Sun-Ultra-20-Workstation|Ultra20-M2|Sun-Ultra-40-M2-Workstation'>
+ <set type='product'
+ setlist='Sun-Fire-V20z|Sun-Fire-V40z|W1100z-2100z|Sun-Ultra-20-Workstation|Ultra20-M2|Sun-Ultra-40-M2-Workstation'>
<propgroup name='protocol' version='1'
name-stability='Private' data-stability='Private' >
@@ -46,9 +46,9 @@
</propgroup>
- </propset>
- <propset type='product'
- set='Sun-Fire(TM)-X2100|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E|Sun-Fire-X4500|X2100-M2|Sun-Blade-X8440-Server-Module|Sun-Fire-X4140|Sun-Fire-X4240|Sun-Fire-X4440'>
+ </set>
+ <set type='product'
+ setlist='Sun-Fire(TM)-X2100|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E|Sun-Fire-X4500|X2100-M2|Sun-Blade-X8440-Server-Module|Sun-Fire-X4140|Sun-Fire-X4240|Sun-Fire-X4440'>
<propgroup name='protocol' version='1'
name-stability='Private' data-stability='Private' >
@@ -63,9 +63,9 @@
</propgroup>
- </propset>
- <propset type='product'
- set='Sun-Fire-X4100-M2|Sun-Fire-X4200-M2'>
+ </set>
+ <set type='product'
+ setlist='Sun-Fire-X4100-M2|Sun-Fire-X4200-M2'>
<propgroup name='protocol' version='1'
name-stability='Private' data-stability='Private' >
@@ -80,9 +80,9 @@
</propgroup>
- </propset>
- <propset type='product'
- set='Sun-Fire-X4600|Sun-Fire-X4600-M2'>
+ </set>
+ <set type='product'
+ setlist='Sun-Fire-X4600|Sun-Fire-X4600-M2'>
<propgroup name='protocol' version='1'
name-stability='Private' data-stability='Private' >
@@ -96,7 +96,7 @@
</propgroup>
- </propset>
+ </set>
<dependents grouping='children'>
@@ -107,7 +107,7 @@
<dependents grouping='children'>
<range name='chip-select' min='0' max='7'>
- <propset type='product' set='Sun-Blade-X8440-Server-Module|Sun-Fire-X4600-M2'>
+ <set type='product' setlist='Sun-Blade-X8440-Server-Module|Sun-Fire-X4600-M2'>
<propgroup name='protocol' version='1'
name-stability='Private'
@@ -124,8 +124,8 @@
</propgroup>
- </propset>
- <propset type='product' set='Sun-Fire-X4140|Sun-Fire-X4240|Sun-Fire-X4440'>
+ </set>
+ <set type='product' setlist='Sun-Fire-X4140|Sun-Fire-X4240|Sun-Fire-X4440'>
<propgroup name='protocol' version='1'
name-stability='Private'
@@ -142,14 +142,14 @@
</propgroup>
- </propset>
+ </set>
</range>
</dependents>
</range>
<range name='dimm' min='0' max='16'>
- <propset type='product' set='Sun-Ultra-20-Workstation|Sun-Fire(TM)-X2100'>
+ <set type='product' setlist='Sun-Ultra-20-Workstation|Sun-Fire(TM)-X2100'>
<propgroup name='protocol' version='1'
name-stability='Private'
@@ -166,8 +166,8 @@
</propgroup>
- </propset>
- <propset type='product' set='Sun-Fire-V20z|Sun-Fire-V40z|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E'>
+ </set>
+ <set type='product' setlist='Sun-Fire-V20z|Sun-Fire-V40z|Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4200E'>
<propgroup name='protocol' version='1'
name-stability='Private'
@@ -188,9 +188,9 @@
</propgroup>
- </propset>
- <propset type='product'
- set='Sun-Ultra-40-M2-Workstation'>
+ </set>
+ <set type='product'
+ setlist='Sun-Ultra-40-M2-Workstation'>
<propgroup name='protocol' version='1'
name-stability='Private'
@@ -209,9 +209,9 @@
</propgroup>
- </propset>
- <propset type='product'
- set='X2100-M2'>
+ </set>
+ <set type='product'
+ setlist='X2100-M2'>
<propgroup name='protocol' version='1'
name-stability='Private'
@@ -230,7 +230,7 @@
</propgroup>
- </propset>
+ </set>
</range>
diff --git a/usr/src/lib/fm/topo/maps/i86pc/fan-hc-topology.xmlgen b/usr/src/lib/fm/topo/maps/i86pc/fan-hc-topology.xmlgen
new file mode 100644
index 0000000000..da510918b1
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/i86pc/fan-hc-topology.xmlgen
@@ -0,0 +1,269 @@
+#!/usr/bin/perl -w
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# The fan topologies can be quite complicated, but are ultimately regular. This
+# perl file uses some simplified internal structures to generate an .xml file
+# without the maintenance overhead.
+#
+
+use Getopt::Std;
+use strict;
+
+#
+# Master table of platforms.
+#
+my @platforms = (
+ #
+ # Galaxy 1/2 platforms.
+ #
+ # These systems have 2 fan-connector boards. Each fan-connector board has 3
+ # fan modules. Each fan module is an individual FRU. The fan-connector
+ # boards are also FRUs.
+ #
+ {
+ set => "Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|" .
+ "Sun-Fire-X4100-M2|Sun-Fire-X4200-M2",
+ topology => [
+ {
+ label => "FT %d",
+ count => 2,
+ fru => "self"
+ }, {
+ count => 3,
+ label => "FT %d FM %d",
+ entity_ref => "ft%d.fm%d.led",
+ fru => "self"
+ }
+ ]
+ },
+
+ #
+ # Thumper platforms
+ #
+ # These systems have 5 fan modules, with each fan module containing 2 fans.
+ # The FRUs for the individual fans are the containing fan module.
+ #
+ {
+ set => "Sun-Fire-X4500|Sun-Fire-X4540",
+ topology => [
+ {
+ label => "FT %d",
+ count => 5,
+ fru => "self",
+ entity_ref => "ft%d.prsnt",
+ }, {
+ count => 2,
+ fru => "parent"
+ }
+ ]
+ },
+
+ #
+ # Fan Module/Fan topology for all G1N/G2N platforms.
+ #
+ # These systems have 6 fan modules, with each fan module containing 2 fans.
+ # The FRU's for the individual fans are the containing fan module.
+ #
+ # Unfortunately, the IPMI topology on these systems is rather broken, and
+ # all the SDRs that should be separate entities in fact refer to the same
+ # entity IDs. So we have to use the alternative 'entity_present' option
+ # using a single SDR record.
+ #
+ {
+ set => "Sun-Fire-X4240|Sun-Fire-X4440",
+ topology => [
+ {
+ count => 2,
+ label => "FT %d",
+ fru => "self"
+ }, {
+ label => "FT %d FM %d",
+ count => 3,
+ fru => "self",
+ entity_present => "fb%d.fm%d.prsnt",
+ }, {
+ count => 2,
+ fru => "parent"
+ }
+
+ ]
+ }
+);
+
+sub usage
+{
+ print STDERR "Usage: xml-gen -p <platform> -i <input_xml_file> -o <output_xml_file>\n";
+}
+
+#
+# Process an entry in the topology list. We are passed the indentation level,
+# the current topology array, and any pushed indices. This is called
+# recursively.
+#
+sub process_topology
+{
+ my ($indent, $toporef, @indices) = @_;
+ my @topo = @$toporef;
+ my $level = shift @topo;
+ my $type = $#topo == -1 ? "fan" : "fanmodule";
+
+ printf(OFILE "%*s<range name='%s' min='%d' max='%d'>\n",
+ $indent, "", $type, 0, $level->{count} - 1);
+ $indent += 2;
+
+ for (my $i = 0; $i < $level->{count}; $i++) {
+ push @indices, $i;
+
+ printf(OFILE "%*s<node instance='%d'>\n", $indent, "", $i);
+
+ $indent += 2;
+
+ # Protocol properties (label, fmri)
+ printf(OFILE "%*s<propgroup name='protocol' version='1' " .
+ "name-stability='Private' data-stability='Private'>\n",
+ $indent, "");
+
+ $indent += 2;
+
+ if ($level->{label}) {
+ printf(OFILE "%*s<propval name='label' type='string' " .
+ "value='", $indent, "");
+ printf(OFILE $level->{label}, @indices);
+ printf(OFILE "' />\n");
+ }
+
+ printf(OFILE "%*s<propmethod name='ipmi_fru_fmri' " .
+ "version='0' propname='FRU' proptype='fmri'>\n",
+ $indent, "");
+ printf(OFILE "%*s<argval name='entity' type='string' " .
+ "value='%s' />\n", $indent + 2, "", $level->{fru});
+ printf(OFILE "%*s</propmethod>\n", $indent, "");
+
+ $indent -= 2;
+
+ printf(OFILE "%*s</propgroup>\n", $indent, "");
+
+ #
+ # Entity reference (if any)
+ #
+ if ($level->{entity_ref} || $level->{entity_present}) {
+ my $name = $level->{entity_ref} ? "entity_ref" :
+ "entity_present";
+ my $val = $level->{$name};
+ printf(OFILE "%*s<propgroup name='ipmi' version='1' " .
+ "name-stability='Private' " .
+ "data-stability='Private' >\n", $indent, "");
+ printf(OFILE "%*s<propval name='%s' " .
+ "type='string' value='", $indent + 2, "", $name);
+ printf(OFILE $val, @indices);
+ printf(OFILE "' />\n");
+ printf(OFILE "%*s</propgroup>\n", $indent, "");
+ }
+
+
+ #
+ # Children (if any)
+ #
+ if ($#topo != -1) {
+ printf(OFILE "%*s<dependents grouping='children'>\n",
+ $indent, "");
+ process_topology($indent + 2, \@topo, @indices);
+ printf(OFILE "%*s</dependents>\n", $indent, "");
+ }
+
+ #
+ # Post-process IPMI enumerator method
+ #
+ printf(OFILE "%*s<enum-method name='ipmi' version='1' />\n",
+ $indent, "");
+
+ $indent -= 2;
+
+ printf(OFILE "%*s</node>\n", $indent, "");
+ pop @indices;
+ }
+
+ $indent -= 2;
+ printf(OFILE "%*s</range>\n", $indent, "");
+}
+
+#
+# Process a single platform file.
+#
+sub process_platform
+{
+ my ($desc) = @_;
+ my $indent = 2;
+
+ printf(OFILE "%*s<set type='product' setlist='%s'>\n", $indent, "",
+ $desc->{set});
+
+ process_topology($indent + 2, $desc->{topology});
+
+ printf(OFILE "%*s</set>\n", $indent, "");
+}
+
+my %options;
+getopts("p:i:o:h", \%options);
+if ($options{'h'}) {
+ usage();
+ exit (1);
+}
+
+my $platform = $options{'p'};
+my $input_file = $options{'i'};
+my $output_file = $options{'o'};
+
+if (!$platform || !$input_file || !$output_file) {
+ usage();
+ exit (1);
+}
+
+open(IFILE, "< $input_file") || die("$input_file cannot be opened.");
+open(OFILE, "> $output_file") || die("$output_file cannot be opened.");
+
+#
+# Open the file and read in the header until we reach the <topology> node.
+#
+while (<IFILE>) {
+ last if /<topology/;
+ print OFILE;
+}
+
+#
+# Construct the framework.
+#
+print OFILE "<topology name='fan' scheme='hc'>\n";
+
+my $desc;
+foreach $desc (@platforms) {
+ my $set = $desc->{set};
+ process_platform($desc);
+}
+
+print OFILE "</topology>\n";
diff --git a/usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml b/usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml
index 9aecf6e30d..573ce1243a 100644
--- a/usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml
+++ b/usr/src/lib/fm/topo/maps/i86pc/i86pc-hc-topology.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1">
<!--
- Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ Copyright 2008 Sun Microsystems, Inc. All rights reserved.
Use is subject to license terms.
CDDL HEADER START
@@ -31,11 +31,11 @@
<range name='motherboard' min='0' max='0'>
<node instance='0'>
<propgroup name='protocol' version='1'
- name-stability='Private' data-stability='Private' >
- <propval name='label' type='string'
- value='MB' />
+ name-stability='Private' data-stability='Private' >
+ <propval name='label' type='string' value='MB' />
</propgroup>
</node>
+
<dependents grouping='children'>
<range name='chip' min='0' max='100'>
<enum-method name='chip' version='1' />
@@ -45,6 +45,45 @@
<enum-method name='hostbridge' version='1' />
</range>
</dependents>
+
+ </range>
+
+ <range name='chassis' min='0' max='0'>
+ <node instance='0'>
+ </node>
+
+ <dependents grouping='children'>
+
+ <set type='product' setlist='Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4100-M2|Sun-Fire-X4200-M2|Sun-Fire-X4240|Sun-Fire-X4440'>
+ <range name='psu' min='0' max='100'>
+ <enum-method name='ipmi' version='1' />
+ <propmap name='psu' />
+ </range>
+ <range name='fanmodule' min='0' max='100'>
+ <propmap name='fan' />
+ </range>
+ </set>
+
+ <set type='product' setlist='Sun-Fire-X4500|Sun-Fire-X4540'>
+ <range name='psu' min='0' max='100'>
+ <propmap name='psu' />
+ </range>
+ <range name='fanmodule' min='0' max='100'>
+ <propmap name='fan' />
+ </range>
+ </set>
+
+ <set type='product' setlist='default'>
+ <range name='psu' min='0' max='100'>
+ <enum-method name='ipmi' version='1' />
+ </range>
+ <range name='fan' min='0' max='100'>
+ <enum-method name='ipmi' version='1' />
+ </range>
+ </set>
+
+ </dependents>
+
</range>
</topology>
diff --git a/usr/src/lib/fm/topo/maps/i86pc/psu-hc-topology.xml b/usr/src/lib/fm/topo/maps/i86pc/psu-hc-topology.xml
new file mode 100644
index 0000000000..334b9067b0
--- /dev/null
+++ b/usr/src/lib/fm/topo/maps/i86pc/psu-hc-topology.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1">
+<!--
+ Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ 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
+
+ ident "%Z%%M% %I% %E% SMI"
+-->
+
+<topology name='psu' scheme='hc'>
+
+ <!--
+ Thumper platforms explicitly have only two power supplies, as
+ the third (unused) bay is reported via IPMI but not actually
+ valid.
+ -->
+ <set type='product' setlist='Sun-Fire-X4500|Sun-Fire-X4540'>
+ <range name='psu' min='0' max='100'>
+ <node instance='0'>
+ <propgroup name='protocol' version='1'
+ name-stability='Private' data-stability='Private' >
+ <propval name='label' type='string' value='PS0' />
+ <propmethod name='ipmi_fru_fmri' version='0'
+ propname='FRU' proptype='fmri' >
+ <argval name='entity' type='string' value='self' />
+ </propmethod>
+ </propgroup>
+ <propgroup name='ipmi' version='1'
+ name-stability='Private' data-stability='Private' >
+
+ <propval name='entity_ref' type='string' value='ps0.prsnt' />
+ </propgroup>
+ <enum-method name='ipmi' version='1' />
+ </node>
+ <node instance='1'>
+ <propgroup name='protocol' version='1'
+ name-stability='Private' data-stability='Private' >
+ <propval name='label' type='string' value='PS1' />
+ <propmethod name='ipmi_fru_fmri' version='0'
+ propname='FRU' proptype='fmri' >
+ <argval name='entity' type='string' value='self' />
+ </propmethod>
+ </propgroup>
+ <propgroup name='ipmi' version='1'
+ name-stability='Private' data-stability='Private' >
+
+ <propval name='entity_ref' type='string' value='ps1.prsnt' />
+ </propgroup>
+ <enum-method name='ipmi' version='1' />
+ </node>
+ </range>
+ </set>
+ <set type='product' setlist='Sun-Fire-X4100-Server|Sun-Fire-X4200-Server|Sun-Fire-X4100-M2|Sun-Fire-X4200-M2|Sun-Fire-X4240|Sun-Fire-X4440'>
+ <range name='psu' min='0' max='100'>
+ <propgroup name='protocol' version='1'
+ name-stability='Private' data-stability='Private' >
+
+ <propmethod name='ipmi_fru_label' version='0'
+ propname='label' proptype='string' >
+
+ <argval name='format' type='string' value='PS%d' />
+ <argval name='offset' type='uint32' value='0' />
+
+ </propmethod>
+ </propgroup>
+ </range>
+ </set>
+</topology>
diff --git a/usr/src/lib/fm/topo/modules/common/Makefile b/usr/src/lib/fm/topo/modules/common/Makefile
index 0af0f58c12..6d008e3e9e 100644
--- a/usr/src/lib/fm/topo/modules/common/Makefile
+++ b/usr/src/lib/fm/topo/modules/common/Makefile
@@ -20,12 +20,15 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#pragma ident "%Z%%M% %I% %E% SMI"
-SUBDIRS = disk xfp
+SUBDIRS = \
+ disk \
+ ipmi \
+ xfp
.PARALLEL: $(SUBDIRS)
diff --git a/usr/src/lib/fm/topo/modules/common/ipmi/Makefile b/usr/src/lib/fm/topo/modules/common/ipmi/Makefile
new file mode 100644
index 0000000000..b6f2839c42
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/ipmi/Makefile
@@ -0,0 +1,34 @@
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+MODULE = ipmi
+CLASS = common
+
+MODULESRCS = ipmi_enum.c ipmi_methods.c
+
+include ../../Makefile.plugin
+
+LDLIBS += -lipmi
diff --git a/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c b/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c
new file mode 100644
index 0000000000..49d104ec5c
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_enum.c
@@ -0,0 +1,471 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <assert.h>
+#include <fm/libtopo.h>
+#include <fm/topo_mod.h>
+#include <sys/fm/protocol.h>
+#include <string.h>
+
+#define TOPO_PGROUP_IPMI "ipmi"
+#define TOPO_PROP_IPMI_ENTITY_REF "entity_ref"
+#define TOPO_PROP_IPMI_ENTITY_PRESENT "entity_present"
+
+typedef struct ipmi_enum_data {
+ topo_mod_t *ed_mod;
+ tnode_t *ed_pnode;
+ const char *ed_name;
+ char *ed_label;
+ uint8_t ed_entity;
+ topo_instance_t ed_instance;
+ boolean_t ed_hasfru;
+} ipmi_enum_data_t;
+
+static int ipmi_present(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
+ nvlist_t **);
+static int ipmi_enum(topo_mod_t *, tnode_t *, const char *,
+ topo_instance_t, topo_instance_t, void *, void *);
+static int ipmi_post_process(topo_mod_t *, tnode_t *);
+
+extern int ipmi_fru_label(topo_mod_t *mod, tnode_t *node,
+ topo_version_t vers, nvlist_t *in, nvlist_t **out);
+
+extern int ipmi_fru_fmri(topo_mod_t *mod, tnode_t *node,
+ topo_version_t vers, nvlist_t *in, nvlist_t **out);
+
+static const topo_method_t ipmi_methods[] = {
+ { TOPO_METH_PRESENT, TOPO_METH_PRESENT_DESC,
+ TOPO_METH_PRESENT_VERSION0, TOPO_STABILITY_INTERNAL, ipmi_present },
+ { "ipmi_fru_label", "Property method", 0,
+ TOPO_STABILITY_INTERNAL, ipmi_fru_label},
+ { "ipmi_fru_fmri", "Property method", 0,
+ TOPO_STABILITY_INTERNAL, ipmi_fru_fmri},
+ { NULL }
+};
+
+const topo_modops_t ipmi_ops = { ipmi_enum, NULL };
+
+const topo_modinfo_t ipmi_info =
+ { "ipmi", FM_FMRI_SCHEME_HC, TOPO_VERSION, &ipmi_ops };
+
+/*
+ * Determine if the entity is present.
+ */
+/*ARGSUSED*/
+static int
+ipmi_present(topo_mod_t *mod, tnode_t *tn, topo_version_t version,
+ nvlist_t *in, nvlist_t **out)
+{
+ ipmi_handle_t *ihp;
+ ipmi_entity_t *ep;
+ boolean_t present;
+ nvlist_t *nvl;
+ int err;
+ char *name;
+ ipmi_sdr_t *sdrp;
+
+ if ((ihp = topo_mod_ipmi(mod)) == NULL)
+ return (topo_mod_seterrno(mod, ETOPO_METHOD_UNKNOWN));
+
+ ep = topo_node_getspecific(tn);
+ if (ep == NULL) {
+ if (topo_prop_get_string(tn, TOPO_PGROUP_IPMI,
+ TOPO_PROP_IPMI_ENTITY_PRESENT, &name, &err) == 0) {
+ /*
+ * Some broken IPMI implementations don't export correct
+ * entities, so referring to an entity isn't sufficient.
+ * For these platforms, we allow the XML to specify a
+ * single SDR record that represents the current present
+ * state.
+ */
+ if ((sdrp = ipmi_sdr_lookup(ihp, name)) == NULL ||
+ ipmi_entity_present_sdr(ihp, sdrp, &present) != 0) {
+ topo_mod_dprintf(mod,
+ "Failed to get present state of %s (%s)\n",
+ name, ipmi_errmsg(ihp));
+ topo_mod_strfree(mod, name);
+ return (-1);
+ }
+
+ topo_mod_strfree(mod, name);
+ } else {
+ if (topo_prop_get_string(tn, TOPO_PGROUP_IPMI,
+ TOPO_PROP_IPMI_ENTITY_REF, &name, &err) != 0) {
+ topo_mod_dprintf(mod,
+ "Failed to get prop %s (%s)\n",
+ TOPO_PROP_IPMI_ENTITY_REF, strerror(err));
+ return (-1);
+ }
+
+ if ((ep = ipmi_entity_lookup_sdr(ihp, name)) == NULL) {
+ topo_mod_strfree(mod, name);
+ topo_mod_dprintf(mod,
+ "Failed to lookup ipmi entity "
+ "%s (%s)\n", name, ipmi_errmsg(ihp));
+ return (-1);
+ }
+
+ topo_mod_strfree(mod, name);
+ topo_node_setspecific(tn, ep);
+ }
+ }
+
+ if (ep != NULL) {
+ if (ipmi_entity_present(ihp, ep, &present) != 0) {
+ topo_mod_dprintf(mod,
+ "ipmi_entity_present() failed: %s",
+ ipmi_errmsg(ihp));
+ present = B_TRUE;
+ }
+ }
+
+ if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0)
+ return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
+
+ if (nvlist_add_uint32(nvl, TOPO_METH_PRESENT_RET, present) != 0) {
+ nvlist_free(nvl);
+ return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
+ }
+
+ *out = nvl;
+
+ return (0);
+}
+
+/*
+ * This determines if the entity has a FRU locator record set, in which case we
+ * treat this as a FRU, even if it's part of an association.
+ */
+/*ARGSUSED*/
+static int
+ipmi_check_sdr(ipmi_handle_t *ihp, ipmi_entity_t *ep, const char *name,
+ ipmi_sdr_t *sdrp, void *data)
+{
+ ipmi_enum_data_t *edp = data;
+
+ if (sdrp->is_type == IPMI_SDR_TYPE_FRU_LOCATOR)
+ edp->ed_hasfru = B_TRUE;
+
+ return (0);
+}
+
+/*
+ * Main entity enumerator. If we find a matching entity type, then instantiate
+ * a topo node.
+ */
+static int
+ipmi_check_entity(ipmi_handle_t *ihp, ipmi_entity_t *ep, void *data)
+{
+ ipmi_enum_data_t *edp = data;
+ ipmi_enum_data_t cdata;
+ tnode_t *pnode = edp->ed_pnode;
+ topo_mod_t *mod = edp->ed_mod;
+ nvlist_t *auth, *fmri;
+ tnode_t *tn;
+ topo_pgroup_info_t pgi;
+ int err;
+ const char *labelname;
+ char label[64];
+ size_t len;
+
+ if (ep->ie_type != edp->ed_entity)
+ return (0);
+
+ /*
+ * The purpose of power and cooling domains is to group psus and fans
+ * together. Unfortunately, some broken IPMI implementations declare
+ * domains that don't contain other elements. Since the end goal is to
+ * only enumerate psus and fans, we'll just ignore such elements.
+ */
+ if ((ep->ie_type == IPMI_ET_POWER_DOMAIN ||
+ ep->ie_type == IPMI_ET_COOLING_DOMAIN) &&
+ ep->ie_children == 0)
+ return (0);
+
+ if ((auth = topo_mod_auth(mod, pnode)) == NULL) {
+ topo_mod_dprintf(mod, "topo_mod_auth() failed: %s",
+ topo_mod_errmsg(mod));
+ return (1);
+ }
+
+ if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION,
+ edp->ed_name, edp->ed_instance, NULL, auth, NULL, NULL,
+ NULL)) == NULL) {
+ nvlist_free(auth);
+ topo_mod_dprintf(mod, "topo_mod_hcfmri() failed: %s",
+ topo_mod_errmsg(mod));
+ return (1);
+ }
+
+ nvlist_free(auth);
+
+ if ((tn = topo_node_bind(mod, pnode, edp->ed_name,
+ edp->ed_instance, fmri)) == NULL) {
+ nvlist_free(fmri);
+ topo_mod_dprintf(mod, "topo_node_bind() failed: %s",
+ topo_mod_errmsg(mod));
+ return (1);
+ }
+
+ /*
+ * We inherit our label from our parent, appending our label in the
+ * process. This results in defaults labels of the form "FM 1 FAN 0"
+ * by default when given a hierarchy.
+ */
+ if (edp->ed_label != NULL)
+ (void) snprintf(label, sizeof (label), "%s ", edp->ed_label);
+ else
+ label[0] = '\0';
+
+ switch (edp->ed_entity) {
+ case IPMI_ET_POWER_DOMAIN:
+ labelname = "PM";
+ break;
+
+ case IPMI_ET_PSU:
+ labelname = "PSU";
+ break;
+
+ case IPMI_ET_COOLING_DOMAIN:
+ labelname = "FM";
+ break;
+
+ case IPMI_ET_FAN:
+ labelname = "FAN";
+ break;
+ }
+
+ len = strlen(label);
+ (void) snprintf(label + len, sizeof (label) - len, "%s %d",
+ labelname, edp->ed_instance);
+
+ nvlist_free(fmri);
+ edp->ed_instance++;
+
+ if (topo_node_label_set(tn, label, &err) != 0) {
+ topo_mod_dprintf(mod, "failed to set label: %s\n",
+ topo_strerror(err));
+ return (1);
+ }
+
+ /*
+ * Store IPMI entity details as properties on the node
+ */
+ pgi.tpi_name = TOPO_PGROUP_IPMI;
+ pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_version = TOPO_VERSION;
+ if (topo_pgroup_create(tn, &pgi, &err) != 0) {
+ if (err != ETOPO_PROP_DEFD) {
+ topo_mod_dprintf(mod, "failed to create propgroup "
+ "%s: %s\n", TOPO_PGROUP_IPMI, topo_strerror(err));
+ return (1);
+ }
+ }
+
+ if (topo_method_register(mod, tn, ipmi_methods) != 0) {
+ topo_mod_dprintf(mod, "topo_method_register() failed: %s",
+ topo_mod_errmsg(mod));
+ return (1);
+ }
+
+ /*
+ * If we are a child of a non-chassis node, and there isn't an explicit
+ * FRU locator record, then propagate the parent's FRU. Otherwise, set
+ * the FRU to be the same as the resource.
+ */
+ edp->ed_hasfru = B_FALSE;
+ (void) ipmi_entity_iter_sdr(ihp, ep, ipmi_check_sdr, edp);
+
+ if (strcmp(topo_node_name(pnode), CHASSIS) == 0 ||
+ edp->ed_hasfru) {
+ if (topo_node_resource(tn, &fmri, &err) != 0) {
+ topo_mod_dprintf(mod, "topo_node_resource() failed: %s",
+ topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ return (1);
+ }
+ } else {
+ if (topo_node_fru(pnode, &fmri, NULL, &err) != 0) {
+ topo_mod_dprintf(mod, "topo_node_fru() failed: %s",
+ topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ return (1);
+ }
+ }
+
+ if (topo_node_fru_set(tn, fmri, 0, &err) != 0) {
+ nvlist_free(fmri);
+ topo_mod_dprintf(mod, "topo_node_fru_set() failed: %s",
+ topo_strerror(err));
+ (void) topo_mod_seterrno(mod, err);
+ return (1);
+ }
+
+ topo_node_setspecific(tn, ep);
+
+ nvlist_free(fmri);
+
+ /*
+ * Iterate over children, once for recursive domains and once for
+ * psu/fans.
+ */
+ if (ep->ie_children != 0 &&
+ (ep->ie_type == IPMI_ET_POWER_DOMAIN ||
+ ep->ie_type == IPMI_ET_COOLING_DOMAIN)) {
+ cdata.ed_mod = edp->ed_mod;
+ cdata.ed_pnode = tn;
+ cdata.ed_instance = 0;
+ cdata.ed_name = edp->ed_name;
+ cdata.ed_entity = edp->ed_entity;
+ cdata.ed_label = label;
+
+ if (ipmi_entity_iter_children(ihp, ep,
+ ipmi_check_entity, &cdata) != 0)
+ return (1);
+
+ switch (cdata.ed_entity) {
+ case IPMI_ET_POWER_DOMAIN:
+ cdata.ed_entity = IPMI_ET_PSU;
+ cdata.ed_name = PSU;
+ break;
+
+ case IPMI_ET_COOLING_DOMAIN:
+ cdata.ed_entity = IPMI_ET_FAN;
+ cdata.ed_name = FAN;
+ break;
+ }
+
+ if (ipmi_entity_iter_children(ihp, ep,
+ ipmi_check_entity, &cdata) != 0)
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * libtopo enumeration point. This simply iterates over entities looking for
+ * the appropriate type.
+ */
+/*ARGSUSED*/
+static int
+ipmi_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
+ topo_instance_t min, topo_instance_t max, void *arg, void *unused)
+{
+ ipmi_handle_t *ihp;
+ ipmi_enum_data_t data;
+ int ret;
+
+ /*
+ * If the node being passed in ISN'T the chassis node, then we're being
+ * asked to post-process a statically defined node.
+ */
+ if (strcmp(topo_node_name(rnode), CHASSIS) != 0) {
+ if (ipmi_post_process(mod, rnode) != 0) {
+ topo_mod_dprintf(mod, "post processing of node %s=%d "
+ "failed!", topo_node_name(rnode),
+ topo_node_instance(rnode));
+ return (-1);
+ }
+ return (0);
+ }
+
+ if ((ihp = topo_mod_ipmi(mod)) == NULL)
+ return (0);
+
+ if (strcmp(name, POWERMODULE) == 0) {
+ data.ed_entity = IPMI_ET_POWER_DOMAIN;
+ } else if (strcmp(name, PSU) == 0) {
+ data.ed_entity = IPMI_ET_PSU;
+ } else if (strcmp(name, FANMODULE) == 0) {
+ data.ed_entity = IPMI_ET_COOLING_DOMAIN;
+ } else if (strcmp(name, FAN) == 0) {
+ data.ed_entity = IPMI_ET_FAN;
+ } else {
+ topo_mod_dprintf(mod, "unknown enumeration type '%s'",
+ name);
+ return (-1);
+ }
+
+ data.ed_mod = mod;
+ data.ed_pnode = rnode;
+ data.ed_name = name;
+ data.ed_instance = 0;
+ data.ed_label = NULL;
+
+ if ((ret = ipmi_entity_iter(ihp, ipmi_check_entity, &data)) != 0) {
+ /*
+ * We don't return failure if IPMI enumeration fails. This may
+ * be due to the SP being unavailable or an otherwise transient
+ * event.
+ */
+ if (ret < 0)
+ topo_mod_dprintf(mod,
+ "failed to enumerate entities: %s",
+ ipmi_errmsg(ihp));
+ else
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+ipmi_post_process(topo_mod_t *mod, tnode_t *tn)
+{
+ if (topo_method_register(mod, tn, ipmi_methods) != 0) {
+ topo_mod_dprintf(mod, "ipmi_post_process() failed: %s",
+ topo_mod_errmsg(mod));
+ return (1);
+ }
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+_topo_init(topo_mod_t *mod, topo_version_t version)
+{
+ if (getenv("TOPOIPMIDEBUG") != NULL)
+ topo_mod_setdebug(mod);
+
+ if (topo_mod_register(mod, &ipmi_info, TOPO_VERSION) != 0) {
+ topo_mod_dprintf(mod, "%s registration failed: %s\n",
+ DISK, topo_mod_errmsg(mod));
+ return (-1); /* mod errno already set */
+ }
+
+ topo_mod_dprintf(mod, "IPMI enumerator initialized\n");
+ return (0);
+}
+
+void
+_topo_fini(topo_mod_t *mod)
+{
+ topo_mod_unregister(mod);
+}
diff --git a/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_methods.c b/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_methods.c
new file mode 100644
index 0000000000..686c06d59f
--- /dev/null
+++ b/usr/src/lib/fm/topo/modules/common/ipmi/ipmi_methods.c
@@ -0,0 +1,208 @@
+/*
+ * 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 2008 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 <stdarg.h>
+#include <string.h>
+#include <strings.h>
+#include <libnvpair.h>
+#include <sys/types.h>
+#include <fm/topo_mod.h>
+
+#define BUFSZ 128
+
+static char *
+get_fmtstr(topo_mod_t *mod, nvlist_t *in)
+{
+ char *fmtstr;
+ nvlist_t *args;
+ int ret;
+
+ topo_mod_dprintf(mod, "get_fmtstr() called\n");
+
+ if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+ strerror(ret));
+ (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+ return (NULL);
+ }
+ if ((ret = nvlist_lookup_string(args, "format", &fmtstr)) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup 'format' arg (%s)\n",
+ strerror(ret));
+ (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL);
+ return (NULL);
+ }
+ return (fmtstr);
+}
+
+static int
+store_prop_val(topo_mod_t *mod, void *buf, char *propname, topo_type_t type,
+ nvlist_t **out)
+{
+ if (topo_mod_nvalloc(mod, out, NV_UNIQUE_NAME) != 0) {
+ topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
+ }
+ if (nvlist_add_string(*out, TOPO_PROP_VAL_NAME, propname) != 0) {
+ topo_mod_dprintf(mod, "Failed to set '%s'\n",
+ TOPO_PROP_VAL_NAME);
+ nvlist_free(*out);
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+ if (nvlist_add_uint32(*out, TOPO_PROP_VAL_TYPE, type)
+ != 0) {
+ topo_mod_dprintf(mod, "Failed to set '%s'\n",
+ TOPO_PROP_VAL_TYPE);
+ nvlist_free(*out);
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+ if (type == TOPO_TYPE_STRING) {
+ if (nvlist_add_string(*out, TOPO_PROP_VAL_VAL, (char *)buf)
+ != 0) {
+ topo_mod_dprintf(mod, "Failed to set '%s'\n",
+ TOPO_PROP_VAL_VAL);
+ nvlist_free(*out);
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+ } else if (type == TOPO_TYPE_FMRI)
+ if (nvlist_add_nvlist(*out, TOPO_PROP_VAL_VAL, (nvlist_t *)buf)
+ != 0) {
+ topo_mod_dprintf(mod, "Failed to set '%s'\n",
+ TOPO_PROP_VAL_VAL);
+ nvlist_free(*out);
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+ return (0);
+}
+
+/*
+ * This is a somewhat generic property method for labelling the PSU and fan
+ * FRU's that we're enumerating. It takes the following three arguments:
+ *
+ * format: a string containing a printf-like format with a two %d tokens
+ * for the cpu and dimm slot label numbers, which this method
+ * computes
+ *
+ * i.e.: Fan %d
+ *
+ * offset: a numeric offset that we'll number the FRU's from. This is to
+ * allow for the fact that some systems may number the FRU's
+ * from zero while others may start from one
+ */
+/* ARGSUSED */
+int
+ipmi_fru_label(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+ nvlist_t *in, nvlist_t **out)
+{
+ char *fmtstr, buf[BUFSZ];
+ int ret;
+ uint32_t offset;
+ nvlist_t *args;
+
+ topo_mod_dprintf(mod, "ipmi_fru_label() called\n");
+ if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+ strerror(ret));
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+ if ((ret = nvlist_lookup_uint32(args, "offset", &offset)) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup 'offset' arg (%s)\n",
+ strerror(ret));
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+
+ if ((fmtstr = get_fmtstr(mod, in)) == NULL) {
+ topo_mod_dprintf(mod, "Failed to retrieve 'format' arg\n");
+ /* topo errno already set */
+ return (-1);
+ }
+
+ /* LINTED: E_SEC_PRINTF_VAR_FMT */
+ (void) snprintf(buf, BUFSZ, fmtstr,
+ (topo_node_instance(node) + offset));
+
+ if (store_prop_val(mod, (void *)buf, "label", TOPO_TYPE_STRING, out)
+ != 0) {
+ topo_mod_dprintf(mod, "Failed to set label\n");
+ /* topo errno already set */
+ return (-1);
+ }
+
+ return (0);
+}
+/*
+ * This is a somewhat generic property method for attaching a FRU fmri onto
+ * a power supply or fan based on the assumption that the FRU will either be
+ * the fan/psu itself or the parent node.
+ *
+ * entity: either "self" or "parent"
+ */
+/* ARGSUSED */
+int
+ipmi_fru_fmri(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+ nvlist_t *in, nvlist_t **out)
+{
+ char *entity;
+ int ret, err;
+ nvlist_t *args, *fru;
+
+ topo_mod_dprintf(mod, "ipmi_fru_fmri() called\n");
+ if ((ret = nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &args)) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup 'args' list (%s)\n",
+ strerror(ret));
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+ if ((ret = nvlist_lookup_string(args, "entity", &entity)) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup 'entity' arg (%s)\n",
+ strerror(ret));
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+
+ if (strcasecmp(entity, "self") == 0) {
+ if (topo_node_resource(node, &fru, &err) != 0)
+ return (-1);
+ } else if (strcasecmp(entity, "parent") == 0) {
+ if (topo_node_resource(topo_node_parent(node), &fru, &err) != 0)
+ return (-1);
+ } else {
+ topo_mod_dprintf(mod, "Invalid 'entity' value\n");
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
+
+ if (store_prop_val(mod, (void *)fru, "FRU", TOPO_TYPE_FMRI, out) != 0) {
+ nvlist_free(fru);
+ topo_mod_dprintf(mod, "Failed to set FRU\n");
+ /* topo errno already set */
+ return (-1);
+ }
+
+ nvlist_free(fru);
+
+ return (0);
+}
diff --git a/usr/src/lib/libipmi/Makefile.com b/usr/src/lib/libipmi/Makefile.com
index efbcc96cf6..304c213600 100644
--- a/usr/src/lib/libipmi/Makefile.com
+++ b/usr/src/lib/libipmi/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -28,11 +28,16 @@ LIBRARY= libipmi.a
VERS= .1
OBJECTS= ipmi_bmc.o \
+ ipmi_entity.o \
ipmi_fru.o \
+ ipmi_hash.o \
+ ipmi_list.o \
ipmi_misc.o \
+ ipmi_sel.o \
ipmi_sdr.o \
ipmi_sensor.o \
ipmi_sunoem.o \
+ ipmi_tables.o \
ipmi_user.o \
ipmi_util.o \
libipmi.o
@@ -57,4 +62,7 @@ all: $(LIBS)
lint: lintcheck
+$(SRCDIR)/ipmi_tables.c: $(SRCDIR)/mktables.sh $(SRCDIR)/libipmi.h
+ sh $(SRCDIR)/mktables.sh $(SRCDIR)/libipmi.h > $@
+
include ../../Makefile.targ
diff --git a/usr/src/lib/libipmi/common/ipmi_entity.c b/usr/src/lib/libipmi/common/ipmi_entity.c
new file mode 100644
index 0000000000..0c379dd157
--- /dev/null
+++ b/usr/src/lib/libipmi/common/ipmi_entity.c
@@ -0,0 +1,754 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * IPMI entities are a strange beast. A reasonable assumption for those
+ * unfamiliar with the spec would be that there was a command to iterate over
+ * all entities, and a command to iterate over sensors associated with each
+ * entity. Instead, the entire IPMI world is derived from the SDR repository.
+ * Entities only exist in the sense that they are referenced by a SDR record.
+ *
+ * In addition, entities can be associated into groups, and determining entity
+ * presence is quite complicated. The IPMI spec dedicates an entire chapter
+ * (40) to the process of handling sensor associations.
+ *
+ * The above logic is implemented via the ipmi_entity_present() function. We
+ * make a first pass over the SDR repository to discover entities, creating
+ * entity groups and associating SDR records with the each.
+ *
+ * We don't currently support device-relative entities.
+ */
+
+#include <libipmi.h>
+#include <ipmi_impl.h>
+#include <stddef.h>
+
+typedef struct ipmi_entity_sdr {
+ ipmi_list_t ies_list;
+ const char *ies_name;
+ ipmi_sdr_t *ies_sdr;
+} ipmi_entity_sdr_t;
+
+typedef struct ipmi_entity_impl {
+ ipmi_list_t ie_list;
+ ipmi_entity_t ie_entity;
+ struct ipmi_entity_impl *ie_parent;
+ ipmi_hash_link_t ie_link;
+ ipmi_list_t ie_child_list;
+ ipmi_list_t ie_sdr_list;
+} ipmi_entity_impl_t;
+
+#define ENTITY_TO_IMPL(ep) \
+ ((ipmi_entity_impl_t *)((char *)(ep) - \
+ offsetof(ipmi_entity_impl_t, ie_entity)))
+
+static int
+ipmi_entity_add_assoc(ipmi_handle_t *ihp, ipmi_entity_impl_t *eip,
+ uint8_t id, uint8_t instance)
+{
+ ipmi_entity_impl_t *cp;
+ ipmi_entity_t search;
+
+ search.ie_type = id;
+ search.ie_instance = instance;
+
+ if ((cp = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) {
+ if ((cp = ipmi_zalloc(ihp,
+ sizeof (ipmi_entity_impl_t))) == NULL)
+ return (-1);
+
+ cp->ie_entity.ie_type = id;
+ cp->ie_entity.ie_instance = instance;
+
+ ipmi_hash_insert(ihp->ih_entities, cp);
+ }
+
+ if (cp->ie_parent != NULL) {
+ /*
+ * This should never happen. However, we want to be tolerant of
+ * pathologically broken IPMI implementations, so we ignore this
+ * error, and the first parent wins.
+ */
+ return (0);
+ }
+
+ cp->ie_parent = eip;
+ ipmi_list_append(&eip->ie_child_list, cp);
+ eip->ie_entity.ie_children++;
+
+ return (0);
+}
+
+static int
+ipmi_entity_sdr_parse(ipmi_sdr_t *sdrp, uint8_t *id, uint8_t *instance,
+ boolean_t *logical)
+{
+ switch (sdrp->is_type) {
+ case IPMI_SDR_TYPE_FULL_SENSOR:
+ {
+ ipmi_sdr_full_sensor_t *fsp =
+ (ipmi_sdr_full_sensor_t *)sdrp->is_record;
+ *id = fsp->is_fs_entity_id;
+ *instance = fsp->is_fs_entity_instance;
+ *logical = fsp->is_fs_entity_logical;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_COMPACT_SENSOR:
+ {
+ ipmi_sdr_compact_sensor_t *csp =
+ (ipmi_sdr_compact_sensor_t *)sdrp->is_record;
+ *id = csp->is_cs_entity_id;
+ *instance = csp->is_cs_entity_instance;
+ *logical = csp->is_cs_entity_logical;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_EVENT_ONLY:
+ {
+ ipmi_sdr_event_only_t *eop =
+ (ipmi_sdr_event_only_t *)sdrp->is_record;
+ *id = eop->is_eo_entity_id;
+ *instance = eop->is_eo_entity_instance;
+ *logical = eop->is_eo_entity_logical;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_ENTITY_ASSOCIATION:
+ {
+ ipmi_sdr_entity_association_t *eap =
+ (ipmi_sdr_entity_association_t *)sdrp->is_record;
+ *id = eap->is_ea_entity_id;
+ *instance = eap->is_ea_entity_instance;
+ *logical = B_TRUE;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_GENERIC_LOCATOR:
+ {
+ ipmi_sdr_generic_locator_t *glp =
+ (ipmi_sdr_generic_locator_t *)sdrp->is_record;
+ *id = glp->is_gl_entity;
+ *instance = glp->is_gl_instance;
+ *logical = B_FALSE;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_FRU_LOCATOR:
+ {
+ ipmi_sdr_fru_locator_t *flp =
+ (ipmi_sdr_fru_locator_t *)sdrp->is_record;
+ *id = flp->is_fl_entity;
+ *instance = flp->is_fl_instance;
+ *logical = B_FALSE;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR:
+ {
+ ipmi_sdr_management_locator_t *mlp =
+ (ipmi_sdr_management_locator_t *)sdrp->is_record;
+ *id = mlp->is_ml_entity_id;
+ *instance = mlp->is_ml_entity_instance;
+ *logical = B_FALSE;
+ break;
+ }
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * This function is responsible for gathering all entities, inserting them into
+ * the global hash, and establishing any associations.
+ */
+/*ARGSUSED*/
+static int
+ipmi_entity_visit(ipmi_handle_t *ihp, const char *name, ipmi_sdr_t *sdrp,
+ void *unused)
+{
+ uint8_t id, instance;
+ boolean_t logical;
+ ipmi_entity_t search;
+ ipmi_entity_impl_t *eip;
+ ipmi_entity_sdr_t *esp;
+
+ if (ipmi_entity_sdr_parse(sdrp, &id, &instance, &logical) != 0)
+ return (0);
+
+ search.ie_type = id;
+ search.ie_instance = instance;
+
+ if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) {
+ if ((eip = ipmi_zalloc(ihp,
+ sizeof (ipmi_entity_impl_t))) == NULL)
+ return (-1);
+
+ eip->ie_entity.ie_type = id;
+ eip->ie_entity.ie_instance = instance;
+
+ ipmi_hash_insert(ihp->ih_entities, eip);
+ }
+
+ eip->ie_entity.ie_logical |= logical;
+
+ if (sdrp->is_type == IPMI_SDR_TYPE_ENTITY_ASSOCIATION) {
+ uint8_t start, end;
+ uint8_t i, type;
+
+ ipmi_sdr_entity_association_t *eap =
+ (ipmi_sdr_entity_association_t *)sdrp->is_record;
+
+ if (eap->is_ea_range) {
+
+ type = eap->is_ea_sub[0].is_ea_sub_id;
+ start = eap->is_ea_sub[0].is_ea_sub_instance;
+ end = eap->is_ea_sub[1].is_ea_sub_instance;
+
+ if (type != 0) {
+ for (i = start; i <= end; i++) {
+ if (ipmi_entity_add_assoc(ihp, eip,
+ type, i) != 0)
+ return (-1);
+ }
+ }
+
+ type = eap->is_ea_sub[2].is_ea_sub_id;
+ start = eap->is_ea_sub[2].is_ea_sub_instance;
+ end = eap->is_ea_sub[3].is_ea_sub_instance;
+
+ if (type != 0) {
+ for (i = start; i <= end; i++) {
+ if (ipmi_entity_add_assoc(ihp, eip,
+ type, i) != 0)
+ return (-1);
+ }
+ }
+ } else {
+ for (i = 0; i < 4; i++) {
+ type = eap->is_ea_sub[i].is_ea_sub_id;
+ instance = eap->is_ea_sub[i].is_ea_sub_instance;
+
+ if (type == 0)
+ continue;
+
+ if (ipmi_entity_add_assoc(ihp, eip, type,
+ instance) != 0)
+ return (-1);
+ }
+ }
+ } else {
+ if ((esp = ipmi_zalloc(ihp,
+ sizeof (ipmi_entity_sdr_t))) == NULL)
+ return (-1);
+
+ esp->ies_sdr = sdrp;
+ esp->ies_name = name;
+ ipmi_list_append(&eip->ie_sdr_list, esp);
+ }
+
+ return (0);
+}
+
+/*
+ * Given a SDR record, return boolean values indicating whether the sensor
+ * indicates explicit presence.
+ *
+ * XXX this should really share code with entity_present()
+ */
+int
+ipmi_entity_present_sdr(ipmi_handle_t *ihp, ipmi_sdr_t *sdrp,
+ boolean_t *valp)
+{
+ uint16_t mask;
+ uint8_t number, sensor_type, reading_type;
+ ipmi_sdr_compact_sensor_t *csp;
+ ipmi_sdr_full_sensor_t *fsp;
+ ipmi_sensor_reading_t *srp;
+
+ switch (sdrp->is_type) {
+ case IPMI_SDR_TYPE_COMPACT_SENSOR:
+ csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record;
+ number = csp->is_cs_number;
+ sensor_type = csp->is_cs_type;
+ reading_type = csp->is_cs_reading_type;
+ break;
+
+ case IPMI_SDR_TYPE_FULL_SENSOR:
+ fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record;
+ number = fsp->is_fs_number;
+ sensor_type = fsp->is_fs_type;
+ reading_type = fsp->is_fs_reading_type;
+ break;
+
+ default:
+ *valp = B_FALSE;
+ return (0);
+ }
+
+ switch (reading_type) {
+ case IPMI_RT_PRESENT:
+ mask = IPMI_SR_PRESENT_ASSERT;
+ break;
+
+ case IPMI_RT_SPECIFIC:
+ switch (sensor_type) {
+ case IPMI_ST_PROCESSOR:
+ mask = IPMI_EV_PROCESSOR_PRESENT;
+ break;
+
+ case IPMI_ST_POWER_SUPPLY:
+ mask = IPMI_EV_POWER_SUPPLY_PRESENT;
+ break;
+
+ case IPMI_ST_MEMORY:
+ mask = IPMI_EV_MEMORY_PRESENT;
+ break;
+
+ case IPMI_ST_BAY:
+ mask = IPMI_EV_BAY_PRESENT;
+ break;
+
+ default:
+ *valp = B_FALSE;
+ return (0);
+ }
+ break;
+
+ default:
+ *valp = B_FALSE;
+ return (0);
+ }
+
+ /*
+ * If we've reached here, then we have a dedicated sensor that
+ * indicates presence.
+ */
+ if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) {
+ if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) {
+ *valp = B_FALSE;
+ return (0);
+ }
+
+ return (-1);
+ }
+
+ *valp = (srp->isr_state & mask) != 0;
+ return (0);
+}
+
+/*
+ * This function follows the procedure documented in section 40 of the spec.
+ * To quote the conclusion from section 40.2:
+ *
+ * Thus, the steps to detecting an Entity are:
+ *
+ * a) Scan the SDRs for sensors associated with the entity.
+ *
+ * b) If there is an active sensor that includes a presence bit, or the
+ * entity has an active Entity Presence sensor, use the sensor to
+ * determine the presence of the entity.
+ *
+ * c) Otherwise, check to see that there is at least one active sensor
+ * associated with the entity. Do this by doing 'Get Sensor Readings'
+ * to the sensors associated with the entity until a scanning sensor is
+ * found.
+ *
+ * d) If there are no active sensors directly associated with the entity,
+ * check the SDRs to see if the entity is a container entity in an
+ * entity-association. If so, check to see if any of the contained
+ * entities are present, if so, assume the container entity exists.
+ * Note that this may need to be iterative, since it's possible to have
+ * multi-level entity associations.
+ *
+ * e) If there are no active sensors for the entity, and the entity is not
+ * the container entity in an active entity-assocation, then the entity
+ * is present if (sic) there there is a FRU device for the entity, and
+ * the FRU device is present.
+ *
+ * It should not be considered an error if a FRU device locator record is
+ * present for a FRU device, but the FRU device is not there.
+ *
+ */
+int
+ipmi_entity_present(ipmi_handle_t *ihp, ipmi_entity_t *ep, boolean_t *valp)
+{
+ /* LINTED - alignment */
+ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep);
+ ipmi_entity_impl_t *cp;
+ ipmi_entity_sdr_t *esp;
+ ipmi_sdr_t *sdrp;
+ uint16_t mask;
+ uint8_t number, sensor_type, reading_type;
+ ipmi_sensor_reading_t *srp;
+ ipmi_sdr_compact_sensor_t *csp;
+ ipmi_sdr_full_sensor_t *fsp;
+ ipmi_sdr_fru_locator_t *frup;
+ char *frudata;
+
+ /*
+ * Search the sensors for a present sensor or a discrete sensor that
+ * indicates presence.
+ */
+ for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL;
+ esp = ipmi_list_next(esp)) {
+ sdrp = esp->ies_sdr;
+ switch (sdrp->is_type) {
+ case IPMI_SDR_TYPE_COMPACT_SENSOR:
+ csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record;
+ number = csp->is_cs_number;
+ sensor_type = csp->is_cs_type;
+ reading_type = csp->is_cs_reading_type;
+ break;
+
+ case IPMI_SDR_TYPE_FULL_SENSOR:
+ fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record;
+ number = fsp->is_fs_number;
+ sensor_type = fsp->is_fs_type;
+ reading_type = fsp->is_fs_reading_type;
+ break;
+
+ default:
+ continue;
+ }
+
+ switch (reading_type) {
+ case IPMI_RT_PRESENT:
+ mask = IPMI_SR_PRESENT_ASSERT;
+ break;
+
+ case IPMI_RT_SPECIFIC:
+ switch (sensor_type) {
+ case IPMI_ST_PROCESSOR:
+ mask = IPMI_EV_PROCESSOR_PRESENT;
+ break;
+
+ case IPMI_ST_POWER_SUPPLY:
+ mask = IPMI_EV_POWER_SUPPLY_PRESENT;
+ break;
+
+ case IPMI_ST_MEMORY:
+ mask = IPMI_EV_MEMORY_PRESENT;
+ break;
+
+ case IPMI_ST_BAY:
+ mask = IPMI_EV_BAY_PRESENT;
+ break;
+
+ default:
+ continue;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ /*
+ * If we've reached here, then we have a dedicated sensor that
+ * indicates presence.
+ */
+ if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) {
+ if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT) {
+ *valp = B_FALSE;
+ return (0);
+ }
+
+ return (-1);
+ }
+
+ *valp = (srp->isr_state & mask) != 0;
+ return (0);
+ }
+
+ /*
+ * No explicit presence sensor was found. See if there is at least one
+ * active sensor associated with the entity.
+ */
+ for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL;
+ esp = ipmi_list_next(esp)) {
+ sdrp = esp->ies_sdr;
+ switch (sdrp->is_type) {
+ case IPMI_SDR_TYPE_COMPACT_SENSOR:
+ csp = (ipmi_sdr_compact_sensor_t *)sdrp->is_record;
+ number = csp->is_cs_number;
+ break;
+
+ case IPMI_SDR_TYPE_FULL_SENSOR:
+ fsp = (ipmi_sdr_full_sensor_t *)sdrp->is_record;
+ number = fsp->is_fs_number;
+ break;
+
+ default:
+ continue;
+ }
+
+ if ((srp = ipmi_get_sensor_reading(ihp, number)) == NULL) {
+ if (ipmi_errno(ihp) == EIPMI_NOT_PRESENT)
+ continue;
+
+ return (-1);
+ }
+
+ if (srp->isr_scanning_enabled) {
+ *valp = B_TRUE;
+ return (0);
+ }
+ }
+
+ /*
+ * If this entity has children, then it is present if any of its
+ * children are present.
+ */
+ for (cp = ipmi_list_next(&eip->ie_child_list); cp != NULL;
+ cp = ipmi_list_next(cp)) {
+ if (ipmi_entity_present(ihp, &cp->ie_entity, valp) != 0)
+ return (-1);
+
+ if (*valp)
+ return (0);
+ }
+
+ /*
+ * If the FRU device is present, then the entity is present.
+ */
+ for (esp = ipmi_list_next(&eip->ie_sdr_list); esp != NULL;
+ esp = ipmi_list_next(esp)) {
+ sdrp = esp->ies_sdr;
+ if (sdrp->is_type != IPMI_SDR_TYPE_FRU_LOCATOR)
+ continue;
+
+ frup = (ipmi_sdr_fru_locator_t *)sdrp->is_record;
+ if (ipmi_fru_read(ihp, frup, &frudata) >= 0) {
+ ipmi_free(ihp, frudata);
+ *valp = B_TRUE;
+ return (0);
+ }
+
+ if (ipmi_errno(ihp) != EIPMI_NOT_PRESENT)
+ return (-1);
+ }
+
+ *valp = B_FALSE;
+ return (0);
+}
+
+static int
+ipmi_entity_refresh(ipmi_handle_t *ihp)
+{
+ if (ipmi_hash_first(ihp->ih_entities) != NULL &&
+ !ipmi_sdr_changed(ihp))
+ return (0);
+
+ if (ipmi_sdr_iter(ihp, ipmi_entity_visit, NULL) != 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+ipmi_entity_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *,
+ ipmi_entity_t *, void *), void *data)
+{
+ ipmi_entity_impl_t *eip;
+ int ret;
+
+ if (ipmi_entity_refresh(ihp) != 0)
+ return (-1);
+
+ for (eip = ipmi_hash_first(ihp->ih_entities); eip != NULL;
+ eip = ipmi_hash_next(ihp->ih_entities, eip)) {
+ if (eip->ie_parent != NULL)
+ continue;
+
+ if ((ret = func(ihp, &eip->ie_entity, data)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+int
+ipmi_entity_iter_sdr(ipmi_handle_t *ihp, ipmi_entity_t *ep,
+ int (*func)(ipmi_handle_t *, ipmi_entity_t *, const char *, ipmi_sdr_t *,
+ void *), void *data)
+{
+ /* LINTED - alignment */
+ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep);
+ ipmi_entity_sdr_t *isp;
+ int ret;
+
+ for (isp = ipmi_list_next(&eip->ie_sdr_list); isp != NULL;
+ isp = ipmi_list_next(isp)) {
+ if ((ret = func(ihp, ep, isp->ies_name,
+ isp->ies_sdr, data)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+int
+ipmi_entity_iter_children(ipmi_handle_t *ihp, ipmi_entity_t *ep,
+ int (*func)(ipmi_handle_t *, ipmi_entity_t *, void *), void *data)
+{
+ /* LINTED - alignment */
+ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep);
+ ipmi_entity_impl_t *cp;
+ int ret;
+
+ for (cp = ipmi_list_next(&eip->ie_child_list); cp != NULL;
+ cp = ipmi_list_next(cp)) {
+ if ((ret = func(ihp, &cp->ie_entity, data)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+ipmi_entity_t *
+ipmi_entity_parent(ipmi_handle_t *ihp, ipmi_entity_t *ep)
+{
+ /* LINTED - alignment */
+ ipmi_entity_impl_t *eip = ENTITY_TO_IMPL(ep);
+
+ if (eip->ie_parent == NULL) {
+ (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+ return (NULL);
+ }
+
+ return (&eip->ie_parent->ie_entity);
+}
+
+ipmi_entity_t *
+ipmi_entity_lookup(ipmi_handle_t *ihp, uint8_t type, uint8_t instance)
+{
+ ipmi_entity_t search;
+ ipmi_entity_impl_t *eip;
+
+ if (ipmi_entity_refresh(ihp) != 0)
+ return (NULL);
+
+ search.ie_type = type;
+ search.ie_instance = instance;
+
+ if ((eip = ipmi_hash_lookup(ihp->ih_entities, &search)) == NULL) {
+ (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+ return (NULL);
+ }
+
+ return (&eip->ie_entity);
+}
+
+ipmi_entity_t *
+ipmi_entity_lookup_sdr(ipmi_handle_t *ihp, const char *name)
+{
+ ipmi_sdr_t *sdrp;
+ uint8_t id, instance;
+ boolean_t logical;
+
+ if ((sdrp = ipmi_sdr_lookup(ihp, name)) == NULL)
+ return (NULL);
+
+ if (ipmi_entity_sdr_parse(sdrp, &id, &instance, &logical) != 0) {
+ (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT,
+ "SDR record %s has no associated entity", name);
+ return (NULL);
+ }
+
+ return (ipmi_entity_lookup(ihp, id, instance));
+}
+
+static const void *
+ipmi_entity_hash_convert(const void *p)
+{
+ const ipmi_entity_impl_t *eip = p;
+
+ return (&eip->ie_entity);
+}
+
+static ulong_t
+ipmi_entity_hash_compute(const void *p)
+{
+ const ipmi_entity_t *ep = p;
+
+ return ((ep->ie_type << 8) | ep->ie_instance);
+}
+
+static int
+ipmi_entity_hash_compare(const void *a, const void *b)
+{
+ const ipmi_entity_t *ea = a;
+ const ipmi_entity_t *eb = b;
+
+ if (ea->ie_type == eb->ie_type &&
+ ea->ie_instance == eb->ie_instance)
+ return (0);
+ else
+ return (-1);
+}
+
+int
+ipmi_entity_init(ipmi_handle_t *ihp)
+{
+ if ((ihp->ih_entities = ipmi_hash_create(ihp,
+ offsetof(ipmi_entity_impl_t, ie_link),
+ ipmi_entity_hash_convert,
+ ipmi_entity_hash_compute,
+ ipmi_entity_hash_compare)) == NULL)
+ return (-1);
+
+ return (0);
+}
+
+void
+ipmi_entity_clear(ipmi_handle_t *ihp)
+{
+ ipmi_entity_impl_t *eip;
+ ipmi_entity_sdr_t *esp;
+
+ while ((eip = ipmi_hash_first(ihp->ih_entities)) != NULL) {
+ while ((esp = ipmi_list_next(&eip->ie_sdr_list)) != NULL) {
+ ipmi_list_delete(&eip->ie_sdr_list, esp);
+ ipmi_free(ihp, esp);
+ }
+ ipmi_hash_remove(ihp->ih_entities, eip);
+ ipmi_free(ihp, eip);
+ }
+}
+
+void
+ipmi_entity_fini(ipmi_handle_t *ihp)
+{
+ if (ihp->ih_entities != NULL) {
+ ipmi_entity_clear(ihp);
+ ipmi_hash_destroy(ihp->ih_entities);
+ }
+}
diff --git a/usr/src/lib/libipmi/common/ipmi_fru.c b/usr/src/lib/libipmi/common/ipmi_fru.c
index eecc606942..072725ef8a 100644
--- a/usr/src/lib/libipmi/common/ipmi_fru.c
+++ b/usr/src/lib/libipmi/common/ipmi_fru.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -111,106 +111,6 @@ ipmi_fru_read(ipmi_handle_t *ihp, ipmi_sdr_fru_locator_t *fru_loc, char **buf)
return (sz);
}
-/*
- * See Sect 12 of the IPMI Platform Management FRU Information Storage
- * Definition (v1.1).
- *
- * The FRU Product Info Area contains a number of fields which encode
- * both the type and length of various name fields into a single byte.
- * The byte is a bitfield broken down as follows:
- *
- * bits descr
- * ---- -----
- * 7:6 encoding:
- * 11b = 8-bit ascii
- * 10b = 6-bit packed ascii
- * 5:0 length of data in bytes
- *
- * This function extracts the type and length and then copies the data into the
- * supplied buffer. If the type is 6-bit packed ASCII then it first converts
- * the string to an 8-bit ASCII string
- *
- * The function returns the length of the data.
- */
-static int
-ipmi_fru_decode_string(uint8_t typelen, char *data, char *buf)
-{
- int i, j = 0, chunks, leftovers;
- uint8_t tmp, lo, type, len;
-
- type = typelen >> 6;
- len = BITX(typelen, 5, 0);
-
- if (len == 0) {
- *buf = '\0';
- return (len);
- }
- /*
- * If the type is 8-bit ASCII, we can simply copy the string and return
- */
- if (type == 0x3) {
- (void) strncpy(buf, data, len);
- *(buf+len) = '\0';
- return (len);
- } else if (type == 0x1 || type == 0x0) {
- /*
- * Yuck - they either used BCD plus encoding, which we don't
- * currently handle, or they used an unspecified encoding type.
- * In these cases we'll set buf to an empty string. We still
- * need to return the length so that we can get to the next
- * record.
- */
- *buf = '\0';
- return (len);
- }
-
- /*
- * Otherwise, it's 6-bit packed ASCII, so we have to convert the
- * data first
- */
- chunks = len / 3;
- leftovers = len % 3;
-
- /*
- * First we decode the 6-bit string in chunks of 3 bytes as far as
- * possible
- */
- for (i = 0; i < chunks; i++) {
- tmp = BITX(*(data+j), 5, 0);
- *buf++ = (char)(tmp + 32);
-
- lo = BITX(*(data+j++), 7, 6);
- tmp = BITX(*(data+j), 3, 0);
- tmp = (tmp << 2) | lo;
- *buf++ = (char)(tmp + 32);
-
- lo = BITX(*(data+j++), 7, 4);
- tmp = BITX(*(data+j), 1, 0);
- tmp = (tmp << 4) | lo;
- *buf++ = (char)(tmp + 32);
-
- tmp = BITX(*(data+j++), 7, 2);
- *buf++ = (char)(tmp + 32);
- }
- switch (leftovers) {
- case 1:
- tmp = BITX(*(data+j), 5, 0);
- *buf++ = (char)(tmp + 32);
- break;
- case 2:
- tmp = BITX(*(data+j), 5, 0);
- *buf++ = (char)(tmp + 32);
-
- lo = BITX(*(data+j++), 7, 6);
- tmp = BITX(*(data+j), 3, 0);
- tmp = (tmp << 2) | lo;
- *buf++ = (char)(tmp + 32);
- break;
- }
- *buf = '\0';
- return (len);
-}
-
int
ipmi_fru_parse_product(ipmi_handle_t *ihp, char *fru_area,
ipmi_fru_prod_info_t *buf)
@@ -236,27 +136,36 @@ ipmi_fru_parse_product(ipmi_handle_t *ihp, char *fru_area,
tmp = fru_area + (fru_hdr.ifh_product_info_off * 8) + 3;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_manuf_name);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_manuf_name);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_product_name);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1,
+ buf->ifpi_product_name);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_part_number);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_part_number);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_product_version);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1,
+ buf->ifpi_product_version);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_product_serial);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1,
+ buf->ifpi_product_serial);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- (void) ipmi_fru_decode_string(typelen, tmp+1, buf->ifpi_asset_tag);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_asset_tag);
return (0);
}
@@ -293,19 +202,24 @@ ipmi_fru_parse_board(ipmi_handle_t *ihp, char *fru_area,
tmp += 3;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_manuf_name);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_manuf_name);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_board_name);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_board_name);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_product_serial);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1,
+ buf->ifbi_product_serial);
tmp += len + 1;
(void) memcpy(&typelen, tmp, sizeof (uint8_t));
- len = ipmi_fru_decode_string(typelen, tmp+1, buf->ifbi_part_number);
+ len = BITX(typelen, 4, 0);
+ ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_part_number);
return (0);
}
diff --git a/usr/src/lib/libipmi/common/ipmi_hash.c b/usr/src/lib/libipmi/common/ipmi_hash.c
new file mode 100644
index 0000000000..a58f18625f
--- /dev/null
+++ b/usr/src/lib/libipmi/common/ipmi_hash.c
@@ -0,0 +1,298 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <strings.h>
+
+#include <assert.h>
+#include <ipmi_impl.h>
+#include <string.h>
+#include <strings.h>
+
+/*
+ * The (prime) number 137 happens to have the nice property that -- when
+ * multiplied by two and added to 33 -- one gets a pretty long series of
+ * primes:
+ *
+ * 307, 647, 1327, 2687, 5407, 10847, 21727, 43487
+ *
+ * And beyond 43487, the numbers in the series have few factors or are prime.
+ * That is, one can have a prime number and roughly double it to get another
+ * prime number -- but the series starts at 137. A size of 137 buckets doesn't
+ * particularly accommodate small hash tables, but we note that 13 also yields
+ * a reasonable sequence when doubling it and adding 5:
+ *
+ * 13, 31, 67, 139, 283, 571
+ *
+ * So we start with this second sequence, crossing over to the first when
+ * the size is greater than 137. (And when reducing the size of the hash
+ * table, we cross back when the size gets below 67.)
+ */
+#define IPMI_HASHCROSSOVER 137
+#define IPMI_HASHCROSSUNDER 67
+#define IPMI_HASHMINSIZE 13
+
+static ulong_t
+ipmi_hash_double(ulong_t size)
+{
+ ulong_t nsize;
+
+ if (size < IPMI_HASHCROSSOVER) {
+ nsize = (size * 2) + 5;
+ return (nsize < IPMI_HASHCROSSOVER ? nsize :
+ IPMI_HASHCROSSOVER);
+ }
+
+ return ((size * 2) + 33);
+}
+
+static ulong_t
+ipmi_hash_half(ulong_t size)
+{
+ ulong_t nsize;
+
+ if (size > IPMI_HASHCROSSUNDER) {
+ nsize = (size - 33) / 2;
+ return (nsize > IPMI_HASHCROSSUNDER ? nsize :
+ IPMI_HASHCROSSUNDER);
+ }
+
+ nsize = (size - 5) / 2;
+
+ return (nsize > IPMI_HASHMINSIZE ? nsize : IPMI_HASHMINSIZE);
+}
+
+ipmi_hash_t *
+ipmi_hash_create(ipmi_handle_t *hp, size_t linkoffs,
+ const void *(*convert)(const void *elem),
+ ulong_t (*compute)(const void *key),
+ int (*compare)(const void *lkey, const void *rkey))
+{
+ ipmi_hash_t *ihp;
+
+ if ((ihp = ipmi_zalloc(hp, sizeof (ipmi_hash_t))) == NULL)
+ return (NULL);
+
+ ihp->ih_handle = hp;
+ ihp->ih_nbuckets = IPMI_HASHMINSIZE;
+ ihp->ih_linkoffs = linkoffs;
+ ihp->ih_convert = convert;
+ ihp->ih_compute = compute;
+ ihp->ih_compare = compare;
+
+ if ((ihp->ih_buckets = ipmi_zalloc(hp,
+ ihp->ih_nbuckets * sizeof (void *))) == NULL) {
+ ipmi_free(hp, ihp);
+ return (NULL);
+ }
+
+ return (ihp);
+}
+
+void
+ipmi_hash_destroy(ipmi_hash_t *ihp)
+{
+ if (ihp != NULL) {
+ ipmi_free(ihp->ih_handle, ihp->ih_buckets);
+ ipmi_free(ihp->ih_handle, ihp);
+ }
+}
+
+ulong_t
+ipmi_hash_strhash(const void *key)
+{
+ ulong_t g, h = 0;
+ const char *p;
+
+ for (p = key; *p != '\0'; p++) {
+ h = (h << 4) + *p;
+
+ if ((g = (h & 0xf0000000)) != 0) {
+ h ^= (g >> 24);
+ h ^= g;
+ }
+ }
+
+ return (h);
+}
+
+int
+ipmi_hash_strcmp(const void *lhs, const void *rhs)
+{
+ return (strcmp(lhs, rhs));
+}
+
+ulong_t
+ipmi_hash_ptrhash(const void *key)
+{
+ return (*((const uintptr_t *)key) >> 4);
+}
+
+int
+ipmi_hash_ptrcmp(const void *lhs, const void *rhs)
+{
+ const uintptr_t *l = lhs, *r = rhs;
+
+ return (*l == *r ? 0 : -1);
+}
+
+
+static ulong_t
+ipmi_hash_compute(ipmi_hash_t *ihp, const void *elem)
+{
+ return (ihp->ih_compute(ihp->ih_convert(elem)) % ihp->ih_nbuckets);
+}
+
+static void
+ipmi_hash_resize(ipmi_hash_t *ihp, ulong_t nsize)
+{
+ size_t osize = ihp->ih_nbuckets;
+ ipmi_handle_t *hp = ihp->ih_handle;
+ ipmi_hash_link_t *link, **nbuckets;
+ ulong_t idx, nidx;
+
+ assert(nsize >= IPMI_HASHMINSIZE);
+
+ if (nsize == osize)
+ return;
+
+ if ((nbuckets = ipmi_zalloc(hp, nsize * sizeof (void *))) == NULL) {
+ /*
+ * This routine can't fail, so we just eat the failure here.
+ * The consequences of this failing are only for performance;
+ * correctness is not affected by our inability to resize
+ * the hash table.
+ */
+ return;
+ }
+
+ ihp->ih_nbuckets = nsize;
+
+ for (idx = 0; idx < osize; idx++) {
+ while ((link = ihp->ih_buckets[idx]) != NULL) {
+ void *elem;
+
+ /*
+ * For every hash element, we need to remove it from
+ * this bucket, and rehash it given the new bucket
+ * size.
+ */
+ ihp->ih_buckets[idx] = link->ihl_next;
+ elem = (void *)((uintptr_t)link - ihp->ih_linkoffs);
+ nidx = ipmi_hash_compute(ihp, elem);
+
+ link->ihl_next = nbuckets[nidx];
+ nbuckets[nidx] = link;
+ }
+ }
+
+ ipmi_free(hp, ihp->ih_buckets);
+ ihp->ih_buckets = nbuckets;
+}
+
+void *
+ipmi_hash_lookup(ipmi_hash_t *ihp, const void *search)
+{
+ ulong_t idx = ihp->ih_compute(search) % ihp->ih_nbuckets;
+ ipmi_hash_link_t *hl;
+
+ for (hl = ihp->ih_buckets[idx]; hl != NULL; hl = hl->ihl_next) {
+ void *elem = (void *)((uintptr_t)hl - ihp->ih_linkoffs);
+
+ if (ihp->ih_compare(ihp->ih_convert(elem), search) == 0)
+ return (elem);
+ }
+
+ return (NULL);
+}
+
+void *
+ipmi_hash_first(ipmi_hash_t *ihp)
+{
+ void *link = ipmi_list_next(&(ihp)->ih_list);
+
+ if (link == NULL)
+ return (NULL);
+
+ return ((void *)((uintptr_t)link - ihp->ih_linkoffs));
+}
+
+void *
+ipmi_hash_next(ipmi_hash_t *ihp, void *elem)
+{
+ void *link = ipmi_list_next((uintptr_t)elem + ihp->ih_linkoffs);
+
+ if (link == NULL)
+ return (NULL);
+
+ return ((void *)((uintptr_t)link - ihp->ih_linkoffs));
+}
+
+void
+ipmi_hash_insert(ipmi_hash_t *ihp, void *elem)
+{
+ ipmi_hash_link_t *link = (void *)((uintptr_t)elem + ihp->ih_linkoffs);
+ ulong_t idx = ipmi_hash_compute(ihp, elem);
+
+ assert(ipmi_hash_lookup(ihp, ihp->ih_convert(elem)) == NULL);
+
+ link->ihl_next = ihp->ih_buckets[idx];
+ ihp->ih_buckets[idx] = link;
+
+ ipmi_list_append(&ihp->ih_list, link);
+
+ if (++ihp->ih_nelements > ihp->ih_nbuckets / 2)
+ ipmi_hash_resize(ihp, ipmi_hash_double(ihp->ih_nbuckets));
+}
+
+void
+ipmi_hash_remove(ipmi_hash_t *ihp, void *elem)
+{
+ ulong_t idx = ipmi_hash_compute(ihp, elem);
+ ipmi_hash_link_t *link = (void *)((uintptr_t)elem + ihp->ih_linkoffs);
+ ipmi_hash_link_t **hlp = &ihp->ih_buckets[idx];
+
+ for (; *hlp != NULL; hlp = &(*hlp)->ihl_next) {
+ if (*hlp == link)
+ break;
+ }
+
+ assert(*hlp != NULL);
+ *hlp = (*hlp)->ihl_next;
+
+ ipmi_list_delete(&ihp->ih_list, link);
+
+ assert(ihp->ih_nelements > 0);
+
+ if (--ihp->ih_nelements < ihp->ih_nbuckets / 4)
+ ipmi_hash_resize(ihp, ipmi_hash_half(ihp->ih_nbuckets));
+}
+
+size_t
+ipmi_hash_count(ipmi_hash_t *ihp)
+{
+ return (ihp->ih_nelements);
+}
diff --git a/usr/src/lib/libipmi/common/ipmi_impl.h b/usr/src/lib/libipmi/common/ipmi_impl.h
index 468629203c..340e647e25 100644
--- a/usr/src/lib/libipmi/common/ipmi_impl.h
+++ b/usr/src/lib/libipmi/common/ipmi_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,20 +29,33 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
+#include <libipmi.h>
#ifdef __cplusplus
extern "C" {
#endif
-struct ipmi_sdr_generic_locator;
-struct ipmi_sdr_fru_locator;
+typedef struct ipmi_list {
+ struct ipmi_list *l_prev;
+ struct ipmi_list *l_next;
+} ipmi_list_t;
-typedef struct ipmi_sdr_cache_ent {
- uint8_t isc_type;
- struct ipmi_sdr_generic_locator *isc_generic;
- struct ipmi_sdr_fru_locator *isc_fru;
- struct ipmi_sdr_cache_ent *isc_next;
-} ipmi_sdr_cache_ent_t;
+typedef struct ipmi_hash_link {
+ ipmi_list_t ihl_list; /* next on list of all elements */
+ struct ipmi_hash_link *ihl_next; /* next on this bucket */
+} ipmi_hash_link_t;
+
+typedef struct ipmi_hash {
+ ipmi_handle_t *ih_handle; /* handle to library state */
+ ipmi_hash_link_t **ih_buckets; /* array of buckets */
+ size_t ih_nbuckets; /* number of buckets */
+ size_t ih_nelements; /* number of elements */
+ ipmi_list_t ih_list; /* list of all elements */
+ size_t ih_linkoffs; /* offset of ipmi_hash_link in elem */
+ const void *(*ih_convert)(const void *); /* key conversion function */
+ ulong_t (*ih_compute)(const void *); /* hash computing function */
+ int (*ih_compare)(const void *, const void *); /* compare function */
+} ipmi_hash_t;
typedef struct ipmi_transport {
void * (*it_open)(struct ipmi_handle *);
@@ -58,12 +71,15 @@ struct ipmi_handle {
int ih_errno;
uint16_t ih_reservation;
int ih_retries;
- ipmi_sdr_cache_ent_t *ih_sdr_cache;
- ipmi_deviceid_t ih_deviceid;
- boolean_t ih_deviceid_valid;
+ ipmi_hash_t *ih_sdr_cache;
+ uint32_t ih_sdr_ts;
+ ipmi_deviceid_t *ih_deviceid;
+ uint32_t ih_deviceid_len;
+ char *ih_firmware_rev;
char ih_errmsg[1024];
char ih_errbuf[1024];
- ipmi_user_t *ih_users;
+ ipmi_list_t ih_users;
+ ipmi_hash_t *ih_entities;
};
/*
@@ -86,10 +102,79 @@ extern char *ipmi_strdup(ipmi_handle_t *, const char *);
extern ipmi_transport_t ipmi_transport_bmc;
/*
+ * Primitives for converting
+ */
+typedef struct ipmi_name_trans {
+ int int_value;
+ const char *int_name;
+} ipmi_name_trans_t;
+
+typedef struct ipmi_sensor_trans {
+ uint8_t ist_key;
+ uint8_t ist_value;
+ ipmi_name_trans_t ist_mask[1];
+} ipmi_sensor_trans_t;
+
+extern ipmi_name_trans_t ipmi_entity_table[];
+extern ipmi_name_trans_t ipmi_sensor_type_table[];
+extern ipmi_name_trans_t ipmi_reading_type_table[];
+extern ipmi_name_trans_t ipmi_errno_table[];
+extern ipmi_name_trans_t ipmi_threshold_state_table[];
+extern ipmi_sensor_trans_t ipmi_reading_state_table[];
+extern ipmi_sensor_trans_t ipmi_specific_state_table[];
+
+/*
* Miscellaneous routines
*/
+extern int ipmi_sdr_init(ipmi_handle_t *);
extern void ipmi_sdr_clear(ipmi_handle_t *);
+extern void ipmi_sdr_fini(ipmi_handle_t *);
extern void ipmi_user_clear(ipmi_handle_t *);
+extern int ipmi_entity_init(ipmi_handle_t *);
+extern void ipmi_entity_clear(ipmi_handle_t *);
+extern void ipmi_entity_fini(ipmi_handle_t *);
+
+extern int ipmi_convert_bcd(int);
+extern void ipmi_decode_string(uint8_t type, uint8_t len, char *data,
+ char *buf);
+extern boolean_t ipmi_is_sun_ilom(ipmi_deviceid_t *);
+
+/*
+ * List routines
+ */
+
+#define ipmi_list_prev(elem) ((void *)(((ipmi_list_t *)(elem))->l_prev))
+#define ipmi_list_next(elem) ((void *)(((ipmi_list_t *)(elem))->l_next))
+
+extern void ipmi_list_append(ipmi_list_t *, void *);
+extern void ipmi_list_prepend(ipmi_list_t *, void *);
+extern void ipmi_list_insert_before(ipmi_list_t *, void *, void *);
+extern void ipmi_list_insert_after(ipmi_list_t *, void *, void *);
+extern void ipmi_list_delete(ipmi_list_t *, void *);
+
+/*
+ * Hash table routines
+ */
+
+extern ipmi_hash_t *ipmi_hash_create(ipmi_handle_t *, size_t,
+ const void *(*convert)(const void *),
+ ulong_t (*compute)(const void *),
+ int (*compare)(const void *, const void *));
+
+extern void ipmi_hash_destroy(ipmi_hash_t *);
+extern void *ipmi_hash_lookup(ipmi_hash_t *, const void *);
+extern void ipmi_hash_insert(ipmi_hash_t *, void *);
+extern void ipmi_hash_remove(ipmi_hash_t *, void *);
+extern size_t ipmi_hash_count(ipmi_hash_t *);
+
+extern ulong_t ipmi_hash_strhash(const void *);
+extern int ipmi_hash_strcmp(const void *, const void *);
+
+extern ulong_t ipmi_hash_ptrhash(const void *);
+extern int ipmi_hash_ptrcmp(const void *, const void *);
+
+extern void *ipmi_hash_first(ipmi_hash_t *);
+extern void *ipmi_hash_next(ipmi_hash_t *, void *);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libipmi/common/ipmi_list.c b/usr/src/lib/libipmi/common/ipmi_list.c
new file mode 100644
index 0000000000..2c0cae20ab
--- /dev/null
+++ b/usr/src/lib/libipmi/common/ipmi_list.c
@@ -0,0 +1,128 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Embedded Linked Lists
+ *
+ * Simple doubly-linked list implementation. This implementation assumes that
+ * each list element contains an embedded ipmi_list_t (previous and next
+ * pointers), which is typically the first member of the element struct.
+ * An additional ipmi_list_t is used to store the head (l_next) and tail
+ * (l_prev) pointers. The current head and tail list elements have their
+ * previous and next pointers set to NULL, respectively.
+ */
+
+#include <assert.h>
+#include <ipmi_impl.h>
+
+void
+ipmi_list_append(ipmi_list_t *lp, void *new)
+{
+ ipmi_list_t *p = lp->l_prev; /* p = tail list element */
+ ipmi_list_t *q = new; /* q = new list element */
+
+ lp->l_prev = q;
+ q->l_prev = p;
+ q->l_next = NULL;
+
+ if (p != NULL) {
+ assert(p->l_next == NULL);
+ p->l_next = q;
+ } else {
+ assert(lp->l_next == NULL);
+ lp->l_next = q;
+ }
+}
+
+void
+ipmi_list_prepend(ipmi_list_t *lp, void *new)
+{
+ ipmi_list_t *p = new; /* p = new list element */
+ ipmi_list_t *q = lp->l_next; /* q = head list element */
+
+ lp->l_next = p;
+ p->l_prev = NULL;
+ p->l_next = q;
+
+ if (q != NULL) {
+ assert(q->l_prev == NULL);
+ q->l_prev = p;
+ } else {
+ assert(lp->l_prev == NULL);
+ lp->l_prev = p;
+ }
+}
+
+void
+ipmi_list_insert_before(ipmi_list_t *lp, void *before_me, void *new)
+{
+ ipmi_list_t *p = before_me;
+ ipmi_list_t *q = new;
+
+ if (p == NULL || p->l_prev == NULL) {
+ ipmi_list_prepend(lp, new);
+ return;
+ }
+
+ q->l_prev = p->l_prev;
+ q->l_next = p;
+ p->l_prev = q;
+ q->l_prev->l_next = q;
+}
+
+void
+ipmi_list_insert_after(ipmi_list_t *lp, void *after_me, void *new)
+{
+ ipmi_list_t *p = after_me;
+ ipmi_list_t *q = new;
+
+ if (p == NULL || p->l_next == NULL) {
+ ipmi_list_append(lp, new);
+ return;
+ }
+
+ q->l_next = p->l_next;
+ q->l_prev = p;
+ p->l_next = q;
+ q->l_next->l_prev = q;
+}
+
+void
+ipmi_list_delete(ipmi_list_t *lp, void *existing)
+{
+ ipmi_list_t *p = existing;
+
+ if (p->l_prev != NULL)
+ p->l_prev->l_next = p->l_next;
+ else
+ lp->l_next = p->l_next;
+
+ if (p->l_next != NULL)
+ p->l_next->l_prev = p->l_prev;
+ else
+ lp->l_prev = p->l_prev;
+}
diff --git a/usr/src/lib/libipmi/common/ipmi_misc.c b/usr/src/lib/libipmi/common/ipmi_misc.c
index e0acdf13e4..ce14a620a2 100644
--- a/usr/src/lib/libipmi/common/ipmi_misc.c
+++ b/usr/src/lib/libipmi/common/ipmi_misc.c
@@ -19,13 +19,14 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libipmi.h>
+#include <stdio.h>
#include <string.h>
#include "ipmi_impl.h"
@@ -35,8 +36,8 @@ ipmi_get_deviceid(ipmi_handle_t *ihp)
{
ipmi_cmd_t cmd, *resp;
- if (ihp->ih_deviceid_valid)
- return (&ihp->ih_deviceid);
+ if (ihp->ih_deviceid != NULL)
+ return (ihp->ih_deviceid);
cmd.ic_netfn = IPMI_NETFN_APP;
cmd.ic_lun = 0;
@@ -52,10 +53,67 @@ ipmi_get_deviceid(ipmi_handle_t *ihp)
return (NULL);
}
- (void) memcpy(&ihp->ih_deviceid, resp->ic_data,
- sizeof (ipmi_deviceid_t));
- ihp->ih_deviceid.id_product = LE_16(ihp->ih_deviceid.id_product);
- ihp->ih_deviceid_valid = B_TRUE;
+ /*
+ * The devid response data may include additional data beyond the end of
+ * the normal structure, so we copy the entire response.
+ */
+ if ((ihp->ih_deviceid = ipmi_alloc(ihp, resp->ic_dlen)) == NULL)
+ return (NULL);
+
+ (void) memcpy(ihp->ih_deviceid, resp->ic_data, resp->ic_dlen);
+ ihp->ih_deviceid->id_product = LE_16(ihp->ih_deviceid->id_product);
+ ihp->ih_deviceid_len = resp->ic_dlen;
+
+ return (ihp->ih_deviceid);
+}
+
+/*
+ * Returns the firmware revision as a string. This does the work of converting
+ * the deviceid data into a human readable string (decoding the BCD values).
+ * It also encodes the fact that Sun ILOM includes the additional micro revision
+ * at the end of the deviceid information.
+ */
+const char *
+ipmi_firmware_version(ipmi_handle_t *ihp)
+{
+ ipmi_deviceid_t *dp;
+ uint8_t *auxrev;
+ size_t len;
+ char rev[128];
+ int i;
+
+ if (ihp->ih_firmware_rev != NULL)
+ return (ihp->ih_firmware_rev);
+
+ if ((dp = ipmi_get_deviceid(ihp)) == NULL)
+ return (NULL);
+
+ /*
+ * Start with the major an minor revision numbers
+ */
+ (void) snprintf(rev, sizeof (rev), "%d.%d", dp->id_firm_major,
+ ipmi_convert_bcd(dp->id_firm_minor));
+
+ if (ipmi_is_sun_ilom(dp) &&
+ ihp->ih_deviceid_len >= sizeof (ipmi_deviceid_t) + 4) {
+ /*
+ * With Sun ILOM we have the micro revision at the end of the
+ * deviceid. The first two bytes of the aux revision field are
+ * the platform version and release version.
+ */
+ auxrev = (uint8_t *)dp + sizeof (ipmi_deviceid_t);
+ for (i = 0; i < 2; i++) {
+ if (auxrev[i] == 0)
+ continue;
+
+ len = strlen(rev);
+ (void) snprintf(rev + len, sizeof (rev) - len, ".%u",
+ auxrev[i]);
+ }
+ }
+
+ if ((ihp->ih_firmware_rev = ipmi_strdup(ihp, rev)) == NULL)
+ return (NULL);
- return (&ihp->ih_deviceid);
+ return (ihp->ih_firmware_rev);
}
diff --git a/usr/src/lib/libipmi/common/ipmi_sdr.c b/usr/src/lib/libipmi/common/ipmi_sdr.c
index da8e1c500e..e5373d0685 100644
--- a/usr/src/lib/libipmi/common/ipmi_sdr.c
+++ b/usr/src/lib/libipmi/common/ipmi_sdr.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -29,9 +29,16 @@
#include <libipmi.h>
#include <stddef.h>
#include <string.h>
+#include <strings.h>
#include "ipmi_impl.h"
+typedef struct ipmi_sdr_cache_ent {
+ char *isc_name;
+ struct ipmi_sdr *isc_sdr;
+ ipmi_hash_link_t isc_link;
+} ipmi_sdr_cache_ent_t;
+
typedef struct ipmi_cmd_get_sdr {
uint16_t ic_gs_resid;
uint16_t ic_gs_recid;
@@ -45,6 +52,34 @@ typedef struct ipmi_rsp_get_sdr {
} ipmi_rsp_get_sdr_t;
/*
+ * "Get SDR Repostiory Info" command.
+ */
+ipmi_sdr_info_t *
+ipmi_sdr_get_info(ipmi_handle_t *ihp)
+{
+ ipmi_cmd_t cmd, *rsp;
+ ipmi_sdr_info_t *sip;
+
+ cmd.ic_netfn = IPMI_NETFN_STORAGE;
+ cmd.ic_lun = 0;
+ cmd.ic_cmd = IPMI_CMD_GET_SDR_INFO;
+ cmd.ic_dlen = 0;
+ cmd.ic_data = NULL;
+
+ if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
+ return (NULL);
+
+ sip = rsp->ic_data;
+
+ sip->isi_record_count = LE_16(sip->isi_record_count);
+ sip->isi_free_space = LE_16(sip->isi_free_space);
+ sip->isi_add_ts = LE_32(sip->isi_add_ts);
+ sip->isi_erase_ts = LE_32(sip->isi_erase_ts);
+
+ return (sip);
+}
+
+/*
* Issue the "Reserve SDR Repository" command.
*/
static int
@@ -66,19 +101,47 @@ ipmi_sdr_reserve_repository(ipmi_handle_t *ihp)
}
/*
+ * Returns B_TRUE if the repository has changed since the cached copy was last
+ * referenced.
+ */
+boolean_t
+ipmi_sdr_changed(ipmi_handle_t *ihp)
+{
+ ipmi_sdr_info_t *sip;
+
+ if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
+ return (B_TRUE);
+
+ return (sip->isi_add_ts > ihp->ih_sdr_ts ||
+ sip->isi_erase_ts > ihp->ih_sdr_ts ||
+ ipmi_hash_first(ihp->ih_sdr_cache) == NULL);
+}
+
+/*
* Refresh the cache of sensor data records.
*/
-static int
+int
ipmi_sdr_refresh(ipmi_handle_t *ihp)
{
- size_t len;
uint16_t id;
ipmi_sdr_t *sdr;
ipmi_sdr_cache_ent_t *ent;
- ipmi_sdr_generic_locator_t *gen_src, *gen_dst;
- ipmi_sdr_fru_locator_t *fru_src, *fru_dst;
+ size_t namelen, len;
+ uint8_t type;
+ char *name;
+ ipmi_sdr_info_t *sip;
+
+ if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
+ return (-1);
+
+ if (sip->isi_add_ts <= ihp->ih_sdr_ts &&
+ sip->isi_erase_ts <= ihp->ih_sdr_ts &&
+ ipmi_hash_first(ihp->ih_sdr_cache) != NULL)
+ return (0);
ipmi_sdr_clear(ihp);
+ ipmi_entity_clear(ihp);
+ ihp->ih_sdr_ts = MAX(sip->isi_add_ts, sip->isi_erase_ts);
/*
* Iterate over all existing SDRs and add them to the cache.
@@ -89,67 +152,196 @@ ipmi_sdr_refresh(ipmi_handle_t *ihp)
return (-1);
/*
- * We currently only understand FRU and generic device records.
+ * Extract the name from the record-specific data.
*/
- if (sdr->is_type != IPMI_SDR_TYPE_GENERIC_LOCATOR &&
- sdr->is_type != IPMI_SDR_TYPE_FRU_LOCATOR)
- continue;
-
- /*
- * Create a copy of the SDR-specific data.
- */
- gen_dst = NULL;
- fru_dst = NULL;
switch (sdr->is_type) {
case IPMI_SDR_TYPE_GENERIC_LOCATOR:
- gen_src = (ipmi_sdr_generic_locator_t *)sdr->is_record;
- len = offsetof(ipmi_sdr_generic_locator_t,
- is_gl_idstring) + gen_src->is_gl_idlen + 1;
- if ((gen_dst = ipmi_alloc(ihp, len)) == NULL)
- return (-1);
- (void) memcpy(gen_dst, gen_src, len - 1);
- ((char *)gen_dst)[len - 1] = '\0';
- break;
+ {
+ ipmi_sdr_generic_locator_t *glp =
+ (ipmi_sdr_generic_locator_t *)
+ sdr->is_record;
+ namelen = glp->is_gl_idlen;
+ type = glp->is_gl_idtype;
+ name = glp->is_gl_idstring;
+ break;
+ }
case IPMI_SDR_TYPE_FRU_LOCATOR:
- fru_src = (ipmi_sdr_fru_locator_t *)sdr->is_record;
- len = offsetof(ipmi_sdr_fru_locator_t,
- is_fl_idstring) + fru_src->is_fl_idlen + 1;
- if ((fru_dst = ipmi_alloc(ihp, len)) == NULL)
- return (-1);
- (void) memcpy(fru_dst, fru_src, len - 1);
- ((char *)fru_dst)[len - 1] = '\0';
- break;
+ {
+ ipmi_sdr_fru_locator_t *flp =
+ (ipmi_sdr_fru_locator_t *)
+ sdr->is_record;
+ namelen = flp->is_fl_idlen;
+ name = flp->is_fl_idstring;
+ type = flp->is_fl_idtype;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_COMPACT_SENSOR:
+ {
+ ipmi_sdr_compact_sensor_t *csp =
+ (ipmi_sdr_compact_sensor_t *)
+ sdr->is_record;
+ namelen = csp->is_cs_idlen;
+ type = csp->is_cs_idtype;
+ name = csp->is_cs_idstring;
+
+ csp->is_cs_assert_mask =
+ LE_16(csp->is_cs_assert_mask);
+ csp->is_cs_deassert_mask =
+ LE_16(csp->is_cs_deassert_mask);
+ csp->is_cs_reading_mask =
+ LE_16(csp->is_cs_reading_mask);
+ break;
+ }
+
+ case IPMI_SDR_TYPE_FULL_SENSOR:
+ {
+ ipmi_sdr_full_sensor_t *csp =
+ (ipmi_sdr_full_sensor_t *)
+ sdr->is_record;
+ namelen = csp->is_fs_idlen;
+ type = csp->is_fs_idtype;
+ name = csp->is_fs_idstring;
+
+ csp->is_fs_assert_mask =
+ LE_16(csp->is_fs_assert_mask);
+ csp->is_fs_deassert_mask =
+ LE_16(csp->is_fs_deassert_mask);
+ csp->is_fs_reading_mask =
+ LE_16(csp->is_fs_reading_mask);
+ break;
+ }
+
+ case IPMI_SDR_TYPE_EVENT_ONLY:
+ {
+ ipmi_sdr_event_only_t *esp =
+ (ipmi_sdr_event_only_t *)
+ sdr->is_record;
+ namelen = esp->is_eo_idlen;
+ type = esp->is_eo_idtype;
+ name = esp->is_eo_idstring;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR:
+ {
+ ipmi_sdr_management_locator_t *msp =
+ (ipmi_sdr_management_locator_t *)
+ sdr->is_record;
+ namelen = msp->is_ml_idlen;
+ type = msp->is_ml_idtype;
+ name = msp->is_ml_idstring;
+ break;
+ }
+
+ case IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION:
+ {
+ ipmi_sdr_management_confirmation_t *mcp =
+ (ipmi_sdr_management_confirmation_t *)
+ sdr->is_record;
+ name = NULL;
+ mcp->is_mc_product = LE_16(mcp->is_mc_product);
+ break;
+ }
+
+ default:
+ name = NULL;
}
- if ((ent = ipmi_alloc(ihp,
- sizeof (ipmi_sdr_cache_ent_t))) == NULL) {
- ipmi_free(ihp, gen_dst);
- ipmi_free(ihp, fru_dst);
+ if ((ent = ipmi_zalloc(ihp,
+ sizeof (ipmi_sdr_cache_ent_t))) == NULL)
return (-1);
+
+ len = sdr->is_length + offsetof(ipmi_sdr_t, is_record);
+ if ((ent->isc_sdr = ipmi_alloc(ihp, len)) == NULL) {
+ ipmi_free(ihp, ent);
+ return (-1);
+ }
+ bcopy(sdr, ent->isc_sdr, len);
+
+ if (name != NULL) {
+ if ((ent->isc_name = ipmi_alloc(ihp, namelen + 1)) ==
+ NULL) {
+ ipmi_free(ihp, ent->isc_sdr);
+ ipmi_free(ihp, ent);
+ }
+
+ ipmi_decode_string(type, namelen, name, ent->isc_name);
}
- ent->isc_generic = gen_dst;
- ent->isc_fru = fru_dst;
- ent->isc_next = ihp->ih_sdr_cache;
- ent->isc_type = sdr->is_type;
- ihp->ih_sdr_cache = ent;
+ ipmi_hash_insert(ihp->ih_sdr_cache, ent);
}
return (0);
}
+/*
+ * Hash routines. We allow lookup by name, but since not all entries have
+ * names, we fall back to the entry pointer, which is guaranteed to be unique.
+ * The end result is that entities without names cannot be looked up, but will
+ * show up during iteration.
+ */
+static const void *
+ipmi_sdr_hash_convert(const void *p)
+{
+ return (p);
+}
+
+static ulong_t
+ipmi_sdr_hash_compute(const void *p)
+{
+ const ipmi_sdr_cache_ent_t *ep = p;
+
+ if (ep->isc_name)
+ return (ipmi_hash_strhash(ep->isc_name));
+ else
+ return (ipmi_hash_ptrhash(ep));
+}
+
+static int
+ipmi_sdr_hash_compare(const void *a, const void *b)
+{
+ const ipmi_sdr_cache_ent_t *ap = a;
+ const ipmi_sdr_cache_ent_t *bp = b;
+
+ if (ap->isc_name == NULL || bp->isc_name == NULL)
+ return (-1);
+
+ return (strcmp(ap->isc_name, bp->isc_name));
+}
+
+int
+ipmi_sdr_init(ipmi_handle_t *ihp)
+{
+ if ((ihp->ih_sdr_cache = ipmi_hash_create(ihp,
+ offsetof(ipmi_sdr_cache_ent_t, isc_link),
+ ipmi_sdr_hash_convert, ipmi_sdr_hash_compute,
+ ipmi_sdr_hash_compare)) == NULL)
+ return (-1);
+
+ return (0);
+}
+
void
ipmi_sdr_clear(ipmi_handle_t *ihp)
{
- ipmi_sdr_cache_ent_t *ent, *next;
+ ipmi_sdr_cache_ent_t *ent;
- while ((ent = ihp->ih_sdr_cache) != NULL) {
- next = ent->isc_next;
- ipmi_free(ihp, ent->isc_generic);
- ipmi_free(ihp, ent->isc_fru);
+ while ((ent = ipmi_hash_first(ihp->ih_sdr_cache)) != NULL) {
+ ipmi_hash_remove(ihp->ih_sdr_cache, ent);
+ ipmi_free(ihp, ent->isc_sdr);
+ ipmi_free(ihp, ent->isc_name);
ipmi_free(ihp, ent);
- ihp->ih_sdr_cache = next;
+ }
+}
+
+void
+ipmi_sdr_fini(ipmi_handle_t *ihp)
+{
+ if (ihp->ih_sdr_cache != NULL) {
+ ipmi_sdr_clear(ihp);
+ ipmi_hash_destroy(ihp->ih_sdr_cache);
}
}
@@ -173,14 +365,15 @@ ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next)
cmd.ic_data = &req;
for (i = 0; i < ihp->ih_retries; i++) {
- if ((rsp = ipmi_send(ihp, &cmd)) == NULL) {
- if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION)
- return (NULL);
+ if ((rsp = ipmi_send(ihp, &cmd)) != NULL)
+ break;
- if (ipmi_sdr_reserve_repository(ihp) != 0)
- return (NULL);
- req.ic_gs_resid = ihp->ih_reservation;
- }
+ if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION)
+ return (NULL);
+
+ if (ipmi_sdr_reserve_repository(ihp) != 0)
+ return (NULL);
+ req.ic_gs_resid = ihp->ih_reservation;
}
if (rsp == NULL)
@@ -197,44 +390,85 @@ ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next)
return ((ipmi_sdr_t *)sdr->ir_gs_record);
}
-ipmi_sdr_fru_locator_t *
-ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr)
+int
+ipmi_sdr_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *,
+ const char *, ipmi_sdr_t *, void *), void *data)
{
ipmi_sdr_cache_ent_t *ent;
+ int ret;
- if (ihp->ih_sdr_cache == NULL &&
+ if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
ipmi_sdr_refresh(ihp) != 0)
- return (NULL);
-
- for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) {
- if (ent->isc_type != IPMI_SDR_TYPE_FRU_LOCATOR)
- continue;
+ return (-1);
- if (strcmp(ent->isc_fru->is_fl_idstring, idstr) == 0)
- return (ent->isc_fru);
+ for (ent = ipmi_hash_first(ihp->ih_sdr_cache); ent != NULL;
+ ent = ipmi_hash_next(ihp->ih_sdr_cache, ent)) {
+ if ((ret = func(ihp, ent->isc_name, ent->isc_sdr, data)) != 0)
+ return (ret);
}
- (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
- return (NULL);
+ return (0);
}
-ipmi_sdr_generic_locator_t *
-ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr)
+ipmi_sdr_t *
+ipmi_sdr_lookup(ipmi_handle_t *ihp, const char *idstr)
{
- ipmi_sdr_cache_ent_t *ent;
+ ipmi_sdr_cache_ent_t *ent, search;
- if (ihp->ih_sdr_cache == NULL &&
+ if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
ipmi_sdr_refresh(ihp) != 0)
return (NULL);
- for (ent = ihp->ih_sdr_cache; ent != NULL; ent = ent->isc_next) {
- if (ent->isc_type != IPMI_SDR_TYPE_GENERIC_LOCATOR)
- continue;
+ search.isc_name = (char *)idstr;
+ if ((ent = ipmi_hash_lookup(ihp->ih_sdr_cache, &search)) == NULL) {
+ (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+ return (NULL);
+ }
+
+ return (ent->isc_sdr);
+}
+
+static void *
+ipmi_sdr_lookup_common(ipmi_handle_t *ihp, const char *idstr,
+ uint8_t type)
+{
+ ipmi_sdr_t *sdrp;
- if (strcmp(ent->isc_generic->is_gl_idstring, idstr) == 0)
- return (ent->isc_generic);
+ if ((sdrp = ipmi_sdr_lookup(ihp, idstr)) == NULL)
+ return (NULL);
+
+ if (sdrp->is_type != type) {
+ (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
+ return (NULL);
}
- (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
- return (NULL);
+ return (sdrp->is_record);
+}
+
+ipmi_sdr_fru_locator_t *
+ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr)
+{
+ return (ipmi_sdr_lookup_common(ihp, idstr,
+ IPMI_SDR_TYPE_FRU_LOCATOR));
+}
+
+ipmi_sdr_generic_locator_t *
+ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr)
+{
+ return (ipmi_sdr_lookup_common(ihp, idstr,
+ IPMI_SDR_TYPE_GENERIC_LOCATOR));
+}
+
+ipmi_sdr_compact_sensor_t *
+ipmi_sdr_lookup_compact_sensor(ipmi_handle_t *ihp, const char *idstr)
+{
+ return (ipmi_sdr_lookup_common(ihp, idstr,
+ IPMI_SDR_TYPE_COMPACT_SENSOR));
+}
+
+ipmi_sdr_full_sensor_t *
+ipmi_sdr_lookup_full_sensor(ipmi_handle_t *ihp, const char *idstr)
+{
+ return (ipmi_sdr_lookup_common(ihp, idstr,
+ IPMI_SDR_TYPE_FULL_SENSOR));
}
diff --git a/usr/src/lib/libipmi/common/ipmi_sel.c b/usr/src/lib/libipmi/common/ipmi_sel.c
new file mode 100644
index 0000000000..2cdabfea72
--- /dev/null
+++ b/usr/src/lib/libipmi/common/ipmi_sel.c
@@ -0,0 +1,196 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <libipmi.h>
+#include <stddef.h>
+#include <string.h>
+#include <strings.h>
+
+#include "ipmi_impl.h"
+
+/*
+ * 31.2 Get SEL Info Command.
+ */
+ipmi_sel_info_t *
+ipmi_sel_get_info(ipmi_handle_t *ihp)
+{
+ ipmi_cmd_t cmd, *rsp;
+ ipmi_sel_info_t *ip;
+
+ cmd.ic_netfn = IPMI_NETFN_STORAGE;
+ cmd.ic_lun = 0;
+ cmd.ic_cmd = IPMI_CMD_GET_SEL_INFO;
+ cmd.ic_dlen = 0;
+ cmd.ic_data = NULL;
+
+ if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
+ return (NULL);
+
+ ip = (ipmi_sel_info_t *)rsp->ic_data;
+
+ ip->isel_entries = LE_16(ip->isel_entries);
+ ip->isel_free = LE_16(ip->isel_free);
+ ip->isel_add_ts = LE_32(ip->isel_add_ts);
+ ip->isel_erase_ts = LE_32(ip->isel_erase_ts);
+
+ return (ip);
+}
+
+typedef struct ipmi_cmd_get_sel_entry {
+ uint16_t ic_sel_ent_resid;
+ uint16_t ic_sel_ent_recid;
+ uint8_t ic_sel_ent_offset;
+ uint8_t ic_sel_ent_bytes;
+} ipmi_cmd_get_sel_entry_t;
+
+ipmi_sel_event_t *
+ipmi_sel_get_entry(ipmi_handle_t *ihp, uint16_t id)
+{
+ ipmi_cmd_t cmd, *rsp;
+ ipmi_sel_event_t *evp;
+ ipmi_cmd_get_sel_entry_t data;
+
+ data.ic_sel_ent_resid = 0;
+ data.ic_sel_ent_recid = LE_16(id);
+ data.ic_sel_ent_offset = 0;
+ data.ic_sel_ent_bytes = 0xFF;
+
+ cmd.ic_netfn = IPMI_NETFN_STORAGE;
+ cmd.ic_lun = 0;
+ cmd.ic_cmd = IPMI_CMD_GET_SEL_ENTRY;
+ cmd.ic_dlen = sizeof (data);
+ cmd.ic_data = &data;
+
+ if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
+ return (NULL);
+
+ if (rsp->ic_dlen < sizeof (ipmi_sel_event_t)) {
+ (void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
+ return (NULL);
+ }
+
+ evp = (ipmi_sel_event_t *)rsp->ic_data;
+
+ evp->isel_ev_next = LE_16(evp->isel_ev_next);
+ evp->isel_ev_recid = LE_16(evp->isel_ev_recid);
+ if (evp->isel_ev_rectype == IPMI_SEL_SYSTEM ||
+ evp->isel_ev_rectype >= IPMI_SEL_OEM_LO)
+ evp->isel_ev_ts = LE_32(evp->isel_ev_ts);
+
+ return (evp);
+}
+
+/*
+ * SEL time management. For the purposes of libipmi we assume that the SDR
+ * repository and SEL share the same timebase, even though the spec allows for
+ * separate time sources. Hence no function to set the SDR repository time.
+ */
+int
+ipmi_sel_get_time(ipmi_handle_t *ihp, uint32_t *tp)
+{
+ ipmi_cmd_t cmd, *rsp;
+
+ cmd.ic_netfn = IPMI_NETFN_STORAGE;
+ cmd.ic_lun = 0;
+ cmd.ic_cmd = IPMI_CMD_GET_SEL_TIME;
+ cmd.ic_dlen = 0;
+ cmd.ic_data = NULL;
+
+ if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
+ return (-1);
+
+ if (rsp->ic_dlen < sizeof (uint32_t))
+ return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+
+ *tp = LE_32(*((uint32_t *)rsp->ic_data));
+
+ return (0);
+}
+
+int
+ipmi_sel_set_time(ipmi_handle_t *ihp, uint32_t t)
+{
+ ipmi_cmd_t cmd;
+
+ t = LE_32(t);
+
+ cmd.ic_netfn = IPMI_NETFN_STORAGE;
+ cmd.ic_lun = 0;
+ cmd.ic_cmd = IPMI_CMD_SET_SEL_TIME;
+ cmd.ic_dlen = sizeof (t);
+ cmd.ic_data = &t;
+
+ if (ipmi_send(ihp, &cmd) == NULL)
+ return (-1);
+
+ return (0);
+}
+
+int
+ipmi_sel_get_utc_offset(ipmi_handle_t *ihp, int *offp)
+{
+ ipmi_cmd_t cmd, *rsp;
+ int16_t off16;
+
+ cmd.ic_netfn = IPMI_NETFN_STORAGE;
+ cmd.ic_lun = 0;
+ cmd.ic_cmd = IPMI_CMD_GET_SEL_UTC_OFFSET;
+ cmd.ic_dlen = 0;
+ cmd.ic_data = NULL;
+
+ if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
+ return (-1);
+
+ if (rsp->ic_dlen < sizeof (uint16_t))
+ return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+
+ off16 = LE_16(*((int16_t *)rsp->ic_data));
+ *offp = off16;
+
+ return (0);
+}
+
+int
+ipmi_sel_set_utc_offset(ipmi_handle_t *ihp, int off)
+{
+ ipmi_cmd_t cmd;
+ int16_t off16 = off;
+
+ off16 = LE_16(off16);
+
+ cmd.ic_netfn = IPMI_NETFN_STORAGE;
+ cmd.ic_lun = 0;
+ cmd.ic_cmd = IPMI_CMD_SET_SEL_UTC_OFFSET;
+ cmd.ic_dlen = sizeof (off16);
+ cmd.ic_data = &off16;
+
+ if (ipmi_send(ihp, &cmd) == NULL)
+ return (-1);
+
+ return (0);
+}
diff --git a/usr/src/lib/libipmi/common/ipmi_sunoem.c b/usr/src/lib/libipmi/common/ipmi_sunoem.c
index 2781d4f824..a1ed544456 100644
--- a/usr/src/lib/libipmi/common/ipmi_sunoem.c
+++ b/usr/src/lib/libipmi/common/ipmi_sunoem.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -66,6 +66,13 @@ typedef struct ipmi_cmd_sunoem_led_get {
#define IPMI_SUNOEM_LED_TYPE_LOCATE 3
#define IPMI_SUNOEM_LED_TYPE_ANY 0xFF
+boolean_t
+ipmi_is_sun_ilom(ipmi_deviceid_t *dp)
+{
+ return (ipmi_devid_manufacturer(dp) == IPMI_OEM_SUN &&
+ dp->id_product == IPMI_PROD_SUN_ILOM);
+}
+
static int
check_sunoem(ipmi_handle_t *ihp)
{
@@ -74,7 +81,7 @@ check_sunoem(ipmi_handle_t *ihp)
if ((devid = ipmi_get_deviceid(ihp)) == NULL)
return (-1);
- if (ipmi_devid_manufacturer(devid) != IPMI_OEM_SUN)
+ if (!ipmi_is_sun_ilom(devid))
return (ipmi_set_error(ihp, EIPMI_INVALID_COMMAND, NULL));
return (0);
diff --git a/usr/src/lib/libipmi/common/ipmi_user.c b/usr/src/lib/libipmi/common/ipmi_user.c
index 7c1828e660..6547ba8e3f 100644
--- a/usr/src/lib/libipmi/common/ipmi_user.c
+++ b/usr/src/lib/libipmi/common/ipmi_user.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,6 +30,11 @@
#include "ipmi_impl.h"
+typedef struct ipmi_user_impl {
+ ipmi_list_t iu_list;
+ ipmi_user_t iu_user;
+} ipmi_user_impl_t;
+
/*
* Get User Access. See section 22.27.
*
@@ -160,13 +165,12 @@ ipmi_get_user_name(ipmi_handle_t *ihp, uint8_t uid)
void
ipmi_user_clear(ipmi_handle_t *ihp)
{
- ipmi_user_t *up, *next;
+ ipmi_user_impl_t *uip;
- while ((up = ihp->ih_users) != NULL) {
- next = up->iu_next;
- ipmi_free(ihp, up->iu_name);
- ipmi_free(ihp, up);
- ihp->ih_users = next;
+ while ((uip = ipmi_list_next(&ihp->ih_users)) != NULL) {
+ ipmi_list_delete(&ihp->ih_users, uip);
+ ipmi_free(ihp, uip->iu_user.iu_name);
+ ipmi_free(ihp, uip);
}
}
@@ -179,6 +183,7 @@ ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
{
ipmi_get_user_access_t *resp;
uint8_t i;
+ ipmi_user_impl_t *uip;
ipmi_user_t *up;
const char *name;
@@ -197,16 +202,18 @@ ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
IPMI_USER_CHANNEL_CURRENT, i)) == NULL)
return (-1);
- if ((up = ipmi_zalloc(ihp, sizeof (ipmi_user_t))) == NULL)
+ if ((uip = ipmi_zalloc(ihp, sizeof (ipmi_user_impl_t))) == NULL)
return (-1);
+ up = &uip->iu_user;
+
up->iu_enabled = resp->igua_enabled_uid;
up->iu_uid = i;
up->iu_ipmi_msg_enable = resp->igua_ipmi_msg_enable;
up->iu_link_auth_enable = resp->igua_link_auth_enable;
up->iu_priv = resp->igua_privilege_level;
- up->iu_next = ihp->ih_users;
- ihp->ih_users = up;
+
+ ipmi_list_append(&ihp->ih_users, uip);
if ((name = ipmi_get_user_name(ihp, i)) == NULL)
return (-1);
@@ -216,8 +223,9 @@ ipmi_user_iter(ipmi_handle_t *ihp, int (*func)(ipmi_user_t *, void *),
return (-1);
}
- for (up = ihp->ih_users; up != NULL; up = up->iu_next) {
- if (func(up, data) != 0)
+ for (uip = ipmi_list_next(&ihp->ih_users); uip != NULL;
+ uip = ipmi_list_next(uip)) {
+ if (func(&uip->iu_user, data) != 0)
return (-1);
}
diff --git a/usr/src/lib/libipmi/common/ipmi_util.c b/usr/src/lib/libipmi/common/ipmi_util.c
index e461820af9..70b3ed9e45 100644
--- a/usr/src/lib/libipmi/common/ipmi_util.c
+++ b/usr/src/lib/libipmi/common/ipmi_util.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,6 +34,12 @@
#include "ipmi_impl.h"
/*
+ * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
+ * u, which must be an unsigned integer.
+ */
+#define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
+
+/*
* Error handling
*/
int
@@ -60,33 +66,6 @@ ipmi_errno(ipmi_handle_t *ihp)
return (ihp->ih_errno);
}
-static struct {
- int err;
- const char *msg;
-} errno_table[] = {
- { EIPMI_NOMEM, "memory allocation failure" },
- { EIPMI_BMC_OPEN_FAILED, "failed to open /dev/bmc" },
- { EIPMI_BMC_PUTMSG, "failed to send message to /dev/bmc" },
- { EIPMI_BMC_GETMSG,
- "failed to read response from /dev/bmc" },
- { EIPMI_BMC_RESPONSE,
- "failed to read response from /dev/bmc" },
- { EIPMI_INVALID_COMMAND, "invalid command" },
- { EIPMI_COMMAND_TIMEOUT, "command timed out" },
- { EIPMI_DATA_LENGTH_EXCEEDED, "maximum data length exceeded" },
- { EIPMI_SEND_FAILED, "failed to send BMC request" },
- { EIPMI_UNSPECIFIED, "unspecified BMC error" },
- { EIPMI_BAD_RESPONSE_LENGTH,
- "unexpected command response data length" },
- { EIPMI_INVALID_RESERVATION, "invalid or cancelled reservation" },
- { EIPMI_NOT_PRESENT, "request entity not present" },
- { EIPMI_INVALID_REQUEST, "malformed request data" },
- { EIPMI_BUSY, "service processor is busy" },
- { EIPMI_NOSPACE, "service processor is out of space" },
- { EIPMI_UNAVAILABLE, "service processor is unavailable" },
- { EIPMI_ACCESS, "insufficient privileges" }
-};
-
/* ARGSUSED */
const char *
ipmi_errmsg(ipmi_handle_t *ihp)
@@ -95,9 +74,9 @@ ipmi_errmsg(ipmi_handle_t *ihp)
const char *str;
str = NULL;
- for (i = 0; i < sizeof (errno_table) / sizeof (errno_table[0]); i++) {
- if (errno_table[i].err == ihp->ih_errno) {
- str = errno_table[i].msg;
+ for (i = 0; ipmi_errno_table[i].int_name != NULL; i++) {
+ if (ipmi_errno_table[i].int_value == ihp->ih_errno) {
+ str = ipmi_errno_table[i].int_name;
break;
}
}
@@ -116,7 +95,6 @@ ipmi_errmsg(ipmi_handle_t *ihp)
/*
* Memory allocation
*/
-
void *
ipmi_alloc(ipmi_handle_t *ihp, size_t size)
{
@@ -156,3 +134,166 @@ ipmi_free(ipmi_handle_t *ihp, void *ptr)
{
free(ptr);
}
+
+/*
+ * Translation between #defines and strings.
+ */
+void
+ipmi_entity_name(uint8_t id, char *buf, size_t len)
+{
+ ipmi_name_trans_t *ntp;
+
+ for (ntp = &ipmi_entity_table[0]; ntp->int_name != NULL; ntp++) {
+ if (ntp->int_value == id) {
+ (void) strlcpy(buf, ntp->int_name, len);
+ return;
+ }
+ }
+
+ (void) snprintf(buf, len, "0x%02x", id);
+}
+
+void
+ipmi_sensor_type_name(uint8_t type, char *buf, size_t len)
+{
+ ipmi_name_trans_t *ntp;
+
+ for (ntp = &ipmi_sensor_type_table[0]; ntp->int_name != NULL; ntp++) {
+ if (ntp->int_value == type) {
+ (void) strlcpy(buf, ntp->int_name, len);
+ return;
+ }
+ }
+
+ (void) snprintf(buf, len, "0x%02x", type);
+}
+
+void
+ipmi_sensor_reading_name(uint8_t sensor_type, uint8_t reading_type,
+ char *buf, size_t len)
+{
+ uint8_t val;
+ ipmi_name_trans_t *ntp;
+
+ if (reading_type == IPMI_RT_SPECIFIC) {
+ val = sensor_type;
+ ntp = &ipmi_sensor_type_table[0];
+ } else {
+ val = reading_type;
+ ntp = &ipmi_reading_type_table[0];
+ }
+
+ for (; ntp->int_name != NULL; ntp++) {
+ if (ntp->int_value == val) {
+ (void) strlcpy(buf, ntp->int_name, len);
+ return;
+ }
+ }
+
+ if (reading_type == IPMI_RT_SPECIFIC)
+ (void) snprintf(buf, len, "%02x/%02x", reading_type,
+ sensor_type);
+ else
+ (void) snprintf(buf, len, "%02x", reading_type);
+}
+
+/*
+ * Converts a BCD decimal value to an integer.
+ */
+int
+ipmi_convert_bcd(int value)
+{
+ int ret = 0;
+ int digit;
+ int i;
+
+ for (i = 7; i >= 0; i--) {
+ digit = ((value & (0xf << (i * 4))) >> (i * 4));
+ ret += digit * 10 * i;
+ }
+
+ return (ret);
+}
+
+/*
+ * See sections 43.15 and 43.16
+ *
+ * This is a utility function for decoding the strings that are packed into
+ * sensor data records. If the type is 6-bit packed ASCII, then it converts
+ * the string to an 8-bit ASCII string and copies that into the suuplied buffer.
+ * If it is 8-bit ASCII, it copies the string into the supplied buffer as-is.
+ */
+void
+ipmi_decode_string(uint8_t type, uint8_t len, char *data, char *buf)
+{
+ int i, j = 0, chunks, leftovers;
+ uint8_t tmp, lo;
+
+ if (len == 0) {
+ *buf = '\0';
+ return;
+ }
+ /*
+ * If the type is 8-bit ASCII, we can simply copy the string and return
+ */
+ if (type == 0x3) {
+ (void) strncpy(buf, data, len);
+ *(buf+len) = '\0';
+ return;
+ } else if (type == 0x1 || type == 0x0) {
+ /*
+ * Yuck - they either used BCD plus encoding, which we don't
+ * currently handle, or they used an unspecified encoding type.
+ * In these cases we'll set buf to an empty string. We still
+ * need to return the length so that we can get to the next
+ * record.
+ */
+ *buf = '\0';
+ return;
+ }
+
+ /*
+ * Otherwise, it's 6-bit packed ASCII, so we have to convert the
+ * data first
+ */
+ chunks = len / 3;
+ leftovers = len % 3;
+
+ /*
+ * First we decode the 6-bit string in chunks of 3 bytes as far as
+ * possible
+ */
+ for (i = 0; i < chunks; i++) {
+ tmp = BITX(*(data+j), 5, 0);
+ *buf++ = (char)(tmp + 32);
+
+ lo = BITX(*(data+j++), 7, 6);
+ tmp = BITX(*(data+j), 3, 0);
+ tmp = (tmp << 2) | lo;
+ *buf++ = (char)(tmp + 32);
+
+ lo = BITX(*(data+j++), 7, 4);
+ tmp = BITX(*(data+j), 1, 0);
+ tmp = (tmp << 4) | lo;
+ *buf++ = (char)(tmp + 32);
+
+ tmp = BITX(*(data+j++), 7, 2);
+ *buf++ = (char)(tmp + 32);
+ }
+ switch (leftovers) {
+ case 1:
+ tmp = BITX(*(data+j), 5, 0);
+ *buf++ = (char)(tmp + 32);
+ break;
+ case 2:
+ tmp = BITX(*(data+j), 5, 0);
+ *buf++ = (char)(tmp + 32);
+
+ lo = BITX(*(data+j++), 7, 6);
+ tmp = BITX(*(data+j), 3, 0);
+ tmp = (tmp << 2) | lo;
+ *buf++ = (char)(tmp + 32);
+ break;
+ }
+ *buf = '\0';
+}
diff --git a/usr/src/lib/libipmi/common/libipmi.c b/usr/src/lib/libipmi/common/libipmi.c
index 1aee67d245..def87d41cf 100644
--- a/usr/src/lib/libipmi/common/libipmi.c
+++ b/usr/src/lib/libipmi/common/libipmi.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,6 +36,7 @@ ipmi_handle_t *
ipmi_open(int *errp, char **msg)
{
ipmi_handle_t *ihp;
+ static char errmsg[48];
if (msg)
*msg = NULL;
@@ -52,11 +53,13 @@ ipmi_open(int *errp, char **msg)
ihp->ih_retries = 3;
- if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp)) == NULL) {
+ if ((ihp->ih_tdata = ihp->ih_transport->it_open(ihp)) == NULL ||
+ ipmi_sdr_init(ihp) != 0 || ipmi_entity_init(ihp) != 0) {
*errp = ihp->ih_errno;
if (msg) {
- if ((*msg = strdup(ipmi_errmsg(ihp))) == NULL)
- *msg = "memory allocation failure";
+ (void) strncpy(errmsg, ipmi_errmsg(ihp), 47);
+ errmsg[47] = '\0';
+ *msg = errmsg;
}
ipmi_close(ihp);
return (NULL);
@@ -70,8 +73,11 @@ ipmi_close(ipmi_handle_t *ihp)
{
if (ihp->ih_transport && ihp->ih_tdata)
ihp->ih_transport->it_close(ihp->ih_tdata);
- ipmi_sdr_clear(ihp);
+ ipmi_free(ihp, ihp->ih_deviceid);
+ ipmi_free(ihp, ihp->ih_firmware_rev);
ipmi_user_clear(ihp);
+ ipmi_sdr_fini(ihp);
+ ipmi_entity_fini(ihp);
free(ihp);
}
diff --git a/usr/src/lib/libipmi/common/libipmi.h b/usr/src/lib/libipmi/common/libipmi.h
index b1a67d2df0..bbe517443e 100644
--- a/usr/src/lib/libipmi/common/libipmi.h
+++ b/usr/src/lib/libipmi/common/libipmi.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -64,28 +64,28 @@ typedef struct ipmi_handle ipmi_handle_t;
*/
#define EIPMI_BASE 2000
-enum {
+typedef enum {
EIPMI_NOMEM = EIPMI_BASE, /* memory allocation failure */
EIPMI_BMC_OPEN_FAILED, /* failed to open /dev/bmc */
- EIPMI_BMC_PUTMSG, /* putmsg() failed */
- EIPMI_BMC_GETMSG, /* getmsg() failed */
+ EIPMI_BMC_PUTMSG, /* failed to send message to /dev/bmc */
+ EIPMI_BMC_GETMSG, /* failed to read response from /dev/bmc */
EIPMI_BMC_RESPONSE, /* response from /dev/bmc failed */
EIPMI_INVALID_COMMAND, /* invalid command */
EIPMI_COMMAND_TIMEOUT, /* command timeout */
EIPMI_DATA_LENGTH_EXCEEDED, /* maximum data length exceeded */
EIPMI_SEND_FAILED, /* failed to send BMC request */
- EIPMI_UNSPECIFIED, /* unspecified error */
+ EIPMI_UNSPECIFIED, /* unspecified BMC error */
EIPMI_UNKNOWN, /* unknown error */
EIPMI_BAD_RESPONSE, /* received unexpected response */
EIPMI_BAD_RESPONSE_LENGTH, /* unexpected response length */
- EIPMI_INVALID_RESERVATION, /* invalid reservation */
+ EIPMI_INVALID_RESERVATION, /* invalid or cancelled reservation */
EIPMI_NOT_PRESENT, /* requested entity not present */
- EIPMI_INVALID_REQUEST, /* malformed request */
- EIPMI_BUSY, /* SP is busy */
- EIPMI_NOSPACE, /* SP is out of space */
- EIPMI_UNAVAILABLE, /* SP is present but unavailable */
+ EIPMI_INVALID_REQUEST, /* malformed request data */
+ EIPMI_BUSY, /* service processor is busy */
+ EIPMI_NOSPACE, /* service processor is out of space */
+ EIPMI_UNAVAILABLE, /* service processor is unavailable */
EIPMI_ACCESS /* insufficient privileges */
-};
+} ipmi_errno_t;
/*
* Basic library functions.
@@ -141,7 +141,8 @@ typedef struct ipmi_deviceid {
uint16_t id_product;
} ipmi_deviceid_t;
-#define IPMI_OEM_SUN 0x2a
+#define IPMI_OEM_SUN 0x2a
+#define IPMI_PROD_SUN_ILOM 0x4701
ipmi_deviceid_t *ipmi_get_deviceid(ipmi_handle_t *);
@@ -150,11 +151,194 @@ ipmi_deviceid_t *ipmi_get_deviceid(ipmi_handle_t *);
((dp)->id_manufacturer[1] << 8) | \
((dp)->id_manufacturer[2] << 16))
+const char *ipmi_firmware_version(ipmi_handle_t *);
+
+/*
+ * SEL (System Event Log) commands. Currently the library only provides
+ * commands for reading the SEL.
+ */
+
+/*
+ * 31.2 Get SEL Info Command
+ */
+#define IPMI_CMD_GET_SEL_INFO 0x40
+
+typedef struct ipmi_sel_info {
+ uint8_t isel_version;
+ uint16_t isel_entries;
+ uint16_t isel_free;
+ uint32_t isel_add_ts;
+ uint32_t isel_erase_ts;
+ DECL_BITFIELD6(
+ isel_supp_allocation :1,
+ isel_supp_reserve :1,
+ isel_supp_partial :1,
+ isel_supp_delete :1,
+ __reserved :3,
+ isel_overflow :1);
+} ipmi_sel_info_t;
+
+extern ipmi_sel_info_t *ipmi_sel_get_info(ipmi_handle_t *);
+extern boolean_t ipmi_sdr_changed(ipmi_handle_t *);
+extern int ipmi_sdr_refresh(ipmi_handle_t *);
+
+/*
+ * 32.1 SEL Event Records
+ */
+typedef struct ipmi_sel_event {
+ uint16_t isel_ev_next;
+ uint16_t isel_ev_recid;
+ uint8_t isel_ev_rectype;
+ uint32_t isel_ev_ts;
+ DECL_BITFIELD2(
+ isel_ev_software :1,
+ isel_ev_addr_or_id :7);
+ DECL_BITFIELD3(
+ isel_ev_lun :2,
+ __reserved :2,
+ isel_ev_channel :4);
+ uint8_t isel_ev_rev;
+ uint8_t isel_ev_sensor_type;
+ uint8_t isel_ev_sensor_number;
+ DECL_BITFIELD2(
+ isel_ev_type :7,
+ isel_ev_dir :1);
+ uint8_t isel_ev_data[3];
+} ipmi_sel_event_t;
+
+#define IPMI_EV_REV15 0x04
+#define IPMI_EV_REV1 0x03
+
+#define IPMI_SEL_SYSTEM 0x02
+#define IPMI_SEL_OEMTS_LO 0xC0
+#define IPMI_SEL_OEMTS_HI 0xDF
+#define IPMI_SEL_OEM_LO 0xE0
+#define IPMI_SEL_OEM_HI 0xFF
+
+#define IPMI_EV_ASSERT 0x0
+#define IPMI_EV_DEASSERT 0x1
+
+/*
+ * 32.2 OEM SEL Record (with timestamp)
+ */
+typedef struct ipmi_sel_oem_ts {
+ uint16_t isel_oem_next;
+ uint16_t isel_oem_id;
+ uint8_t isel_oem_type;
+ uint32_t isel_oem_ts;
+ uint8_t isel_oem_devid[3];
+ uint8_t isel_oem_data[6];
+} ipmi_sel_oem_ts_t;
+
+/*
+ * 32.3 OEM SEL Record (no timestamp)
+ */
+typedef struct ipmi_sel_oem {
+ uint16_t isel_oem_next;
+ uint16_t isel_oem_id;
+ uint8_t isel_oem_type;
+ uint8_t isel_oem_data[13];
+} ipmi_sel_oem_t;
+
+/*
+ * 29.7 Event Data Field Formats. Consumers can cast the data field of the
+ * event record to the appropriate type depending on the sensor class.
+ */
+
+typedef struct ipmi_event_threshold {
+ DECL_BITFIELD3(
+ iev_offset :4,
+ iev_desc_byte3 :2,
+ iev_desc_byte2 :2);
+ uint8_t iev_reading;
+ uint8_t iev_threshold;
+} ipmi_event_threshold_t;
+
+#define IPMI_EV_DESC_UNSPECIFIED 0x00
+#define IPMI_EV_DESC_TRIGGER 0x01
+#define IPMI_EV_DESC_OEM 0x02
+#define IPMI_EV_DESC_SPECIFIC 0x03
+
+typedef struct ipmi_event_discrete {
+ DECL_BITFIELD3(
+ iev_offset :4,
+ iev_desc_byte3 :2,
+ iev_desc_byte2 :2);
+ DECL_BITFIELD2(
+ iev_offset_type :4,
+ iev_offset_severity :4);
+ uint8_t iev_oem_code;
+} ipmi_event_discrete_t;
+
+#define IPMI_EV_DESC_PREVSTATE 0x01
+#define IPMI_EV_DESC_SPECIFIC 0x03
+
+typedef struct ipmi_event_oem {
+ DECL_BITFIELD3(
+ iev_offset :4,
+ iev_desc_byte3 :2,
+ iev_desc_byte2 :2);
+ DECL_BITFIELD2(
+ iev_offset_type :4,
+ iev_offset_severity :4);
+ uint8_t iev_oem_code;
+} ipmi_event_oem_t;
+
+/*
+ * Get SEL Entry Command. See section 31.5. We don't support partial reads, so
+ * this interface is quite a bit simpler than in the spec. We default to
+ * returning event records, though the consumer should check the type field and
+ * cast it to the appropriate type if it is no IPMI_SEL_SYSTEM.
+ */
+#define IPMI_CMD_GET_SEL_ENTRY 0x43
+
+extern ipmi_sel_event_t *ipmi_sel_get_entry(ipmi_handle_t *, uint16_t);
+
+#define IPMI_SEL_FIRST_ENTRY 0x0000
+#define IPMI_SEL_LAST_ENTRY 0xFFFF
+
+/*
+ * SEL time management. See sections 31.10 and 31.11.
+ */
+#define IPMI_CMD_GET_SEL_TIME 0x48
+#define IPMI_CMD_SET_SEL_TIME 0x49
+#define IPMI_CMD_GET_SEL_UTC_OFFSET 0x5C
+#define IPMI_CMD_SET_SEL_UTC_OFFSET 0x5D
+
+extern int ipmi_sel_get_time(ipmi_handle_t *, uint32_t *);
+extern int ipmi_sel_set_time(ipmi_handle_t *, uint32_t);
+extern int ipmi_sel_get_utc_offset(ipmi_handle_t *, int *);
+extern int ipmi_sel_set_utc_offset(ipmi_handle_t *, int);
+
/*
* SDR (Sensor Device Record) requests. A cache of the current SDR repository
- * is kept as part of the IPMI handle and updated when necessary. Routines to
- * access the raw SDR repository are also provided.
+ * is kept as part of the IPMI handle and updated when necessary. This does the
+ * work of processing the SDR names and providing an easy way to lookup
+ * individual records and iterate over all records.
+ */
+
+/*
+ * Get SDR Repository Info Command. See section 33.9.
*/
+#define IPMI_CMD_GET_SDR_INFO 0x20
+
+typedef struct ipmi_sdr_info {
+ uint8_t isi_version;
+ uint16_t isi_record_count;
+ uint16_t isi_free_space;
+ uint32_t isi_add_ts;
+ uint32_t isi_erase_ts;
+ DECL_BITFIELD7(
+ isi_supp_allocation :1,
+ isi_supp_reserve :1,
+ isi_supp_partial :1,
+ isi_supp_delete :1,
+ __reserved :1,
+ isi_modal :2,
+ isi_overflow :1);
+} ipmi_sdr_info_t;
+
+extern ipmi_sdr_info_t *ipmi_sdr_get_info(ipmi_handle_t *);
/*
* Reserve repository command. See section 33.11.
@@ -183,6 +367,778 @@ typedef struct ipmi_sdr {
extern ipmi_sdr_t *ipmi_sdr_get(ipmi_handle_t *, uint16_t, uint16_t *);
/*
+ * Full Sensor Record. See 43.1
+ */
+#define IPMI_SDR_TYPE_FULL_SENSOR 0x01
+
+typedef struct ipmi_sdr_full_sensor {
+ /* RECORD KEY BYTES */
+ uint8_t is_fs_owner;
+ DECL_BITFIELD3(
+ is_fs_sensor_lun :2,
+ __reserved1 :2,
+ is_fs_channel :4);
+ uint8_t is_fs_number;
+ /* RECORD BODY BYTES */
+ uint8_t is_fs_entity_id;
+ DECL_BITFIELD2(
+ is_fs_entity_instance :7,
+ is_fs_entity_logical :1);
+ DECL_BITFIELD8(
+ is_fs_sensor_scanning_enabled :1,
+ is_fs_event_generation_enabled :1,
+ is_fs_init_sensor_type :1,
+ is_fs_init_hysteresis :1,
+ is_fs_init_thresholds :1,
+ is_fs_init_events :1,
+ is_fs_init_scanning :1,
+ is_fs_settable :1);
+ DECL_BITFIELD5(
+ is_fs_event_support :2,
+ is_fs_threshold_support :2,
+ is_fs_hysteresis_support :2,
+ is_fs_rearm_support :1,
+ is_fs_ignore :1);
+ uint8_t is_fs_type;
+ uint8_t is_fs_reading_type;
+ uint16_t is_fs_assert_mask;
+ uint16_t is_fs_deassert_mask;
+ uint16_t is_fs_reading_mask;
+ DECL_BITFIELD4(
+ is_fs_units_isprcnt :1,
+ is_fs_mod_unit :2,
+ is_fs_rate_unit :3,
+ is_fs_analog_fmt :2);
+ uint8_t is_fs_unit2;
+ uint8_t is_fs_unit3;
+ /* Linearization */
+ DECL_BITFIELD2(
+ is_fs_sensor_linear_type :7,
+ __reserved2 :1);
+ /* M, Tolerance */
+ uint16_t is_fs_mtol;
+ /* B, Accuracy, R exp, B exp */
+ uint32_t is_fs_bacc;
+ DECL_BITFIELD4(
+ is_fs_nominal_reading_spec :1,
+ is_fs_normal_max_spec :1,
+ is_fs_normal_min_spec :1,
+ __reserved3 :5);
+ uint8_t is_fs_nominal_reading;
+ uint8_t is_fs_normal_maximum;
+ uint8_t is_fs_normal_minimum;
+ uint8_t is_fs_max;
+ uint8_t is_fs_min;
+ uint8_t is_fs_upper_nonrecov;
+ uint8_t is_fs_upper_critical;
+ uint8_t is_fs_upper_noncrit;
+ uint8_t is_fs_lower_nonrecov;
+ uint8_t is_fs_lower_critical;
+ uint8_t is_fs_lower_noncrit;
+ uint8_t is_fs_hysteresis_positive;
+ uint8_t is_fs_hysteresis_negative;
+ uint16_t __reserved4;
+ uint8_t is_fs_oem;
+ DECL_BITFIELD3(
+ is_fs_idlen :5,
+ __reserved5 :1,
+ is_fs_idtype :2);
+ char is_fs_idstring[1];
+} ipmi_sdr_full_sensor_t;
+
+#define IPMI_SDR_TYPE_COMPACT_SENSOR 0x02
+
+/*
+ * Compact Sensor Record. See section 43.2
+ */
+typedef struct ipmi_sdr_compact_sensor {
+ /* RECORD KEY BYTES */
+ uint8_t is_cs_owner;
+ DECL_BITFIELD3(
+ is_cs_sensor_lun :2,
+ is_cs_fru_lun :2,
+ is_cs_channel :4);
+ uint8_t is_cs_number;
+ /* RECORD BODY BYTES */
+ uint8_t is_cs_entity_id;
+ DECL_BITFIELD2(
+ is_cs_entity_instance :7,
+ is_cs_entity_logical :1);
+ DECL_BITFIELD8(
+ is_cs_sensor_scanning_enabled :1,
+ is_cs_event_generation_enabled :1,
+ is_cs_init_sensor_type :1,
+ is_cs_init_hysteresis :1,
+ __reserved1 :1,
+ is_cs_init_events :1,
+ is_cs_init_scanning :1,
+ is_cs_settable :1);
+ DECL_BITFIELD5(
+ is_cs_event_support :2,
+ is_cs_threshold_support :2,
+ is_cs_hysteresis_support :2,
+ is_cs_rearm_support :1,
+ is_cs_ignore :1);
+ uint8_t is_cs_type;
+ uint8_t is_cs_reading_type;
+ uint16_t is_cs_assert_mask;
+ uint16_t is_cs_deassert_mask;
+ uint16_t is_cs_reading_mask;
+ DECL_BITFIELD4(
+ is_cs_units_isprcnt :1,
+ is_cs_mod_unit :2,
+ is_cs_rate_unit :3,
+ __reserved2 :2);
+ uint8_t is_cs_unit2;
+ uint8_t is_cs_unit3;
+ DECL_BITFIELD3(
+ is_cs_share_count :4,
+ is_cs_modifier_type :2,
+ is_cs_direction :2);
+ DECL_BITFIELD2(
+ is_cs_modifier_offset :7,
+ is_cs_sharing :1);
+ uint8_t is_cs_hysteresis_positive;
+ uint8_t is_cs_hysteresis_negative;
+ uint16_t __reserved3;
+ uint8_t __reserved4;
+ uint8_t is_cs_oem;
+ DECL_BITFIELD3(
+ is_cs_idlen :5,
+ __reserved5 :1,
+ is_cs_idtype :2);
+ char is_cs_idstring[1];
+} ipmi_sdr_compact_sensor_t;
+
+/*
+ * Threshold sensor masks for is_cs_assert_mask and is_cs_deassert_mask.
+ */
+#define IPMI_SENSOR_RETURN_NONRECOV 0x4000
+#define IPMI_SENSOR_RETURN_CRIT 0x2000
+#define IPMI_SENSOR_RETURN_NONCRIT 0x1000
+
+#define IPMI_SENSOR_MASK_UPPER_NONRECOV_HI 0x0800
+#define IPMI_SENSOR_MASK_UPPER_NONRECOV_LO 0x0400
+#define IPMI_SENSOR_MASK_UPPER_CRIT_HI 0x0200
+#define IPMI_SENSOR_MASK_UPPER_CRIT_LO 0x0100
+#define IPMI_SENSOR_MASK_UPPER_NONCRIT_HI 0x0080
+#define IPMI_SENSOR_MASK_UPPER_NONCRIT_LO 0x0040
+#define IPMI_SENSOR_MASK_LOWER_NONRECOV_HI 0x0020
+#define IPMI_SENSOR_MASK_LOWER_NONRECOV_LO 0x0010
+#define IPMI_SENSOR_MASK_LOWER_CRIT_HI 0x0008
+#define IPMI_SENSOR_MASK_LOWER_CRIT_LO 0x0004
+#define IPMI_SENSOR_MASK_LOWER_NONCRIT_HI 0x0002
+#define IPMI_SENSOR_MASK_LOWER_NONCRIT_LO 0x0001
+
+/*
+ * Threshold sensor masks for is_cs_reading_mask.
+ */
+#define IPMI_SENSOR_SETTABLE_UPPER_NONRECOV 0x2000
+#define IPMI_SENSOR_SETTABLE_UPPER_CRIT 0x1000
+#define IPMI_SENSOR_SETTABLE_UPPER_NONCRIT 0x0800
+#define IPMI_SENSOR_SETTABLE_LOWER_NONRECOV 0x0400
+#define IPMI_SENSOR_SETTABLE_LOWER_CRIT 0x0200
+#define IPMI_SENSOR_SETTABLE_LOWER_NONCRIT 0x0100
+#define IPMI_SENSOR_READABLE_UPPER_NONRECOV 0x0020
+#define IPMI_SENSOR_READABLE_UPPER_CRIT 0x0010
+#define IPMI_SENSOR_READABLE_UPPER_NONCRIT 0x0008
+#define IPMI_SENSOR_READABLE_LOWER_NONRECOV 0x0004
+#define IPMI_SENSOR_READABLE_LOWER_CRIT 0x0002
+#define IPMI_SENSOR_READABLE_LOWER_NONCRIT 0x0001
+
+/*
+ * Values for is_cs_reading_type. See table 42-2.
+ */
+#define IPMI_RT_THRESHOLD 0x01
+#define IPMI_RT_USAGE 0x02
+#define IPMI_RT_STATE 0x03
+#define IPMI_RT_PREDFAIL 0x04
+#define IPMI_RT_LIMIT 0x05
+#define IPMI_RT_PERFORMANCE 0x06
+#define IPMI_RT_SEVERITY 0x07
+#define IPMI_RT_PRESENT 0x08
+#define IPMI_RT_ENABLED 0x09
+#define IPMI_RT_AVAILABILITY 0x0A
+#define IPMI_RT_REDUNDANCY 0x0B
+#define IPMI_RT_ACPI 0x0C
+#define IPMI_RT_SPECIFIC 0x6F
+
+/*
+ * Bitmasks based on above reading types. See table 42-2
+ */
+#define IPMI_SR_THRESHOLD_LOWER_NONCRIT_LOW 0x0001
+#define IPMI_SR_THRESHOLD_LOWER_NONCRIT_HIGH 0x0002
+#define IPMI_SR_THRESHOLD_LOWER_CRIT_LOW 0x0004
+#define IPMI_SR_THRESHOLD_LOWER_CRIT_HIGH 0x0008
+#define IPMI_SR_THRESHOLD_LOWER_NONRECOV_LOW 0x0010
+#define IPMI_SR_THRESHOLD_LOWER_NONRECOV_HIGH 0x0020
+#define IPMI_SR_THRESHOLD_UPPER_NONCRIT_LOW 0x0040
+#define IPMI_SR_THRESHOLD_UPPER_NONCRIT_HIGH 0x0080
+#define IPMI_SR_THRESHOLD_UPPER_CRIT_LOW 0x0100
+#define IPMI_SR_THRESHOLD_UPPER_CRIT_HIGH 0x0200
+#define IPMI_SR_THRESHOLD_UPPER_NONRECOV_LOW 0x0400
+#define IPMI_SR_THRESHOLD_UPPER_NONRECOV_HIGH 0x0800
+
+#define IPMI_SR_USAGE_IDLE 0x0001
+#define IPMI_SR_USAGE_ACTIVE 0x0002
+#define IPMI_SR_USAGE_BUSY 0x0004
+
+#define IPMI_SR_STATE_DEASSERT 0x0001
+#define IPMI_SR_STATE_ASSERT 0x0002
+
+#define IPMI_SR_PREDFAIL_DEASSERT 0x0001
+#define IPMI_SR_PREDFAIL_ASSERT 0x0002
+
+#define IPMI_SR_LIMIT_NOTEXCEEDED 0x0001
+#define IPMI_SR_LIMIT_EXCEEDED 0x0002
+
+#define IPMI_SR_PERFORMANCE_MET 0x0001
+#define IPMI_SR_PERFORMANCE_LAGS 0x0002
+
+#define IPMI_SR_SEVERITY_TO_OK 0x0001
+#define IPMI_SR_SEVERITY_OK_TO_NONCRIT 0x0002
+#define IPMI_SR_SEVERITY_LESS_TO_CRIT 0x0004
+#define IPMI_SR_SEVERITY_LESS_TO_NONRECOV 0x0008
+#define IPMI_SR_SEVERITY_MORE_TO_NONCRIT 0x0010
+#define IPMI_SR_SEVERITY_NONRECOV_TO_CRIT 0x0020
+#define IPMI_SR_SEVERITY_TO_NONRECOV 0x0040
+#define IPMI_SR_SEVERITY_MONITOR 0x0080
+#define IPMI_SR_SEVERITY_INFO 0x0100
+
+#define IPMI_SR_PRESENT_DEASSERT 0x0001
+#define IPMI_SR_PRESENT_ASSERT 0x0002
+
+#define IPMI_SR_ENABLED_DEASSERT 0x0001
+#define IPMI_SR_ENABLED_ASSERT 0x0002
+
+#define IPMI_SR_AVAILABILITY_RUNNING 0x0001
+#define IPMI_SR_AVAILABILITY_INTEST 0x0002
+#define IPMI_SR_AVAILABILITY_POWEROFF 0x0004
+#define IPMI_SR_AVAILABILITY_ONLINE 0x0008
+#define IPMI_SR_AVAILABILITY_OFFLINE 0x0010
+#define IPMI_SR_AVAILABILITY_OFFDUTY 0x0020
+#define IPMI_SR_AVAILABILITY_DEGRADED 0x0040
+#define IPMI_SR_AVAILABILITY_POWERSAVE 0x0080
+#define IPMI_SR_AVAILABILITY_INSTALLERR 0x0100
+
+#define IPMI_SR_REDUNDANCY_FULL 0x0001
+#define IPMI_SR_REDUNDANCY_LOST 0x0002
+#define IPMI_SR_REDUNDANCY_DEGRADED 0x0004
+#define IPMI_SR_REDUNDANCY_NONE_MINIMAL 0x0008
+#define IPMI_SR_REDUNDANCY_NONE_REGAINED 0x0010
+#define IPMI_SR_REDUNDANCY_NONE_INSUFFFICIENT 0x0020
+#define IPMI_SR_REDUNDANCY_DEG_FROM_FULL 0x0040
+#define IPMI_SR_REDUNDANCY_DEG_FROM_NON 0x0080
+
+#define IPMI_SR_ACPI_DO 0x0001
+#define IPMI_SR_ACPI_D1 0x0002
+#define IPMI_SR_ACPI_D2 0x0004
+#define IPMI_SR_ACPI_D3 0x0008
+
+/*
+ * Bitmasks for sensor-specific reading type (0x6F). See section 42.2.
+ */
+#define IPMI_ST_RESERVED 0x00
+#define IPMI_ST_TEMP 0x01
+#define IPMI_ST_VOLTAGE 0x02
+#define IPMI_ST_CURRENT 0x03
+#define IPMI_ST_FAN 0x04
+#define IPMI_ST_PHYSICAL 0x05
+
+#define IPMI_EV_PHYSICAL_GENERAL 0x0001
+#define IPMI_EV_PHYSICAL_BAY 0x0002
+#define IPMI_EV_PHYSICAL_CARD 0x0004
+#define IPMI_EV_PHYSICAL_PROCESSOR 0x0008
+#define IPMI_EV_PHYSICAL_LAN 0x0010
+#define IPMI_EV_PHYSICAL_DOCK 0x0020
+#define IPMI_EV_PHYSICAL_FAN 0x0040
+
+#define IPMI_ST_PLATFORM 0x06
+
+#define IPMI_EV_PLATFORM_SECURE 0x0001
+#define IPMI_EV_PLATFORM_USER_PASS 0x0002
+#define IPMI_EV_PLATFORM_SETUP_PASS 0x0004
+#define IPMI_EV_PLATFORM_NETWORK_PASS 0x0008
+#define IPMI_EV_PLATFORM_OTHER_PASS 0x0010
+#define IPMI_EV_PLATFORM_OUT_OF_BAND 0x0020
+
+#define IPMI_ST_PROCESSOR 0x07
+
+#define IPMI_EV_PROCESSOR_IERR 0x0001
+#define IPMI_EV_PROCESSOR_THERMAL 0x0002
+#define IPMI_EV_PROCESSOR_FRB1 0x0004
+#define IPMI_EV_PROCESSOR_FRB2 0x0008
+#define IPMI_EV_PROCESSOR_FRB3 0x0010
+#define IPMI_EV_PROCESSOR_CONFIG 0x0020
+#define IPMI_EV_PROCESSOR_SMBIOS 0x0040
+#define IPMI_EV_PROCESSOR_PRESENT 0x0080
+#define IPMI_EV_PROCESSOR_DISABLED 0x0100
+#define IPMI_EV_PROCESSOR_TERMINATOR 0x0200
+#define IPMI_EV_PROCESSOR_THROTTLED 0x0400
+
+#define IPMI_ST_POWER_SUPPLY 0x08
+
+#define IPMI_EV_POWER_SUPPLY_PRESENT 0x0001
+#define IPMI_EV_POWER_SUPPLY_FAILURE 0x0002
+#define IPMI_EV_POWER_SUPPLY_PREDFAIL 0x0004
+#define IPMI_EV_POWER_SUPPLY_INPUT_LOST 0x0008
+#define IPMI_EV_POWER_SUPPLY_INPUT_RANGE 0x0010
+#define IPMI_EV_POWER_SUPPLY_INPUT_RANGE_PRES 0x0020
+#define IPMI_EV_POWER_SUPPLY_CONFIG_ERR 0x0040
+
+#define IPMI_ST_POWER_UNIT 0x09
+
+#define IPMI_EV_POWER_UNIT_OFF 0x0001
+#define IPMI_EV_POWER_UNIT_CYCLE 0x0002
+#define IPMI_EV_POWER_UNIT_240_DOWN 0x0004
+#define IPMI_EV_POWER_UNIT_INTERLOCK_DOWN 0x0008
+#define IPMI_EV_POWER_UNIT_AC_LOST 0x0010
+#define IPMI_EV_POWER_UNIT_SOFT_FAILURE 0x0020
+#define IPMI_EV_POWER_UNIT_FAIL 0x0040
+#define IPMI_EV_POWER_UNIT_PREDFAIL 0x0080
+
+#define IPMI_ST_COOLING 0x0A
+#define IPMI_ST_OTHER 0x0B
+#define IPMI_ST_MEMORY 0x0C
+
+#define IPMI_EV_MEMORY_CE 0x0001
+#define IPMI_EV_MEMORY_UE 0x0002
+#define IPMI_EV_MEMORY_PARITY 0x0004
+#define IPMI_EV_MEMORY_SCRUB_FAIL 0x0008
+#define IPMI_EV_MEMORY_DISABLED 0x0010
+#define IPMI_EV_MEMORY_CE_LOG_LIMIT 0x0020
+#define IPMI_EV_MEMORY_PRESENT 0x0040
+#define IPMI_EV_MEMORY_CONFIG_ERR 0x0080
+#define IPMI_EV_MEMORY_SPARE 0x0100
+#define IPMI_EV_MEMORY_THROTTLED 0x0200
+#define IPMI_EV_MEMORY_OVERTEMP 0x0400
+
+#define IPMI_ST_BAY 0x0D
+
+#define IPMI_EV_BAY_PRESENT 0x0001
+#define IPMI_EV_BAY_FAULT 0x0002
+#define IPMI_EV_BAY_PREDFAIL 0x0004
+#define IPMI_EV_BAY_SPARE 0x0008
+#define IPMI_EV_BAY_CHECK 0x0010
+#define IPMI_EV_BAY_CRITICAL 0x0020
+#define IPMI_EV_BAY_FAILED 0x0040
+#define IPMI_EV_BAY_REBUILDING 0x0080
+#define IPMI_EV_BAY_ABORTED 0x0100
+
+#define IPMI_ST_POST_RESIZE 0x0E
+#define IPMI_ST_FIRMWARE 0x0F
+
+#define IPMI_EV_FIRMWARE_ERROR 0x0001
+#define IPMI_EV_FIRMWARE_HANG 0x0002
+#define IPMI_EV_FIRMWARE_PROGRESS 0x0004
+
+#define IPMI_ST_EVENT_LOG 0x10
+
+#define IPMI_EV_EVENT_LOG_CE 0x0001
+#define IPMI_EV_EVENT_LOG_TYPE 0x0002
+#define IPMI_EV_EVENT_LOG_RESET 0x0004
+#define IPMI_EV_EVENT_LOG_ALL 0x0008
+#define IPMI_EV_EVENT_LOG_FULL 0x0010
+#define IPMI_EV_EVENT_LOG_ALMOST_FULL 0x0020
+
+#define IPMI_ST_WATCHDOG1 0x11
+
+#define IPMI_EV_WATCHDOG_BIOS_RESET 0x0001
+#define IPMI_EV_WATCHDOG_OS_RESET 0x0002
+#define IPMI_EV_WATCHDOG_OS_SHUTDOWN 0x0004
+#define IPMI_EV_WATCHDOG_OS_PWR_DOWN 0x0008
+#define IPMI_EV_WATCHDOG_OS_PWR_CYCLE 0x0010
+#define IPMI_EV_WATCHDOG_OS_NMI_DIAG 0x0020
+#define IPMI_EV_WATCHDOG_EXPIRED 0x0040
+#define IPMI_EV_WATCHDOG_PRE_TIMEOUT_INT 0x0080
+
+#define IPMI_ST_SYSTEM 0x12
+
+#define IPMI_EV_STSTEM_RECONF 0x0001
+#define IPMI_EV_STSTEM_BOOT 0x0002
+#define IPMI_EV_STSTEM_UNKNOWN_HW_FAILURE 0x0004
+#define IPMI_EV_STSTEM_AUX_LOG_UPDATED 0x0008
+#define IPMI_EV_STSTEM_PEF_ACTION 0x0010
+#define IPMI_EV_SYSTEM_TIMETAMP_CLOCKSYNC 0x0020
+
+#define IPMI_ST_CRITICAL 0x13
+
+#define IPMI_EV_CRITICAL_EXT_NMI 0x0001
+#define IPMI_EV_CRITICAL_BUS_TIMOEOUT 0x0002
+#define IPMI_EV_CRITICAL_IO_NMI 0x0004
+#define IPMI_EV_CRITICAL_SW_NMI 0x0008
+#define IPMI_EV_CRITICAL_PCI_PERR 0x0010
+#define IPMI_EV_CRITICAL_PCI_SERR 0x0020
+#define IPMI_EV_CRITICAL_EISA_FAILSAFE 0x0040
+#define IPMI_EV_CRITICAL_BUS_CE 0x0080
+#define IPMI_EV_CRITICAL_BUS_UE 0x0100
+#define IPMI_EV_CRITICAL_FATAL_NMI 0x0200
+#define IPMI_EV_CRITICAL_BUS_FATAL_ERR 0x0400
+#define IPMI_EV_CRITICAL_BUS_DEGRADED 0x0800
+
+#define IPMI_ST_BUTTON 0x14
+
+#define IPMI_EV_BUTTON_PWR 0x0001
+#define IPMI_EV_BUTTON_SLEEP 0x0002
+#define IPMI_EV_BUTTON_RESET 0x0004
+#define IPMI_EV_BUTTON_FRU_LATCH 0x0008
+#define IPMI_EV_BUTTON_FRU_SERVICE 0x0010
+
+#define IPMI_ST_MODULE 0x15
+#define IPMI_ST_MICROCONTROLLER 0x16
+#define IPMI_ST_CARD 0x17
+#define IPMI_ST_CHASSIS 0x18
+
+#define IPMI_ST_CHIPSET 0x19
+
+#define IPMI_EV_CHIPSET_PWR_CTL_FAIL 0x0001
+
+#define IPMI_ST_FRU 0x1A
+#define IPMI_ST_CABLE 0x1B
+
+#define IPMI_EV_CABLE_CONNECTED 0x0001
+#define IPMI_EV_CABLE_CONFIG_ERR 0x0002
+
+#define IPMI_ST_TERMINATOR 0x1C
+
+#define IPMI_ST_BOOT 0x1D
+
+#define IPMI_EV_BOOT_BIOS_PWR_UP 0x0001
+#define IPMI_EV_BOOT_BIOS_HARD_RESET 0x0002
+#define IPMI_EV_BOOT_BIOS_WARM_RESET 0x0004
+#define IPMI_EV_BOOT_PXE_BOOT 0x0008
+#define IPMI_EV_BOOT_DIAG_BOOT 0x0010
+#define IPMI_EV_BOOT_OS_HARD_RESET 0x0020
+#define IPMI_EV_BOOT_OS_WARM_RESET 0x0040
+#define IPMI_EV_BOOT_SYS_RESTART 0x0080
+
+#define IPMI_ST_BOOT_ERROR 0x1E
+
+#define IPMI_EV_BOOT_ERROR_NOMEDIA 0x0001
+#define IPMI_EV_BOOT_ERROR_NON_BOOTABLE_DISK 0x0002
+#define IPMI_EV_BOOT_ERROR_NO_PXE_SERVER 0x0004
+#define IPMI_EV_BOOT_ERROR_INV_BOOT_SECT 0x0008
+#define IPMI_EV_BOOT_ERROR_USR_SELECT_TIMEOUT 0x0010
+
+#define IPMI_ST_BOOT_OS 0x1F
+
+#define IPMI_EV_BOOT_OS_A_DRV_BOOT_COMPLETE 0x0001
+#define IPMI_EV_BOOT_OS_C_DRV_BOOT_COMPLETE 0x0002
+#define IPMI_EV_BOOT_OS_PXE_BOOT_COMPLETE 0x0004
+#define IPMI_EV_BOOT_OS_DIAG_BOOT_COMPLETE 0x0008
+#define IPMI_EV_BOOT_OS_CDROM_BOOT_COMPLETE 0x0010
+#define IPMI_EV_BOOT_OS_ROM_BOOT_COMPLETE 0x0020
+#define IPMI_EV_BOOT_OS_UNSPEC_BOOT_COMPLETE 0x0040
+
+#define IPMI_ST_OS_SHUTDOWN 0x20
+
+#define IPMI_EV_OS_SHUTDOWN_LOADING 0x0001
+#define IPMI_EV_OS_SHUTDOWN_CRASH 0x0002
+#define IPMI_EV_OS_STOP_GRACEFUL 0x0004
+#define IPMI_EV_OS_SHUTDOWN_GRACEFUL 0x0008
+#define IPMI_EV_OS_SHUTDOWN_PEF 0x0010
+#define IPMI_EV_OS_SHUTDOWN_BMC 0x0020
+
+#define IPMI_ST_SLOT 0x21
+
+#define IPMI_EV_SLOT_FAULT_ASSERTED 0x0001
+#define IPMI_EV_SLOT_IDENTIFY_ASSERTED 0x0002
+#define IPMI_EV_SLOT_CONNECTED 0x0004
+#define IPMI_EV_SLOT_INSTALL_READY 0x0008
+#define IPMI_EV_SLOT_REMOVE_READY 0x0010
+#define IPMI_EV_SLOT_PWR_OFF 0x0020
+#define IPMI_EV_SLOT_REMOVED 0x0040
+#define IPMI_EV_SLOT_INTERLOCK_ASSERTED 0x0080
+#define IPMI_EV_SLOT_DISABLED 0x0100
+#define IPMI_EV_SLOT_SPARE_DEVICE 0x0200
+
+#define IPMI_ST_ACPI 0x22
+
+#define IPMI_EV_ACPI_PSTATE_S0_G0 0x0001
+#define IPMI_EV_ACPI_PSTATE_S1 0x0002
+#define IPMI_EV_ACPI_PSTATE_S2 0x0004
+#define IPMI_EV_ACPI_PSTATE_S3 0x0008
+#define IPMI_EV_ACPI_PSTATE_S4 0x0010
+#define IPMI_EV_ACPI_PSTATE_S5_G2_SOFT_OFF 0x0020
+#define IPMI_EV_ACPI_PSTATE_S4_S5_SOFT_OFF 0x0040
+#define IPMI_EV_ACPI_PSATTE_G3_MECH_OFF 0x0080
+#define IPMI_EV_ACPI_PSTATE_S1_S2_S3_SLEEP 0x0100
+#define IPMI_EV_ACPI_PSTATE_G1_SLEEP 0x0200
+#define IPMI_EV_ACPI_PSTATE_S5_OVERRIDE 0x0400
+#define IPMI_EV_ACPI_PSTATE_LEGACY_ON 0x0800
+#define IPMI_EV_ACPI_PSTATE_LEGACY_OFF 0x1000
+#define IPMI_EV_ACPI_PSTATE_UNKNOWN 0x2000
+
+#define IPMI_ST_WATCHDOG2 0x23
+
+#define IPMI_EV_WATCHDOG2_EXPIRED 0x0001
+#define IPMI_EV_WATCHDOG2_HARD_RESET 0x0002
+#define IPMI_EV_WATCHDOG2_PWR_DOWN 0x0004
+#define IPMI_EV_WATCHDOG2_PWR_CYCLE 0x0008
+#define IPMI_EV_WATCHDOG2_RESERVED1 0x0010
+#define IPMI_EV_WATCHDOG2_RESERVED2 0x0020
+#define IPMI_EV_WATCHDOG2_RESERVED3 0x0040
+#define IPMI_EV_WATCHDOG2_RESERVED4 0x0080
+#define IPMI_EV_WATCHDOG2_TIMEOUT_INT 0x0100
+
+#define IPMI_ST_ALERT 0x24
+
+#define IPMI_EV_ALERT_PLAT_PAGE 0x0001
+#define IPMI_EV_ALERT_PLAT_LAN_ALERT 0x0002
+#define IPMI_EV_ALERT_PLAT_EVT_TRAP 0x0004
+#define IPMI_EV_ALERT_PLAT_SNMP_TRAP 0x0008
+
+#define IPMI_ST_PRESENCE 0x25
+
+#define IPMI_EV_PRESENCE_PRESENT 0x0001
+#define IPMI_EV_PRESENCE_ABSENT 0x0002
+#define IPMI_EV_PRESENCE_DISABLED 0x0004
+
+#define IPMI_ST_ASIC 0x26
+
+#define IPMI_ST_LAN 0x27
+
+#define IPMI_EV_LAN_HEARTBEAT_LOST 0x0001
+#define IPMI_EV_LAN_HEARTBEAT 0x0002
+
+#define IPMI_ST_HEALTH 0x28
+
+#define IPMI_EV_HEALTH_SENSOR_ACC_DEGRADED 0x0001
+#define IPMI_EV_HEALTH_CNTLR_ACC_DEGRADED 0x0002
+#define IPMI_EV_HEALTH_CNTLR_OFFLINE 0x0004
+#define IPMI_EV_HEALTH_CNTLR_UNAVAIL 0x0008
+#define IPMI_EV_HEALTH_SENSOR_FAILURE 0x0010
+#define IPMI_EV_HEALTH_FRU_FAILURE 0x0020
+
+#define IPMI_ST_BATTERY 0x29
+
+#define IPMI_EV_BATTERY_LOW 0x0001
+#define IPMI_EV_BATTERY_FAILED 0x0002
+#define IPMI_EV_BATTERY_PRESENCE 0x0004
+
+#define IPMI_ST_AUDIT 0x2A
+
+#define IPMI_EV_AUDIT_SESSION_ACTIVATED 0x0001
+#define IPMI_EV_AUDIT_SESSION_DEACTIVATED 0x0002
+
+#define IPMI_ST_VERSION 0x2B
+
+#define IPMI_EV_VERSION_HW_CHANGE 0x0001
+#define IPMI_EV_VERSION_SW_CHANGE 0x0002
+#define IPMI_EV_VERSION_HW_INCOMPATIBLE 0x0004
+#define IPMI_EV_VERSION_SW_INCOMPATIBLE 0x0008
+#define IPMI_EV_VERSION_HW_INVAL 0x0010
+#define IPMI_EV_VERSION_SW_INVAL 0x0020
+#define IPMI_EV_VERSION_HW_CHANGE_SUCCESS 0x0040
+#define IPMI_EV_VERSION_SW_CHANGE_SUCCESS 0x0080
+
+#define IPMI_ST_FRU_STATE 0x2C
+
+#define IPMI_EV_FRU_STATE_NOT_INSTALLED 0x0001
+#define IPMI_EV_FRU_STATE_INACTIVE 0x0002
+#define IPMI_EV_FRU_STATE_ACT_REQ 0x0004
+#define IPMI_EV_FRU_STATE_ACT_INPROGRESS 0x0008
+#define IPMI_EV_FRU_STATE_ACTIVE 0x0010
+#define IPMI_EV_FRU_STATE_DEACT_REQ 0x0020
+#define IPMI_EV_FRU_STATE_DEACT_INPROGRESS 0x0040
+#define IPMI_EV_FRU_STATE_COMM_LOST 0x0080
+
+/*
+ * Constants for unit type codes. See Table 43-15.
+ */
+#define IPMI_UNITS_UNSPECIFIED 0x00
+#define IPMI_UNITS_DEGREES_C 0x01
+#define IPMI_UNITS_DEGREES_F 0x02
+#define IPMI_UNITS_DEGREES_K 0x03
+#define IPMI_UNITS_VOLTS 0x04
+#define IPMI_UNITS_AMPS 0x05
+#define IPMI_UNITS_WATTS 0x06
+#define IPMI_UNITS_JOULES 0x07
+#define IPMI_UNITS_COULOMBS 0x08
+#define IPMI_UNITS_VA 0x09
+#define IPMI_UNITS_NITS 0x0A
+#define IPMI_UNITS_LUMEN 0x0B
+#define IPMI_UNITS_LUX 0x0C
+#define IPMI_UNITS_CANDELA 0x0D
+#define IPMI_UNITS_KPA 0x0E
+#define IPMI_UNITS_PSI 0x0F
+
+#define IPMI_UNITS_NEWTON 0x10
+#define IPMI_UNITS_CFM 0x11
+#define IPMI_UNITS_RPM 0x12
+#define IPMI_UNITS_HZ 0x13
+#define IPMI_UNITS_MICROSEC 0x14
+#define IPMI_UNITS_MILLISEC 0x15
+#define IPMI_UNITS_SECS 0x16
+#define IPMI_UNITS_MIN 0x17
+#define IPMI_UNITS_HOUR 0x18
+#define IPMI_UNITS_DAY 0x19
+#define IPMI_UNITS_WEEK 0x1A
+#define IPMI_UNITS_MIL 0x1B
+#define IPMI_UNITS_INCHES 0x1C
+#define IPMI_UNITS_FEET 0x1D
+#define IPMI_UNITS_CUB_INCH 0x1E
+#define IPMI_UNITS_CUB_FEET 0x1F
+
+#define IPMI_UNITS_MM 0x20
+#define IPMI_UNITS_CM 0x21
+#define IPMI_UNITS_METERS 0x22
+#define IPMI_UNITS_CUB_CM 0x23
+#define IPMI_UNITS_CUB_METER 0x24
+#define IPMI_UNITS_LITERS 0x25
+#define IPMI_UNITS_FLUID_OUNCE 0x26
+#define IPMI_UNITS_RADIANS 0x27
+#define IPMI_UNITS_STERADIANS 0x28
+#define IPMI_UNITS_REVOLUTIONS 0x29
+#define IPMI_UNITS_CYCLES 0x2A
+#define IPMI_UNITS_GRAVITIES 0x2B
+#define IPMI_UNITS_OUNCE 0x2C
+#define IPMI_UNITS_POUND 0x2D
+#define IPMI_UNITS_FOOT_POUND 0x2E
+#define IPMI_UNITS_OZ_INCH 0x2F
+
+#define IPMI_UNITS_GAUSS 0x30
+#define IPMI_UNITS_GILBERTS 0x31
+#define IPMI_UNITS_HENRY 0x32
+#define IPMI_UNITS_MILHENRY 0x33
+#define IPMI_UNITS_FARAD 0x34
+#define IPMI_UNITS_MICROFARAD 0x35
+#define IPMI_UNITS_OHMS 0x36
+#define IPMI_UNITS_SIEMENS 0x37
+#define IPMI_UNITS_MOLE 0x38
+#define IPMI_UNITS_BECQUEREL 0x39
+#define IPMI_UNITS_PPM 0x3A
+/* 0x3B is reserved */
+#define IPMI_UNITS_DECIBELS 0x3C
+#define IPMI_UNITS_DBA 0x3D
+#define IPMI_UNITS_DBC 0x3E
+#define IPMI_UNITS_GRAY 0x3F
+
+#define IPMI_UNITS_SIEVERT 0x40
+#define IPMI_UNITS_COLOR_TEMP_K 0x41
+#define IPMI_UNITS_BIT 0x42
+#define IPMI_UNITS_KILOBIT 0x43
+#define IPMI_UNITS_MEGABIT 0x44
+#define IPMI_UNITS_GIGABIT 0x45
+#define IPMI_UNITS_BYTE 0x46
+#define IPMI_UNITS_KILOBYTE 0x47
+#define IPMI_UNITS_MEGABYTE 0x48
+#define IPMI_UNITS_GIGABYTE 0x49
+#define IPMI_UNITS_WORD 0x4A
+#define IPMI_UNITS_DWORD 0x4B
+#define IPMI_UNITS_QWORD 0x4C
+#define IPMI_UNITS_MEMLINE 0x4D
+#define IPMI_UNITS_HIT 0x4E
+#define IPMI_UNITS_MISS 0x4F
+
+#define IPMI_UNITS_RETRY 0x50
+#define IPMI_UNITS_RESET 0x51
+#define IPMI_UNITS_OVERFLOW 0x52
+#define IPMI_UNITS_UNDERRUN 0x53
+#define IPMI_UNITS_COLLISION 0x54
+#define IPMI_UNITS_PACKETS 0x55
+#define IPMI_UNITS_MESSAGES 0x56
+#define IPMI_UNITS_CHARACTERS 0x57
+#define IPMI_UNITS_ERROR 0x58
+#define IPMI_UNITS_CE 0x59
+#define IPMI_UNITS_UE 0x5A
+#define IPMI_UNITS_FATAL_ERROR 0x5B
+#define IPMI_UNITS_GRAMS 0x5C
+
+/*
+ * Event-Only Record. See section 43.3.
+ */
+
+#define IPMI_SDR_TYPE_EVENT_ONLY 0x03
+
+typedef struct ipmi_sdr_event_only {
+ /* RECORD KEY BYTES */
+ uint8_t is_eo_owner;
+ DECL_BITFIELD3(
+ is_eo_sensor_lun :2,
+ is_eo_fru_lun :2,
+ is_eo_channel :4);
+ uint8_t is_eo_number;
+ /* RECORD BODY BYTES */
+ uint8_t is_eo_entity_id;
+ DECL_BITFIELD2(
+ is_eo_entity_instance :7,
+ is_eo_entity_logical :1);
+ uint8_t is_eo_sensor_type;
+ uint8_t is_eo_reading_type;
+ DECL_BITFIELD3(
+ is_eo_share_count :4,
+ is_eo_modifier_type :2,
+ is_eo_direction :2);
+ DECL_BITFIELD2(
+ is_eo_modifier_offset :7,
+ is_eo_sharing :1);
+ uint8_t __reserved;
+ uint8_t is_eo_oem;
+ DECL_BITFIELD3(
+ is_eo_idlen :5,
+ __reserved1 :1,
+ is_eo_idtype :2);
+ char is_eo_idstring[1];
+} ipmi_sdr_event_only_t;
+
+/*
+ * Entity Association Record. See section 43.4.
+ */
+
+#define IPMI_SDR_TYPE_ENTITY_ASSOCIATION 0x08
+
+typedef struct ipmi_sdr_entity_association {
+ /* RECORD KEY BYTES */
+ uint8_t is_ea_entity_id;
+ uint8_t is_ea_entity_instance;
+ DECL_BITFIELD4(
+ __reserved :5,
+ is_ea_presence :1,
+ is_ea_record_link :1,
+ is_ea_range :1);
+ /* RECORD BODY BYTES */
+ struct {
+ uint8_t is_ea_sub_id;
+ uint8_t is_ea_sub_instance;
+ } is_ea_sub[4];
+} ipmi_sdr_entity_association_t;
+
+/*
+ * Device-relative Entity Association Record. See section 43.5.
+ */
+
+#define IPMI_SDR_TYPE_DEVICE_RELATIVE 0x09
+
+typedef struct ipmi_sdr_device_relative {
+ /* RECORD KEY BYTES */
+ uint8_t is_dr_entity_id;
+ uint8_t is_dr_entity_instance;
+ DECL_BITFIELD2(
+ __reserved1 :1,
+ is_dr_slaveaddr :7);
+ DECL_BITFIELD2(
+ __reserved2 :4,
+ is_dr_channel :4);
+ DECL_BITFIELD4(
+ __reserved :5,
+ is_dr_presence :1,
+ is_dr_record_link :1,
+ is_dr_range :1);
+ /* RECORD BODY BYTES */
+ struct {
+ DECL_BITFIELD2(
+ __reserved3 :1,
+ is_dr_sub_slaveaddr :7);
+ DECL_BITFIELD2(
+ __reserved4 :4,
+ is_dr_sub_channel :4);
+ uint8_t is_ea_sub_id;
+ uint8_t is_ea_sub_instance;
+ } is_ea_sub[4];
+} ipmi_sdr_device_relative_t;
+
+/*
* Generic Device Locator Record. See section 43.7.
*/
@@ -210,8 +1166,9 @@ typedef struct ipmi_sdr_generic_locator {
uint8_t is_gl_entity;
uint8_t is_gl_instance;
uint8_t is_gl_oem;
- DECL_BITFIELD2(
- is_gl_idlen :6,
+ DECL_BITFIELD3(
+ is_gl_idlen :5,
+ __reserved4 :1,
is_gl_idtype :2);
char is_gl_idstring[1];
} ipmi_sdr_generic_locator_t;
@@ -252,8 +1209,9 @@ typedef struct ipmi_sdr_fru_locator {
uint8_t is_fl_entity;
uint8_t is_fl_instance;
uint8_t is_fl_oem;
- DECL_BITFIELD2(
- is_fl_idlen :6,
+ DECL_BITFIELD3(
+ is_fl_idlen :5,
+ __reserved5 :1,
is_fl_idtype :2);
char is_fl_idstring[1];
} ipmi_sdr_fru_locator_t;
@@ -262,26 +1220,187 @@ typedef struct ipmi_sdr_fru_locator {
#define is_fl_slaveaddr _devid_or_slaveaddr._nonintelligent._is_fl_slaveaddr
/*
- * The remaining SDR types do not have an associated structure, yet.
+ * Management Controller Device Locator Record. See section 43.9
*/
-#define IPMI_SDR_TYPE_FULL_SENSOR 0x01
-#define IPMI_SDR_TYPE_COMPACT_SENSOR 0x02
-#define IPMI_SDR_TYPE_EVENT_ONLY 0x03
-#define IPMI_SDR_TYPE_ENTITY_ASSOCIATION 0x08
-#define IPMI_SDR_TYPE_DEVICE_RELATIVE 0x09
-#define IPMI_SDR_TYPE_MANAGEMENT_DEVICE 0x12
+
+#define IPMI_SDR_TYPE_MANAGEMENT_LOCATOR 0x12
+
+typedef struct ipmi_sdr_management_locator {
+ /* RECORD KEY BYTES */
+ DECL_BITFIELD2(
+ __reserved1 :1,
+ is_ml_devaddr :7);
+ DECL_BITFIELD2(
+ is_ml_channel :4,
+ __reserved2 :4);
+ /* RECORD BODY BYTES */
+ DECL_BITFIELD7(
+ is_ml_init_message :2,
+ is_ml_init_log :1,
+ is_ml_init_controller_log :1,
+ __reserved3 :1,
+ is_ml_static :1,
+ is_ml_acpi_device :1,
+ is_ml_acpi_system :1);
+ DECL_BITFIELD8(
+ is_ml_supp_sensor :1,
+ is_ml_supp_sdr :1,
+ is_ml_supp_sel :1,
+ is_ml_supp_fru :1,
+ is_ml_supp_event_receiver :1,
+ is_ml_supp_event_generator :1,
+ is_ml_supp_bridge :1,
+ is_ml_supp_chassis :1);
+ uint8_t __reserved4;
+ uint16_t __reserved5;
+ uint8_t is_ml_entity_id;
+ uint8_t is_ml_entity_instance;
+ uint8_t is_ml_oem;
+ DECL_BITFIELD3(
+ is_ml_idlen :5,
+ __reserved6 :1,
+ is_ml_idtype :2);
+ char is_ml_idstring[1];
+} ipmi_sdr_management_locator_t;
+
+#define IPMI_MESSAGE_INIT_ENABLE 0x0
+#define IPMI_MESSAGE_INIT_DISABLE 0x1
+#define IPMI_MESSAGE_INIT_NONE 0x2
+
+/*
+ * Management Controller Confirmation Record. See section 43.10
+ */
+
#define IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION 0x13
+
+typedef struct ipmi_sdr_management_confirmation {
+ /* RECORD KEY BYTES */
+ DECL_BITFIELD2(
+ __reserved1 :1,
+ is_mc_slaveaddr :7);
+ uint8_t is_mc_deviceid;
+ DECL_BITFIELD2(
+ is_mc_dev_revision :4,
+ is_mc_channel :4);
+ /* RECORD BODY BYTES */
+ DECL_BITFIELD2(
+ is_mc_major_rev :7,
+ __reserved2 :1);
+ uint8_t is_mc_minor_rev;
+ uint8_t is_mc_impi_ver;
+ uint8_t is_mc_manufacturer[3];
+ uint16_t is_mc_product;
+ uint8_t is_mc_guid[16];
+} ipmi_sdr_management_confirmation_t;
+
+/*
+ * BMC Message Channel Info Record. See esction 43.11.
+ */
+
#define IPMI_SDR_TYPE_BMC_MESSAGE_CHANNEL 0x14
+
+typedef struct ipmi_sdr_bmc_channel {
+ /* RECORD BODY BYTES */
+ struct {
+ DECL_BITFIELD3(
+ is_bc_protocol :4,
+ is_bc_receive_lun :3,
+ is_bc_transmit :1);
+ } is_bc_channel[8];
+ uint8_t is_bc_interrupt_type;
+ uint8_t is_bc_buffer_type;
+ uint8_t __reserved;
+} ipmi_sdr_bmc_channel_t;
+
+/*
+ * OEM Record. See ction 43.12.
+ */
+
#define IPMI_SDR_TYPE_OEM 0xC0
+typedef struct ipmi_sdr_oem {
+ uint8_t is_oem_manufacturer[3];
+ uint8_t is_oem_data[1];
+} ipmi_sdr_oem_t;
+
+/*
+ * Iterate over the SDR repository. This function does the work of parsing the
+ * name when available, and keeping the repository in a consistent state.
+ */
+extern int ipmi_sdr_iter(ipmi_handle_t *,
+ int (*)(ipmi_handle_t *, const char *, ipmi_sdr_t *, void *), void *);
+
/*
* Lookup the given sensor type by name. These functions automatically read in
* and cache the complete SDR repository.
*/
+extern ipmi_sdr_t *ipmi_sdr_lookup(ipmi_handle_t *, const char *);
extern ipmi_sdr_fru_locator_t *ipmi_sdr_lookup_fru(ipmi_handle_t *,
const char *);
extern ipmi_sdr_generic_locator_t *ipmi_sdr_lookup_generic(ipmi_handle_t *,
const char *);
+extern ipmi_sdr_compact_sensor_t *ipmi_sdr_lookup_compact_sensor(
+ ipmi_handle_t *, const char *);
+extern ipmi_sdr_full_sensor_t *ipmi_sdr_lookup_full_sensor(
+ ipmi_handle_t *, const char *);
+
+/*
+ * Entity ID codes. See table 43.13.
+ */
+#define IPMI_ET_UNSPECIFIED 0x00
+#define IPMI_ET_OTHER 0x01
+#define IPMI_ET_UNKNOWN 0x02
+#define IPMI_ET_PROCESSOR 0x03
+#define IPMI_ET_DISK 0x04
+#define IPMI_ET_PERIPHERAL 0x05
+#define IPMI_ET_MANAGEMENT_MODULE 0x06
+#define IPMI_ET_MOTHERBOARD 0x07
+#define IPMI_ET_MEMORY_MODULE 0x08
+#define IPMI_ET_PROCESSOR_MODULE 0x09
+#define IPMI_ET_PSU 0x0A
+#define IPMI_ET_CARD 0x0B
+#define IPMI_ET_FRONT_PANEL 0x0C
+#define IPMI_ET_BACK_PANEL 0x0D
+#define IPMI_ET_POWER_BOARD 0x0E
+#define IPMI_ET_BACKPLANE 0x0F
+#define IPMI_ET_EXPANSION_BOARD 0x10
+#define IPMI_ET_OTHER_BOARD 0x11
+#define IPMI_ET_PROCESSOR_BOARD 0x12
+#define IPMI_ET_POWER_DOMAIN 0x13
+#define IPMI_ET_POWER_CONVERTER 0x14
+#define IPMI_ET_POWER_MANAGEMENT 0x15
+#define IPMI_ET_BACK_CHASSIS 0x16
+#define IPMI_ET_SYSTEM_CHASSIS 0x17
+#define IPMI_ET_SUB_CHASSIS 0x18
+#define IPMI_ET_OTHER_CHASSIS 0x19
+#define IPMI_ET_DISK_BAY 0x1A
+#define IPMI_ET_PERIPHERAL_BAY 0x1B
+#define IPMI_ET_DEVICE_BAY 0x1C
+#define IPMI_ET_FAN 0x1D
+#define IPMI_ET_COOLING_DOMAIN 0x1E
+#define IPMI_ET_CABLE 0x1F
+#define IPMI_ET_MEMORY_DEVICE 0x20
+#define IPMI_ET_MANAGEMENT_SOFTWARE 0x21
+#define IPMI_ET_SYSTEM_FIRMWARE 0x22
+#define IPMI_ET_OS 0x23
+#define IPMI_ET_SYSTEM_BUS 0x24
+#define IPMI_ET_GROUP 0x25
+#define IPMI_ET_REMOTE 0x26
+#define IPMI_ET_ENVIRONMENT 0x27
+#define IPMI_ET_BATTERY 0x28
+#define IPMI_ET_BLADE 0x29
+#define IPMI_ET_SWITCH 0x2A
+#define IPMI_ET_PROCMEM_MODULE 0x2B
+#define IPMI_ET_IO_MODULE 0x2C
+#define IPMI_ET_PROCIO_MODULE 0x2D
+#define IPMI_ET_CONTROLLER_FIRMWARE 0x2E
+#define IPMI_ET_CHANNEL 0x2F
+#define IPMI_ET_PCI 0x30
+#define IPMI_ET_PCIE 0x31
+#define IPMI_ET_SCSI 0x32
+#define IPMI_ET_SATA_SAS 0x33
+#define IPMI_ET_FSB 0x34
+#define IPMI_ET_RTC 0x35
/*
* Get Sensor Reading. See section 35.14.
@@ -294,11 +1413,18 @@ typedef struct ipmi_sensor_reading {
DECL_BITFIELD4(
__reserved1 :5,
isr_state_unavailable :1,
- isr_scanning_disabled :1,
- isr_event_disabled :1);
+ isr_scanning_enabled :1,
+ isr_event_enabled :1);
uint16_t isr_state;
} ipmi_sensor_reading_t;
+#define IPMI_SENSOR_THRESHOLD_LOWER_NONCRIT 0x0001
+#define IPMI_SENSOR_THRESHOLD_LOWER_CRIT 0x0002
+#define IPMI_SENSOR_THRESHOLD_LOWER_NONRECOV 0x0004
+#define IPMI_SENSOR_THRESHOLD_UPPER_NONCRIT 0x0008
+#define IPMI_SENSOR_THRESHOLD_UPPER_CRIT 0x0010
+#define IPMI_SENSOR_THRESHOLD_UPPER_NONRECOV 0x0020
+
extern ipmi_sensor_reading_t *ipmi_get_sensor_reading(ipmi_handle_t *, uint8_t);
/*
@@ -381,9 +1507,46 @@ typedef struct ipmi_fru_prod_info
char ifpi_asset_tag[FRU_INFO_MAXLEN];
} ipmi_fru_prod_info_t;
-int ipmi_fru_read(ipmi_handle_t *, ipmi_sdr_fru_locator_t *, char **);
-int ipmi_fru_parse_board(ipmi_handle_t *, char *, ipmi_fru_brd_info_t *);
-int ipmi_fru_parse_product(ipmi_handle_t *, char *, ipmi_fru_prod_info_t *);
+extern int ipmi_fru_read(ipmi_handle_t *, ipmi_sdr_fru_locator_t *, char **);
+extern int ipmi_fru_parse_board(ipmi_handle_t *, char *, ipmi_fru_brd_info_t *);
+extern int ipmi_fru_parse_product(ipmi_handle_t *, char *,
+ ipmi_fru_prod_info_t *);
+
+/*
+ * Routines to convert from entity and sensors defines into text strings.
+ */
+void ipmi_entity_name(uint8_t, char *, size_t);
+void ipmi_sensor_type_name(uint8_t, char *, size_t);
+void ipmi_sensor_reading_name(uint8_t, uint8_t, char *, size_t);
+
+/*
+ * Entity management. IPMI has a notion of 'entities', but these are not
+ * directly accessible from any commands. Instead, their existence is inferred
+ * from examining the SDR repository. Since this is rather unwieldy, and
+ * iterating over entities is a common operation, libipmi provides an entity
+ * abstraction that hides the implementation details. This handles entity
+ * groupings as well as SDR associations.
+ */
+typedef struct ipmi_entity {
+ uint8_t ie_type;
+ uint8_t ie_instance;
+ uint8_t ie_children;
+ boolean_t ie_logical;
+} ipmi_entity_t;
+
+extern int ipmi_entity_iter(ipmi_handle_t *, int (*)(ipmi_handle_t *,
+ ipmi_entity_t *, void *), void *);
+extern int ipmi_entity_iter_sdr(ipmi_handle_t *, ipmi_entity_t *,
+ int (*)(ipmi_handle_t *, ipmi_entity_t *, const char *, ipmi_sdr_t *,
+ void *), void *);
+extern int ipmi_entity_iter_children(ipmi_handle_t *, ipmi_entity_t *,
+ int (*)(ipmi_handle_t *, ipmi_entity_t *, void *), void *);
+extern ipmi_entity_t *ipmi_entity_lookup(ipmi_handle_t *, uint8_t,
+ uint8_t);
+extern ipmi_entity_t *ipmi_entity_lookup_sdr(ipmi_handle_t *, const char *);
+extern ipmi_entity_t *ipmi_entity_parent(ipmi_handle_t *, ipmi_entity_t *);
+extern int ipmi_entity_present(ipmi_handle_t *, ipmi_entity_t *, boolean_t *);
+extern int ipmi_entity_present_sdr(ipmi_handle_t *, ipmi_sdr_t *, boolean_t *);
/*
* User management. The raw functions are private to libipmi, and only the
@@ -405,7 +1568,6 @@ typedef struct ipmi_user {
boolean_t iu_ipmi_msg_enable;
boolean_t iu_link_auth_enable;
uint8_t iu_priv;
- struct ipmi_user *iu_next;
} ipmi_user_t;
extern int ipmi_user_iter(ipmi_handle_t *,
diff --git a/usr/src/lib/libipmi/common/mapfile-vers b/usr/src/lib/libipmi/common/mapfile-vers
index da3f2be56d..beb74afb00 100644
--- a/usr/src/lib/libipmi/common/mapfile-vers
+++ b/usr/src/lib/libipmi/common/mapfile-vers
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -27,17 +27,41 @@
SUNWprivate_1.1 {
global:
ipmi_close;
+ ipmi_entity_iter;
+ ipmi_entity_iter_children;
+ ipmi_entity_iter_sdr;
+ ipmi_entity_lookup;
+ ipmi_entity_lookup_sdr;
+ ipmi_entity_name;
+ ipmi_entity_parent;
+ ipmi_entity_present;
+ ipmi_entity_present_sdr;
ipmi_errmsg;
ipmi_errno;
+ ipmi_firmware_version;
ipmi_fru_parse_board;
ipmi_fru_parse_product;
ipmi_fru_read;
ipmi_get_deviceid;
ipmi_get_sensor_reading;
ipmi_open;
+ ipmi_sdr_changed;
ipmi_sdr_get;
+ ipmi_sdr_iter;
+ ipmi_sdr_lookup;
+ ipmi_sdr_lookup_compact_sensor;
+ ipmi_sdr_lookup_full_sensor;
ipmi_sdr_lookup_fru;
ipmi_sdr_lookup_generic;
+ ipmi_sdr_refresh;
+ ipmi_sel_get_entry;
+ ipmi_sel_get_info;
+ ipmi_sel_get_time;
+ ipmi_sel_get_utc_offset;
+ ipmi_sel_set_time;
+ ipmi_sel_set_utc_offset;
+ ipmi_sensor_reading_name;
+ ipmi_sensor_type_name;
ipmi_send;
ipmi_set_sensor_reading;
ipmi_sunoem_led_get;
diff --git a/usr/src/lib/libipmi/common/mktables.sh b/usr/src/lib/libipmi/common/mktables.sh
new file mode 100644
index 0000000000..9377b1b8c2
--- /dev/null
+++ b/usr/src/lib/libipmi/common/mktables.sh
@@ -0,0 +1,109 @@
+#!/bin/sh
+
+#
+# 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 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+
+#
+# Construct translation tables for defines in libipmi.h to translate to readable
+# strings.
+#
+
+if [ $# -ne 1 ]; then
+ echo >&2 "USAGE: $0 <path to libimpi.h>"
+ exit 1
+fi
+
+if [ -r $1 ]; then
+ libipmi_h=$1
+else
+ echo >&2 "USAGE: $0 <path to libimpi.h>"
+ echo >&2 "Make sure libipmi.h exists and is readable"
+ exit 1
+fi
+
+echo "\
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident \"%Z%%M% %I% %E% SMI\"
+
+#include <libipmi.h>
+#include <ipmi_impl.h>"
+
+#
+# Error table.
+#
+echo "
+ipmi_name_trans_t ipmi_errno_table[] = {"
+
+pattern=" \(EIPMI_[0-9A-Z_]*\)[^ \/]*\/\* \(.*\) \*\/$"
+replace=" { \1, \"\2\" },"
+
+cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1
+
+echo "\t{ 0, NULL }
+};"
+
+#
+# Entity table.
+#
+echo "\nipmi_name_trans_t ipmi_entity_table[] = {"
+
+pattern="#define IPMI_ET_\([A-Z0-9_]*\).*\$"
+replace=" { IPMI_ET_\1, \"\1\" },"
+
+cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1
+
+echo "\t{ 0, NULL }
+};"
+
+#
+# Sensor types.
+#
+echo "\nipmi_name_trans_t ipmi_sensor_type_table[] = {"
+
+pattern="#define IPMI_ST_\([A-Z0-9_]*\).*\$"
+replace=" { IPMI_ST_\1, \"\1\" },"
+
+cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1
+
+echo "\t{ 0, NULL }
+};"
+
+#
+# Reading types.
+#
+echo "\nipmi_name_trans_t ipmi_reading_type_table[] = {"
+
+pattern="#define IPMI_RT_\([A-Z0-9_]*\).*\$"
+replace=" { IPMI_RT_\1, \"\1\" },"
+
+cat $libipmi_h | sed -n "s/$pattern/$replace/p" || exit 1
+
+echo "\t{ 0, NULL }
+};"
diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_com b/usr/src/pkgdefs/SUNWfmd/prototype_com
index d1dd820957..c88e791cfe 100644
--- a/usr/src/pkgdefs/SUNWfmd/prototype_com
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_com
@@ -20,7 +20,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -66,6 +66,7 @@ f none usr/lib/fm/fmd/fmd 555 root bin
f none usr/lib/fm/fmd/fminject 555 root bin
f none usr/lib/fm/fmd/fmsim 555 root bin
f none usr/lib/fm/fmd/fmtopo 555 root bin
+f none usr/lib/fm/fmd/ipmitopo 555 root bin
d none usr/lib/fm/fmd/plugins 755 root bin
f none usr/lib/fm/fmd/plugins/cpumem-retire.conf 644 root bin
f none usr/lib/fm/fmd/plugins/cpumem-retire.so 555 root bin
@@ -132,6 +133,7 @@ d none usr/lib/fm/topo/maps 755 root bin
f none usr/lib/fm/topo/maps/xfp-hc-topology.xml 444 root bin
d none usr/lib/fm/topo/plugins 755 root bin
f none usr/lib/fm/topo/plugins/disk.so 555 root bin
+f none usr/lib/fm/topo/plugins/ipmi.so 555 root bin
f none usr/lib/fm/topo/plugins/xfp.so 555 root bin
d none usr/lib/locale 755 root bin
d none usr/lib/locale/C 755 root bin
diff --git a/usr/src/pkgdefs/SUNWfmd/prototype_i386 b/usr/src/pkgdefs/SUNWfmd/prototype_i386
index e4fb72787c..4866dcd088 100644
--- a/usr/src/pkgdefs/SUNWfmd/prototype_i386
+++ b/usr/src/pkgdefs/SUNWfmd/prototype_i386
@@ -20,7 +20,7 @@
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -82,6 +82,8 @@ f none usr/platform/i86pc/lib/fm/topo/plugins/hostbridge.so 555 root bin
f none usr/platform/i86pc/lib/fm/topo/plugins/pcibus.so 555 root bin
d none usr/platform/i86pc/lib/fm/topo/maps 755 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/chip-hc-topology.xml 444 root bin
+f none usr/platform/i86pc/lib/fm/topo/maps/fan-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/i86pc-hc-topology.xml 444 root bin
+f none usr/platform/i86pc/lib/fm/topo/maps/psu-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/Sun-Fire-X4500-hc-topology.xml 444 root bin
f none usr/platform/i86pc/lib/fm/topo/maps/Sun-Fire-X4540-hc-topology.xml 444 root bin