diff options
author | robj <none@none> | 2008-02-22 15:04:09 -0800 |
---|---|---|
committer | robj <none@none> | 2008-02-22 15:04:09 -0800 |
commit | 2eeaed14a5e2ed9bd811643ad5bffc3510ca0310 (patch) | |
tree | c67130267b295fc81a2bfe2dbc26ce790c5c3bed /usr/src | |
parent | 387214a609155b1c9d15e8e68043b80bd549b92b (diff) | |
download | illumos-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')
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&+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&-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&-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&-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&-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&+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&-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&-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&-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&-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&+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 |