summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-23 15:03:00 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-23 15:03:00 +0200
commitb32d92e890caac903491116e9d817aa780c0323b (patch)
tree5a135c37eaa9ac94772819a28ce5beedd18e5c4a /lib
parentc3445516ecd58e97de483cf4b7fafcc1104890d7 (diff)
Imported Upstream version 1.8.14upstream/1.8.14
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am48
-rw-r--r--lib/Makefile.in601
-rw-r--r--lib/dimm_spd.c943
-rw-r--r--lib/helper.c789
-rw-r--r--lib/hpm2.c289
-rw-r--r--lib/ipmi_channel.c903
-rw-r--r--lib/ipmi_chassis.c1393
-rwxr-xr-xlib/ipmi_dcmi.c2193
-rw-r--r--lib/ipmi_delloem.c4225
-rw-r--r--lib/ipmi_ekanalyzer.c4195
-rw-r--r--lib/ipmi_event.c642
-rw-r--r--lib/ipmi_firewall.c1191
-rw-r--r--lib/ipmi_fru.c5209
-rw-r--r--lib/ipmi_fwum.c1132
-rw-r--r--lib/ipmi_gendev.c640
-rw-r--r--lib/ipmi_hpmfwupg.c2624
-rwxr-xr-xlib/ipmi_ime.c1044
-rw-r--r--lib/ipmi_isol.c828
-rw-r--r--lib/ipmi_kontronoem.c808
-rw-r--r--lib/ipmi_lanp.c2352
-rw-r--r--lib/ipmi_main.c1063
-rw-r--r--lib/ipmi_mc.c1112
-rw-r--r--lib/ipmi_oem.c168
-rw-r--r--lib/ipmi_pef.c890
-rw-r--r--lib/ipmi_picmg.c2371
-rw-r--r--lib/ipmi_raw.c432
-rw-r--r--lib/ipmi_sdr.c4835
-rw-r--r--lib/ipmi_sdradd.c668
-rw-r--r--lib/ipmi_sel.c3094
-rw-r--r--lib/ipmi_sensor.c964
-rw-r--r--lib/ipmi_session.c459
-rw-r--r--lib/ipmi_sol.c2098
-rw-r--r--lib/ipmi_strings.c578
-rw-r--r--lib/ipmi_sunoem.c2434
-rw-r--r--lib/ipmi_tsol.c608
-rw-r--r--lib/ipmi_user.c836
-rw-r--r--lib/log.c156
37 files changed, 54815 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..d878b11
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,48 @@
+# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# Redistribution of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# Redistribution in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# Neither the name of Sun Microsystems, Inc. or the names of
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# This software is provided "AS IS," without a warranty of any kind.
+# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+INCLUDES = -I$(top_srcdir)/include
+MAINTAINERCLEANFILES = Makefile.in
+
+noinst_LTLIBRARIES = libipmitool.la
+libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \
+ ipmi_lanp.c ipmi_fru.c ipmi_chassis.c ipmi_mc.c log.c \
+ dimm_spd.c ipmi_sensor.c ipmi_channel.c ipmi_event.c \
+ ipmi_session.c ipmi_strings.c ipmi_user.c ipmi_raw.c \
+ ipmi_oem.c ipmi_isol.c ipmi_sunoem.c ipmi_fwum.c ipmi_picmg.c \
+ ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c \
+ ipmi_hpmfwupg.c ipmi_sdradd.c ipmi_ekanalyzer.c ipmi_gendev.c \
+ ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c hpm2.c \
+ ../src/plugins/lan/md5.c ../src/plugins/lan/md5.h
+
+libipmitool_la_LDFLAGS = -export-dynamic
+libipmitool_la_LIBADD = -lm
+libipmitool_la_DEPENDENCIES =
+
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..0925a1f
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,601 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# Redistribution of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# Redistribution in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# Neither the name of Sun Microsystems, Inc. or the names of
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# This software is provided "AS IS," without a warranty of any kind.
+# ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+# INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+# PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+# SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+# OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+# SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+# OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+# PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+# LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+# EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = lib
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am_libipmitool_la_OBJECTS = helper.lo ipmi_sdr.lo ipmi_sel.lo \
+ ipmi_sol.lo ipmi_pef.lo ipmi_lanp.lo ipmi_fru.lo \
+ ipmi_chassis.lo ipmi_mc.lo log.lo dimm_spd.lo ipmi_sensor.lo \
+ ipmi_channel.lo ipmi_event.lo ipmi_session.lo ipmi_strings.lo \
+ ipmi_user.lo ipmi_raw.lo ipmi_oem.lo ipmi_isol.lo \
+ ipmi_sunoem.lo ipmi_fwum.lo ipmi_picmg.lo ipmi_main.lo \
+ ipmi_tsol.lo ipmi_firewall.lo ipmi_kontronoem.lo \
+ ipmi_hpmfwupg.lo ipmi_sdradd.lo ipmi_ekanalyzer.lo \
+ ipmi_gendev.lo ipmi_ime.lo ipmi_delloem.lo ipmi_dcmi.lo \
+ hpm2.lo md5.lo
+libipmitool_la_OBJECTS = $(am_libipmitool_la_OBJECTS)
+libipmitool_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libipmitool_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libipmitool_la_SOURCES)
+DIST_SOURCES = $(libipmitool_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+ARCH = @ARCH@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASEDIR = @BASEDIR@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTRO = @DISTRO@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTF_BMC = @INTF_BMC@
+INTF_BMC_LIB = @INTF_BMC_LIB@
+INTF_DUMMY = @INTF_DUMMY@
+INTF_DUMMY_LIB = @INTF_DUMMY_LIB@
+INTF_FREE = @INTF_FREE@
+INTF_FREE_LIB = @INTF_FREE_LIB@
+INTF_IMB = @INTF_IMB@
+INTF_IMB_LIB = @INTF_IMB_LIB@
+INTF_LAN = @INTF_LAN@
+INTF_LANPLUS = @INTF_LANPLUS@
+INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@
+INTF_LAN_LIB = @INTF_LAN_LIB@
+INTF_LIPMI = @INTF_LIPMI@
+INTF_LIPMI_LIB = @INTF_LIPMI_LIB@
+INTF_OPEN = @INTF_OPEN@
+INTF_OPEN_LIB = @INTF_OPEN_LIB@
+INTF_SERIAL = @INTF_SERIAL@
+INTF_SERIAL_LIB = @INTF_SERIAL_LIB@
+IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OS = @OS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POW_LIB = @POW_LIB@
+PSTAMP = @PSTAMP@
+RANLIB = @RANLIB@
+RPMBUILD = @RPMBUILD@
+RPM_RELEASE = @RPM_RELEASE@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_configure_args = @ac_configure_args@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(top_srcdir)/include
+MAINTAINERCLEANFILES = Makefile.in
+noinst_LTLIBRARIES = libipmitool.la
+libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \
+ ipmi_lanp.c ipmi_fru.c ipmi_chassis.c ipmi_mc.c log.c \
+ dimm_spd.c ipmi_sensor.c ipmi_channel.c ipmi_event.c \
+ ipmi_session.c ipmi_strings.c ipmi_user.c ipmi_raw.c \
+ ipmi_oem.c ipmi_isol.c ipmi_sunoem.c ipmi_fwum.c ipmi_picmg.c \
+ ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c \
+ ipmi_hpmfwupg.c ipmi_sdradd.c ipmi_ekanalyzer.c ipmi_gendev.c \
+ ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c hpm2.c \
+ ../src/plugins/lan/md5.c ../src/plugins/lan/md5.h
+
+libipmitool_la_LDFLAGS = -export-dynamic
+libipmitool_la_LIBADD = -lm
+libipmitool_la_DEPENDENCIES =
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign lib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libipmitool.la: $(libipmitool_la_OBJECTS) $(libipmitool_la_DEPENDENCIES) $(EXTRA_libipmitool_la_DEPENDENCIES)
+ $(libipmitool_la_LINK) $(libipmitool_la_OBJECTS) $(libipmitool_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dimm_spd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helper.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hpm2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_channel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_chassis.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_dcmi.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_delloem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_ekanalyzer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_event.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_firewall.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_fru.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_fwum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_gendev.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_hpmfwupg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_ime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_isol.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_kontronoem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_lanp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_main.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_mc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_oem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_pef.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_picmg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_raw.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sdr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sdradd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sensor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_session.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sol.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_strings.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sunoem.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_tsol.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_user.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+md5.lo: ../src/plugins/lan/md5.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT md5.lo -MD -MP -MF $(DEPDIR)/md5.Tpo -c -o md5.lo `test -f '../src/plugins/lan/md5.c' || echo '$(srcdir)/'`../src/plugins/lan/md5.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/md5.Tpo $(DEPDIR)/md5.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../src/plugins/lan/md5.c' object='md5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o md5.lo `test -f '../src/plugins/lan/md5.c' || echo '$(srcdir)/'`../src/plugins/lan/md5.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/dimm_spd.c b/lib/dimm_spd.c
new file mode 100644
index 0000000..1f27de2
--- /dev/null
+++ b/lib/dimm_spd.c
@@ -0,0 +1,943 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_fru.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+extern int verbose;
+
+/*
+ * Also, see ipmi_fru.c.
+ *
+ * Apparently some systems have problems with FRU access greater than 16 bytes
+ * at a time, even when using byte (not word) access. In order to ensure we
+ * work with the widest variety of hardware request size is capped at 16 bytes.
+ * Since this may result in slowdowns on some systems with lots of FRU data you
+ * can change this define to enable larger (up to 32 bytes at a time) access.
+ */
+#define FRU_DATA_RQST_SIZE 16;
+
+const struct valstr spd_memtype_vals[] = {
+ { 0x01, "STD FPM DRAM" },
+ { 0x02, "EDO" },
+ { 0x04, "SDRAM" },
+ { 0x05, "ROM" },
+ { 0x06, "DDR SGRAM" },
+ { 0x07, "DDR SDRAM" },
+ { 0x08, "DDR2 SDRAM" },
+ { 0x09, "DDR2 SDRAM FB-DIMM" },
+ { 0x0A, "DDR2 SDRAM FB-DIMM Probe" },
+ { 0x0B, "DDR3 SDRAM" },
+ { 0x00, NULL },
+};
+
+const struct valstr ddr3_density_vals[] =
+{
+ { 0, "256 Mb" },
+ { 1, "512 Mb" },
+ { 2, "1 Gb" },
+ { 3, "2 Gb" },
+ { 4, "4 Gb" },
+ { 5, "8 Gb" },
+ { 6, "16 Gb" },
+ { 0x00, NULL },
+};
+
+const struct valstr ddr3_banks_vals[] =
+{
+ { 0, "3 (8 Banks)" },
+ { 1, "4 (16 Banks)" },
+ { 2, "5 (32 Banks)" },
+ { 3, "6 (64 Banks)" },
+ { 0x00, NULL },
+};
+
+const struct valstr ddr3_ecc_vals[] =
+{
+ { 0, "0 bits" },
+ { 1, "8 bits" },
+ { 0x00, NULL },
+};
+
+const struct valstr spd_config_vals[] = {
+ { 0x00, "None" },
+ { 0x01, "Parity" },
+ { 0x02, "ECC" },
+ { 0x04, "Addr Cmd Parity" },
+ { 0x00, NULL },
+};
+
+const struct valstr spd_voltage_vals[] = {
+ { 0x00, "5.0V TTL" },
+ { 0x01, "LVTTL" },
+ { 0x02, "HSTL 1.5V" },
+ { 0x03, "SSTL 3.3V" },
+ { 0x04, "SSTL 2.5V" },
+ { 0x05, "SSTL 1.8V" },
+ { 0x00, NULL },
+};
+
+/*
+ * JEDEC Standard Manufacturers Identification Code
+ * publication JEP106N, December 2003
+ */
+
+const struct valstr jedec_id1_vals[] = {
+ { 0x01, "AMD" },
+ { 0x02, "AMI" },
+ { 0x83, "Fairchild" },
+ { 0x04, "Fujitsu" },
+ { 0x85, "GTE" },
+ { 0x86, "Harris" },
+ { 0x07, "Hitachi" },
+ { 0x08, "Inmos" },
+ { 0x89, "Intel" },
+ { 0x8a, "I.T.T." },
+ { 0x0b, "Intersil" },
+ { 0x8c, "Monolithic Memories" },
+ { 0x0d, "Mostek" },
+ { 0x0e, "Motorola" },
+ { 0x8f, "National" },
+ { 0x10, "NEC" },
+ { 0x91, "RCA" },
+ { 0x92, "Raytheon" },
+ { 0x13, "Conexant (Rockwell)" },
+ { 0x94, "Seeq" },
+ { 0x15, "Philips Semi. (Signetics)" },
+ { 0x16, "Synertek" },
+ { 0x97, "Texas Instruments" },
+ { 0x98, "Toshiba" },
+ { 0x19, "Xicor" },
+ { 0x1a, "Zilog" },
+ { 0x9b, "Eurotechnique" },
+ { 0x1c, "Mitsubishi" },
+ { 0x9d, "Lucent (AT&T)" },
+ { 0x9e, "Exel" },
+ { 0x1f, "Atmel" },
+ { 0x20, "SGS/Thomson" },
+ { 0xa1, "Lattice Semi." },
+ { 0xa2, "NCR" },
+ { 0x23, "Wafer Scale Integration" },
+ { 0xa4, "IBM" },
+ { 0x25, "Tristar" },
+ { 0x26, "Visic" },
+ { 0xa7, "Intl. CMOS Technology" },
+ { 0xa8, "SSSI" },
+ { 0x29, "Microchip Technology" },
+ { 0x2a, "Ricoh Ltd." },
+ { 0xab, "VLSI" },
+ { 0x2c, "Micron Technology" },
+ { 0xad, "Hyundai Electronics" },
+ { 0xae, "OKI Semiconductor" },
+ { 0x2f, "ACTEL" },
+ { 0xb0, "Sharp" },
+ { 0x31, "Catalyst" },
+ { 0x32, "Panasonic" },
+ { 0xb3, "IDT" },
+ { 0x34, "Cypress" },
+ { 0xb5, "DEC" },
+ { 0xb6, "LSI Logic" },
+ { 0x37, "Zarlink" },
+ { 0x38, "UTMC" },
+ { 0xb9, "Thinking Machine" },
+ { 0xba, "Thomson CSF" },
+ { 0x3b, "Integrated CMOS(Vertex)" },
+ { 0xbc, "Honeywell" },
+ { 0x3d, "Tektronix" },
+ { 0x3e, "Sun Microsystems" },
+ { 0xbf, "SST" },
+ { 0x40, "MOSEL" },
+ { 0xc1, "Infineon" },
+ { 0xc2, "Macronix" },
+ { 0x43, "Xerox" },
+ { 0xc4, "Plus Logic" },
+ { 0x45, "SunDisk" },
+ { 0x46, "Elan Circuit Tech." },
+ { 0xc7, "European Silicon Str." },
+ { 0xc8, "Apple Computer" },
+ { 0xc9, "Xilinx" },
+ { 0x4a, "Compaq" },
+ { 0xcb, "Protocol Engines" },
+ { 0x4c, "SCI" },
+ { 0xcd, "Seiko Instruments" },
+ { 0xce, "Samsung" },
+ { 0x4f, "I3 Design System" },
+ { 0xd0, "Klic" },
+ { 0x51, "Crosspoint Solutions" },
+ { 0x52, "Alliance Semiconductor" },
+ { 0xd3, "Tandem" },
+ { 0x54, "Hewlett-Packard" },
+ { 0xd5, "Intg. Silicon Solutions" },
+ { 0xd6, "Brooktree" },
+ { 0x57, "New Media" },
+ { 0x58, "MHS Electronic" },
+ { 0xd9, "Performance Semi." },
+ { 0xda, "Winbond Electronic" },
+ { 0x5b, "Kawasaki Steel" },
+ { 0xdc, "Bright Micro" },
+ { 0x5d, "TECMAR" },
+ { 0x5e, "Exar" },
+ { 0xdf, "PCMCIA" },
+ { 0xe0, "LG Semiconductor" },
+ { 0x61, "Northern Telecom" },
+ { 0x62, "Sanyo" },
+ { 0xe3, "Array Microsystems" },
+ { 0x64, "Crystal Semiconductor" },
+ { 0xe5, "Analog Devices" },
+ { 0xe6, "PMC-Sierra" },
+ { 0x67, "Asparix" },
+ { 0x68, "Convex Computer" },
+ { 0xe9, "Quality Semiconductor" },
+ { 0xea, "Nimbus Technology" },
+ { 0x6b, "Transwitch" },
+ { 0xec, "Micronas (ITT Intermetall)" },
+ { 0x6d, "Cannon" },
+ { 0x6e, "Altera" },
+ { 0xef, "NEXCOM" },
+ { 0x70, "QUALCOMM" },
+ { 0xf1, "Sony" },
+ { 0xf2, "Cray Research" },
+ { 0x73, "AMS (Austria Micro)" },
+ { 0xf4, "Vitesse" },
+ { 0x75, "Aster Electronics" },
+ { 0x76, "Bay Networks (Synoptic)" },
+ { 0xf7, "Zentrum" },
+ { 0xf8, "TRW" },
+ { 0x79, "Thesys" },
+ { 0x7a, "Solbourne Computer" },
+ { 0xfb, "Allied-Signal" },
+ { 0x7c, "Dialog" },
+ { 0xfd, "Media Vision" },
+ { 0xfe, "Level One Communication" },
+ { 0x00, NULL },
+};
+
+const struct valstr jedec_id2_vals[] = {
+ { 0x01, "Cirrus Logic" },
+ { 0x02, "National Instruments" },
+ { 0x83, "ILC Data Device" },
+ { 0x04, "Alcatel Mietec" },
+ { 0x85, "Micro Linear" },
+ { 0x86, "Univ. of NC" },
+ { 0x07, "JTAG Technologies" },
+ { 0x08, "Loral" },
+ { 0x89, "Nchip" },
+ { 0x8A, "Galileo Tech" },
+ { 0x0B, "Bestlink Systems" },
+ { 0x8C, "Graychip" },
+ { 0x0D, "GENNUM" },
+ { 0x0E, "VideoLogic" },
+ { 0x8F, "Robert Bosch" },
+ { 0x10, "Chip Express" },
+ { 0x91, "DATARAM" },
+ { 0x92, "United Microelec Corp." },
+ { 0x13, "TCSI" },
+ { 0x94, "Smart Modular" },
+ { 0x15, "Hughes Aircraft" },
+ { 0x16, "Lanstar Semiconductor" },
+ { 0x97, "Qlogic" },
+ { 0x98, "Kingston" },
+ { 0x19, "Music Semi" },
+ { 0x1A, "Ericsson Components" },
+ { 0x9B, "SpaSE" },
+ { 0x1C, "Eon Silicon Devices" },
+ { 0x9D, "Programmable Micro Corp" },
+ { 0x9E, "DoD" },
+ { 0x1F, "Integ. Memories Tech." },
+ { 0x20, "Corollary Inc." },
+ { 0xA1, "Dallas Semiconductor" },
+ { 0xA2, "Omnivision" },
+ { 0x23, "EIV(Switzerland)" },
+ { 0xA4, "Novatel Wireless" },
+ { 0x25, "Zarlink (formerly Mitel)" },
+ { 0x26, "Clearpoint" },
+ { 0xA7, "Cabletron" },
+ { 0xA8, "Silicon Technology" },
+ { 0x29, "Vanguard" },
+ { 0x2A, "Hagiwara Sys-Com" },
+ { 0xAB, "Vantis" },
+ { 0x2C, "Celestica" },
+ { 0xAD, "Century" },
+ { 0xAE, "Hal Computers" },
+ { 0x2F, "Rohm Company Ltd." },
+ { 0xB0, "Juniper Networks" },
+ { 0x31, "Libit Signal Processing" },
+ { 0x32, "Enhanced Memories Inc." },
+ { 0xB3, "Tundra Semiconductor" },
+ { 0x34, "Adaptec Inc." },
+ { 0xB5, "LightSpeed Semi." },
+ { 0xB6, "ZSP Corp." },
+ { 0x37, "AMIC Technology" },
+ { 0x38, "Adobe Systems" },
+ { 0xB9, "Dynachip" },
+ { 0xBA, "PNY Electronics" },
+ { 0x3B, "Newport Digital" },
+ { 0xBC, "MMC Networks" },
+ { 0x3D, "T Square" },
+ { 0x3E, "Seiko Epson" },
+ { 0xBF, "Broadcom" },
+ { 0x40, "Viking Components" },
+ { 0xC1, "V3 Semiconductor" },
+ { 0xC2, "Flextronics (formerly Orbit)" },
+ { 0x43, "Suwa Electronics" },
+ { 0xC4, "Transmeta" },
+ { 0x45, "Micron CMS" },
+ { 0x46, "American Computer & Digital Components Inc" },
+ { 0xC7, "Enhance 3000 Inc" },
+ { 0xC8, "Tower Semiconductor" },
+ { 0x49, "CPU Design" },
+ { 0x4A, "Price Point" },
+ { 0xCB, "Maxim Integrated Product" },
+ { 0x4C, "Tellabs" },
+ { 0xCD, "Centaur Technology" },
+ { 0xCE, "Unigen Corporation" },
+ { 0x4F, "Transcend Information" },
+ { 0xD0, "Memory Card Technology" },
+ { 0x51, "CKD Corporation Ltd." },
+ { 0x52, "Capital Instruments, Inc." },
+ { 0xD3, "Aica Kogyo, Ltd." },
+ { 0x54, "Linvex Technology" },
+ { 0xD5, "MSC Vertriebs GmbH" },
+ { 0xD6, "AKM Company, Ltd." },
+ { 0x57, "Dynamem, Inc." },
+ { 0x58, "NERA ASA" },
+ { 0xD9, "GSI Technology" },
+ { 0xDA, "Dane-Elec (C Memory)" },
+ { 0x5B, "Acorn Computers" },
+ { 0xDC, "Lara Technology" },
+ { 0x5D, "Oak Technology, Inc." },
+ { 0x5E, "Itec Memory" },
+ { 0xDF, "Tanisys Technology" },
+ { 0xE0, "Truevision" },
+ { 0x61, "Wintec Industries" },
+ { 0x62, "Super PC Memory" },
+ { 0xE3, "MGV Memory" },
+ { 0x64, "Galvantech" },
+ { 0xE5, "Gadzoox Nteworks" },
+ { 0xE6, "Multi Dimensional Cons." },
+ { 0x67, "GateField" },
+ { 0x68, "Integrated Memory System" },
+ { 0xE9, "Triscend" },
+ { 0xEA, "XaQti" },
+ { 0x6B, "Goldenram" },
+ { 0xEC, "Clear Logic" },
+ { 0x6D, "Cimaron Communications" },
+ { 0x6E, "Nippon Steel Semi. Corp." },
+ { 0xEF, "Advantage Memory" },
+ { 0x70, "AMCC" },
+ { 0xF1, "LeCroy" },
+ { 0xF2, "Yamaha Corporation" },
+ { 0x73, "Digital Microwave" },
+ { 0xF4, "NetLogic Microsystems" },
+ { 0x75, "MIMOS Semiconductor" },
+ { 0x76, "Advanced Fibre" },
+ { 0xF7, "BF Goodrich Data." },
+ { 0xF8, "Epigram" },
+ { 0x79, "Acbel Polytech Inc." },
+ { 0x7A, "Apacer Technology" },
+ { 0xFB, "Admor Memory" },
+ { 0x7C, "FOXCONN" },
+ { 0xFD, "Quadratics Superconductor" },
+ { 0xFE, "3COM" },
+ { 0x00, NULL },
+};
+
+const struct valstr jedec_id3_vals[] = {
+ { 0x01, "Camintonn Corporation" },
+ { 0x02, "ISOA Incorporated" },
+ { 0x83, "Agate Semiconductor" },
+ { 0x04, "ADMtek Incorporated" },
+ { 0x85, "HYPERTEC" },
+ { 0x86, "Adhoc Technologies" },
+ { 0x07, "MOSAID Technologies" },
+ { 0x08, "Ardent Technologies" },
+ { 0x89, "Switchcore" },
+ { 0x8A, "Cisco Systems, Inc." },
+ { 0x0B, "Allayer Technologies" },
+ { 0x8C, "WorkX AG" },
+ { 0x0D, "Oasis Semiconductor" },
+ { 0x0E, "Novanet Semiconductor" },
+ { 0x8F, "E-M Solutions" },
+ { 0x10, "Power General" },
+ { 0x91, "Advanced Hardware Arch." },
+ { 0x92, "Inova Semiconductors GmbH" },
+ { 0x13, "Telocity" },
+ { 0x94, "Delkin Devices" },
+ { 0x15, "Symagery Microsystems" },
+ { 0x16, "C-Port Corporation" },
+ { 0x97, "SiberCore Technologies" },
+ { 0x98, "Southland Microsystems" },
+ { 0x19, "Malleable Technologies" },
+ { 0x1A, "Kendin Communications" },
+ { 0x9B, "Great Technology Microcomputer" },
+ { 0x1C, "Sanmina Corporation" },
+ { 0x9D, "HADCO Corporation" },
+ { 0x9E, "Corsair" },
+ { 0x1F, "Actrans System Inc." },
+ { 0x20, "ALPHA Technologies" },
+ { 0xA1, "Cygnal Integrated Products Incorporated" },
+ { 0xA2, "Artesyn Technologies" },
+ { 0x23, "Align Manufacturing" },
+ { 0xA4, "Peregrine Semiconductor" },
+ { 0x25, "Chameleon Systems" },
+ { 0x26, "Aplus Flash Technology" },
+ { 0xA7, "MIPS Technologies" },
+ { 0xA8, "Chrysalis ITS" },
+ { 0x29, "ADTEC Corporation" },
+ { 0x2A, "Kentron Technologies" },
+ { 0xAB, "Win Technologies" },
+ { 0x2C, "ASIC Designs Inc" },
+ { 0xAD, "Extreme Packet Devices" },
+ { 0xAE, "RF Micro Devices" },
+ { 0x2F, "Siemens AG" },
+ { 0xB0, "Sarnoff Corporation" },
+ { 0x31, "Itautec Philco SA" },
+ { 0x32, "Radiata Inc." },
+ { 0xB3, "Benchmark Elect. (AVEX)" },
+ { 0x34, "Legend" },
+ { 0xB5, "SpecTek Incorporated" },
+ { 0xB6, "Hi/fn" },
+ { 0x37, "Enikia Incorporated" },
+ { 0x38, "SwitchOn Networks" },
+ { 0xB9, "AANetcom Incorporated" },
+ { 0xBA, "Micro Memory Bank" },
+ { 0x3B, "ESS Technology" },
+ { 0xBC, "Virata Corporation" },
+ { 0x3D, "Excess Bandwidth" },
+ { 0x3E, "West Bay Semiconductor" },
+ { 0xBF, "DSP Group" },
+ { 0x40, "Newport Communications" },
+ { 0xC1, "Chip2Chip Incorporated" },
+ { 0xC2, "Phobos Corporation" },
+ { 0x43, "Intellitech Corporation" },
+ { 0xC4, "Nordic VLSI ASA" },
+ { 0x45, "Ishoni Networks" },
+ { 0x46, "Silicon Spice" },
+ { 0xC7, "Alchemy Semiconductor" },
+ { 0xC8, "Agilent Technologies" },
+ { 0x49, "Centillium Communications" },
+ { 0x4A, "W.L. Gore" },
+ { 0xCB, "HanBit Electronics" },
+ { 0x4C, "GlobeSpan" },
+ { 0xCD, "Element 14" },
+ { 0xCE, "Pycon" },
+ { 0x4F, "Saifun Semiconductors" },
+ { 0xD0, "Sibyte, Incorporated" },
+ { 0x51, "MetaLink Technologies" },
+ { 0x52, "Feiya Technology" },
+ { 0xD3, "I & C Technology" },
+ { 0x54, "Shikatronics" },
+ { 0xD5, "Elektrobit" },
+ { 0xD6, "Megic" },
+ { 0x57, "Com-Tier" },
+ { 0x58, "Malaysia Micro Solutions" },
+ { 0xD9, "Hyperchip" },
+ { 0xDA, "Gemstone Communications" },
+ { 0x5B, "Anadyne Microelectronics" },
+ { 0xDC, "3ParData" },
+ { 0x5D, "Mellanox Technologies" },
+ { 0x5E, "Tenx Technologies" },
+ { 0xDF, "Helix AG" },
+ { 0xE0, "Domosys" },
+ { 0x61, "Skyup Technology" },
+ { 0x62, "HiNT Corporation" },
+ { 0xE3, "Chiaro" },
+ { 0x64, "MCI Computer GMBH" },
+ { 0xE5, "Exbit Technology A/S" },
+ { 0xE6, "Integrated Technology Express" },
+ { 0x67, "AVED Memory" },
+ { 0x68, "Legerity" },
+ { 0xE9, "Jasmine Networks" },
+ { 0xEA, "Caspian Networks" },
+ { 0x6B, "nCUBE" },
+ { 0xEC, "Silicon Access Networks" },
+ { 0x6D, "FDK Corporation" },
+ { 0x6E, "High Bandwidth Access" },
+ { 0xEF, "MultiLink Technology" },
+ { 0x70, "BRECIS" },
+ { 0xF1, "World Wide Packets" },
+ { 0xF2, "APW" },
+ { 0x73, "Chicory Systems" },
+ { 0xF4, "Xstream Logic" },
+ { 0x75, "Fast-Chip" },
+ { 0x76, "Zucotto Wireless" },
+ { 0xF7, "Realchip" },
+ { 0xF8, "Galaxy Power" },
+ { 0x79, "eSilicon" },
+ { 0x7A, "Morphics Technology" },
+ { 0xFB, "Accelerant Networks" },
+ { 0x7C, "Silicon Wave" },
+ { 0xFD, "SandCraft" },
+ { 0xFE, "Elpida" },
+ { 0x00, NULL },
+};
+
+const struct valstr jedec_id4_vals[] = {
+ { 0x01, "Solectron" },
+ { 0x02, "Optosys Technologies" },
+ { 0x83, "Buffalo (Formerly Melco)" },
+ { 0x04, "TriMedia Technologies" },
+ { 0x85, "Cyan Technologies" },
+ { 0x86, "Global Locate" },
+ { 0x07, "Optillion" },
+ { 0x08, "Terago Communications" },
+ { 0x89, "Ikanos Communications" },
+ { 0x8A, "Princeton Technology" },
+ { 0x0B, "Nanya Technology" },
+ { 0x8C, "Elite Flash Storage" },
+ { 0x0D, "Mysticom" },
+ { 0x0E, "LightSand Communications" },
+ { 0x8F, "ATI Technologies" },
+ { 0x10, "Agere Systems" },
+ { 0x91, "NeoMagic" },
+ { 0x92, "AuroraNetics" },
+ { 0x13, "Golden Empire" },
+ { 0x94, "Muskin" },
+ { 0x15, "Tioga Technologies" },
+ { 0x16, "Netlist" },
+ { 0x97, "TeraLogic" },
+ { 0x98, "Cicada Semiconductor" },
+ { 0x19, "Centon Electronics" },
+ { 0x1A, "Tyco Electronics" },
+ { 0x9B, "Magis Works" },
+ { 0x1C, "Zettacom" },
+ { 0x9D, "Cogency Semiconductor" },
+ { 0x9E, "Chipcon AS" },
+ { 0x1F, "Aspex Technology" },
+ { 0x20, "F5 Networks" },
+ { 0xA1, "Programmable Silicon Solutions" },
+ { 0xA2, "ChipWrights" },
+ { 0x23, "Acorn Networks" },
+ { 0xA4, "Quicklogic" },
+ { 0x25, "Kingmax Semiconductor" },
+ { 0x26, "BOPS" },
+ { 0xA7, "Flasys" },
+ { 0xA8, "BitBlitz Communications" },
+ { 0x29, "eMemory Technology" },
+ { 0x2A, "Procket Networks" },
+ { 0xAB, "Purple Ray" },
+ { 0x2C, "Trebia Networks" },
+ { 0xAD, "Delta Electronics" },
+ { 0xAE, "Onex Communications" },
+ { 0x2F, "Ample Communications" },
+ { 0xB0, "Memory Experts Intl" },
+ { 0x31, "Astute Networks" },
+ { 0x32, "Azanda Network Devices" },
+ { 0xB3, "Dibcom" },
+ { 0x34, "Tekmos" },
+ { 0xB5, "API NetWorks" },
+ { 0xB6, "Bay Microsystems" },
+ { 0x37, "Firecron Ltd" },
+ { 0x38, "Resonext Communications" },
+ { 0xB9, "Tachys Technologies" },
+ { 0xBA, "Equator Technology" },
+ { 0x3B, "Concept Computer" },
+ { 0xBC, "SILCOM" },
+ { 0x3D, "3Dlabs" },
+ { 0x3E, "ct Magazine" },
+ { 0xBF, "Sanera Systems" },
+ { 0x40, "Silicon Packets" },
+ { 0xC1, "Viasystems Group" },
+ { 0xC2, "Simtek" },
+ { 0x43, "Semicon Devices Singapore" },
+ { 0xC4, "Satron Handelsges" },
+ { 0x45, "Improv Systems" },
+ { 0x46, "INDUSYS GmbH" },
+ { 0xC7, "Corrent" },
+ { 0xC8, "Infrant Technologies" },
+ { 0x49, "Ritek Corp" },
+ { 0x4A, "empowerTel Networks" },
+ { 0xCB, "Hypertec" },
+ { 0x4C, "Cavium Networks" },
+ { 0xCD, "PLX Technology" },
+ { 0xCE, "Massana Design" },
+ { 0x4F, "Intrinsity" },
+ { 0xD0, "Valence Semiconductor" },
+ { 0x51, "Terawave Communications" },
+ { 0x52, "IceFyre Semiconductor" },
+ { 0xD3, "Primarion" },
+ { 0x54, "Picochip Designs Ltd" },
+ { 0xD5, "Silverback Systems" },
+ { 0xD6, "Jade Star Technologies" },
+ { 0x57, "Pijnenburg Securealink" },
+ { 0x58, "MemorySolutioN" },
+ { 0xD9, "Cambridge Silicon Radio" },
+ { 0xDA, "Swissbit" },
+ { 0x5B, "Nazomi Communications" },
+ { 0xDC, "eWave System" },
+ { 0x5D, "Rockwell Collins" },
+ { 0x5E, "PAION" },
+ { 0xDF, "Alphamosaic Ltd" },
+ { 0xE0, "Sandburst" },
+ { 0x61, "SiCon Video" },
+ { 0x62, "NanoAmp Solutions" },
+ { 0xE3, "Ericsson Technology" },
+ { 0x64, "PrairieComm" },
+ { 0xE5, "Mitac International" },
+ { 0xE6, "Layer N Networks" },
+ { 0x67, "Atsana Semiconductor" },
+ { 0x68, "Allegro Networks" },
+ { 0xE9, "Marvell Semiconductors" },
+ { 0xEA, "Netergy Microelectronic" },
+ { 0x6B, "NVIDIA" },
+ { 0xEC, "Internet Machines" },
+ { 0x6D, "Peak Electronics" },
+ { 0xEF, "Accton Technology" },
+ { 0x70, "Teradiant Networks" },
+ { 0xF1, "Europe Technologies" },
+ { 0xF2, "Cortina Systems" },
+ { 0x73, "RAM Components" },
+ { 0xF4, "Raqia Networks" },
+ { 0x75, "ClearSpeed" },
+ { 0x76, "Matsushita Battery" },
+ { 0xF7, "Xelerated" },
+ { 0xF8, "SimpleTech" },
+ { 0x79, "Utron Technology" },
+ { 0x7A, "Astec International" },
+ { 0xFB, "AVM gmbH" },
+ { 0x7C, "Redux Communications" },
+ { 0xFD, "Dot Hill Systems" },
+ { 0xFE, "TeraChip" },
+ { 0x00, NULL },
+};
+
+const struct valstr jedec_id5_vals[] = {
+ { 0x01, "T-RAM Incorporated" },
+ { 0x02, "Innovics Wireless" },
+ { 0x83, "Teknovus" },
+ { 0x04, "KeyEye Communications" },
+ { 0x85, "Runcom Technologies" },
+ { 0x86, "RedSwitch" },
+ { 0x07, "Dotcast" },
+ { 0x08, "Silicon Mountain Memory" },
+ { 0x89, "Signia Technologies" },
+ { 0x8A, "Pixim" },
+ { 0x0B, "Galazar Networks" },
+ { 0x8C, "White Electronic Designs" },
+ { 0x0D, "Patriot Scientific" },
+ { 0x0E, "Neoaxiom Corporation" },
+ { 0x8F, "3Y Power Technology" },
+ { 0x10, "Europe Technologies" },
+ { 0x91, "Potentia Power Systems" },
+ { 0x92, "C-guys Incorporated" },
+ { 0x13, "Digital Communications Technology Incorporated" },
+ { 0x94, "Silicon-Based Technology" },
+ { 0x15, "Fulcrum Microsystems" },
+ { 0x16, "Positivo Informatica Ltd" },
+ { 0x97, "XIOtech Corporation" },
+ { 0x98, "PortalPlayer" },
+ { 0x19, "Zhiying Software" },
+ { 0x1A, "Direct2Data" },
+ { 0x9B, "Phonex Broadband" },
+ { 0x1C, "Skyworks Solutions" },
+ { 0x9D, "Entropic Communications" },
+ { 0x9E, "Pacific Force Technology" },
+ { 0x1F, "Zensys A/S" },
+ { 0x20, "Legend Silicon Corp." },
+ { 0xA1, "sci-worx GmbH" },
+ { 0xA2, "Oasis Silicon Systems" },
+ { 0x23, "Renesas Technology" },
+ { 0xA4, "Raza Microelectronics" },
+ { 0x25, "Phyworks" },
+ { 0x26, "MediaTek" },
+ { 0xA7, "Non-cents Productions" },
+ { 0xA8, "US Modular" },
+ { 0x29, "Wintegra Ltd" },
+ { 0x2A, "Mathstar" },
+ { 0xAB, "StarCore" },
+ { 0x2C, "Oplus Technologies" },
+ { 0xAD, "Mindspeed" },
+ { 0xAE, "Just Young Computer" },
+ { 0x2F, "Radia Communications" },
+ { 0xB0, "OCZ" },
+ { 0x31, "Emuzed" },
+ { 0x32, "LOGIC Devices" },
+ { 0xB3, "Inphi Corporation" },
+ { 0x34, "Quake Technologies" },
+ { 0xB5, "Vixel" },
+ { 0xB6, "SolusTek" },
+ { 0x37, "Kongsberg Maritime" },
+ { 0x38, "Faraday Technology" },
+ { 0xB9, "Altium Ltd." },
+ { 0xBA, "Insyte" },
+ { 0x3B, "ARM Ltd." },
+ { 0xBC, "DigiVision" },
+ { 0x3D, "Vativ Technologies" },
+ { 0x3E, "Endicott Interconnect Technologies" },
+ { 0xBF, "Pericom" },
+ { 0x40, "Bandspeed" },
+ { 0xC1, "LeWiz Communications" },
+ { 0xC2, "CPU Technology" },
+ { 0x43, "Ramaxel Technology" },
+ { 0xC4, "DSP Group" },
+ { 0x45, "Axis Communications" },
+ { 0x46, "Legacy Electronics" },
+ { 0xC7, "Chrontel" },
+ { 0xC8, "Powerchip Semiconductor" },
+ { 0x49, "MobilEye Technologies" },
+ { 0x4A, "Excel Semiconductor" },
+ { 0xCB, "A-DATA Technology" },
+ { 0x4C, "VirtualDigm" },
+ { 0x00, NULL },
+};
+
+int
+ipmi_spd_print(uint8_t *spd_data, int len)
+{
+ int k = 0;
+ int ii = 0;
+
+ if (len < 92)
+ return -1; /* we need first 91 bytes to do our thing */
+
+ printf(" Memory Type : %s\n",
+ val2str(spd_data[2], spd_memtype_vals));
+
+ if (spd_data[2] == 0x0B) /* DDR3 SDRAM */
+ {
+ int iPN;
+ char *pchPN = spd_data+128;
+ int sdram_cap = 0;
+ int pri_bus_width = 0;
+ int sdram_width = 0;
+ int ranks = 0;
+ int mem_size = 0;
+
+ if (len < 148)
+ return -1; /* we need first 91 bytes to do our thing */
+
+
+ sdram_cap = ldexp(256,(spd_data[4]&15));
+ pri_bus_width = ldexp(8,(spd_data[8]&7));
+ sdram_width = ldexp(4,(spd_data[7]&7));
+ ranks = ldexp(1,((spd_data[7]&0x3F)>>3));
+ mem_size = (sdram_cap/8) * (pri_bus_width/sdram_width) * ranks;
+ printf(" SDRAM Capacity : %d MB\n", sdram_cap );
+ printf(" Memory Banks : %s\n", val2str(spd_data[4]>>4, ddr3_banks_vals));
+ printf(" Primary Bus Width : %d bits\n", pri_bus_width );
+ printf(" SDRAM Device Width : %d bits\n", sdram_width );
+ printf(" Number of Ranks : %d\n", ranks );
+ printf(" Memory size : %d MB\n", mem_size );
+
+ /* printf(" Memory Density : %s\n", val2str(spd_data[4]&15, ddr3_density_vals)); */
+ printf(" 1.5 V Nominal Op : %s\n", (((spd_data[6]&1) != 0) ? "No":"Yes" ) );
+ printf(" 1.35 V Nominal Op : %s\n", (((spd_data[6]&2) != 0) ? "No":"Yes" ) );
+ printf(" 1.2X V Nominal Op : %s\n", (((spd_data[6]&4) != 0) ? "No":"Yes" ) );
+ printf(" Error Detect/Cor : %s\n", val2str(spd_data[8]>>3, ddr3_ecc_vals));
+
+ printf(" Manufacturer : ");
+ switch (spd_data[117]&127)
+ {
+ case 0:
+ printf("%s\n", val2str(spd_data[118], jedec_id1_vals));
+ break;
+
+ case 1:
+ printf("%s\n", val2str(spd_data[118], jedec_id2_vals));
+ break;
+
+ case 2:
+ printf("%s\n", val2str(spd_data[118], jedec_id3_vals));
+ break;
+
+ case 3:
+ printf("%s\n", val2str(spd_data[118], jedec_id4_vals));
+ break;
+
+ case 4:
+ printf("%s\n", val2str(spd_data[118], jedec_id5_vals));
+ break;
+
+ default:
+ printf("%s\n", "JEDEC JEP106 update required" );
+
+ }
+
+ printf(" Manufacture Date : year %c%c week %c%c\n",
+ '0'+(spd_data[120]>>4), '0'+(spd_data[120]&15), '0'+(spd_data[121]>>4), '0'+(spd_data[121]&15) );
+
+ printf(" Serial Number : %02x%02x%02x%02x\n",
+ spd_data[122], spd_data[123], spd_data[124], spd_data[125]);
+
+ printf(" Part Number : ");
+ for (iPN=0; iPN < 19; iPN++)
+ {
+ printf( "%c", *pchPN++ );
+ }
+ printf("\n");
+ }
+ else
+ {
+ ii = (spd_data[3] & 0x0f) + (spd_data[4] & 0x0f) - 17;
+ k = ((spd_data[5] & 0x7) + 1) * spd_data[17];
+
+ if(ii > 0 && ii <= 12 && k > 0) {
+ printf(" Memory Size : %d MB\n", ((1 << ii) * k));
+ } else {
+ printf(" Memory Size INVALID: %d, %d, %d, %d\n", spd_data[3],
+ spd_data[4], spd_data[5], spd_data[17]);
+ }
+ printf(" Voltage Intf : %s\n",
+ val2str(spd_data[8], spd_voltage_vals));
+ printf(" Error Detect/Cor : %s\n",
+ val2str(spd_data[11], spd_config_vals));
+
+ /* handle jedec table bank continuation values */
+ printf(" Manufacturer : ");
+ if (spd_data[64] != 0x7f)
+ printf("%s\n",
+ val2str(spd_data[64], jedec_id1_vals));
+ else {
+ if (spd_data[65] != 0x7f)
+ printf("%s\n",
+ val2str(spd_data[65], jedec_id2_vals));
+ else {
+ if (spd_data[66] != 0x7f)
+ printf("%s\n",
+ val2str(spd_data[66], jedec_id3_vals));
+ else {
+ if (spd_data[67] != 0x7f)
+ printf("%s\n",
+ val2str(spd_data[67],
+ jedec_id4_vals));
+ else
+ printf("%s\n",
+ val2str(spd_data[68],
+ jedec_id5_vals));
+ }
+ }
+ }
+
+ if (spd_data[73]) {
+ char part[19];
+ memcpy(part, spd_data+73, 18);
+ part[18] = 0;
+ printf(" Part Number : %s\n", part);
+ }
+
+ printf(" Serial Number : %02x%02x%02x%02x\n",
+ spd_data[95], spd_data[96], spd_data[97], spd_data[98]);
+ }
+
+ if (verbose) {
+ printf("\n");
+ printbuf(spd_data, len, "SPD DATA");
+ }
+
+ return 0;
+}
+
+int
+ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ uint8_t spd_data[256], msg_data[4];
+ int len, offset;
+
+ msg_data[0] = id;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
+ fru.size, fru.access ? "words" : "bytes");
+
+ if (fru.size < 1) {
+ lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ offset = 0;
+ memset(spd_data, 0, 256);
+ do {
+ msg_data[0] = id;
+ msg_data[1] = offset;
+ msg_data[2] = 0;
+ msg_data[3] = FRU_DATA_RQST_SIZE;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+
+ /* Timeouts are acceptable. No DIMM in the socket */
+ if (rsp->ccode == 0xc3)
+ return 1;
+
+ return -1;
+ }
+
+ len = rsp->data[0];
+ memcpy(&spd_data[offset], rsp->data + 1, len);
+ offset += len;
+ } while (offset < fru.size);
+
+ /* now print spd info */
+ ipmi_spd_print(spd_data, offset);
+
+ return 0;
+}
diff --git a/lib/helper.c b/lib/helper.c
new file mode 100644
index 0000000..4b903b0
--- /dev/null
+++ b/lib/helper.c
@@ -0,0 +1,789 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h> /* For TIOCNOTTY */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#else
+# define _PATH_VARRUN "/var/run/"
+#endif
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+
+extern int verbose;
+
+uint32_t buf2long(uint8_t * buf)
+{
+ return (uint32_t)(buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]);
+}
+
+uint16_t buf2short(uint8_t * buf)
+{
+ return (uint16_t)(buf[1] << 8 | buf[0]);
+}
+
+const char * buf2str(uint8_t * buf, int len)
+{
+ static char str[2049];
+ int i;
+
+ if (len <= 0 || len > 1024)
+ return NULL;
+
+ memset(str, 0, 2049);
+
+ for (i=0; i<len; i++)
+ sprintf(str+i+i, "%2.2x", buf[i]);
+
+ str[len*2] = '\0';
+
+ return (const char *)str;
+}
+
+void printbuf(const uint8_t * buf, int len, const char * desc)
+{
+ int i;
+
+ if (len <= 0)
+ return;
+
+ if (verbose < 1)
+ return;
+
+ fprintf(stderr, "%s (%d bytes)\n", desc, len);
+ for (i=0; i<len; i++) {
+ if (((i%16) == 0) && (i != 0))
+ fprintf(stderr, "\n");
+ fprintf(stderr, " %2.2x", buf[i]);
+ }
+ fprintf(stderr, "\n");
+}
+
+const char * val2str(uint16_t val, const struct valstr *vs)
+{
+ static char un_str[32];
+ int i;
+
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (vs[i].val == val)
+ return vs[i].str;
+ }
+
+ memset(un_str, 0, 32);
+ snprintf(un_str, 32, "Unknown (0x%02X)", val);
+
+ return un_str;
+}
+
+const char * oemval2str(uint32_t oem, uint16_t val,
+ const struct oemvalstr *vs)
+{
+ static char un_str[32];
+ int i;
+
+ for (i = 0; vs[i].oem != 0xffffff && vs[i].str != NULL; i++) {
+ /* FIXME: for now on we assume PICMG capability on all IANAs */
+ if ( (vs[i].oem == oem || vs[i].oem == IPMI_OEM_PICMG) &&
+ vs[i].val == val ) {
+ return vs[i].str;
+ }
+ }
+
+ memset(un_str, 0, 32);
+ snprintf(un_str, 32, "Unknown (0x%X)", val);
+
+ return un_str;
+}
+
+/* str2double - safely convert string to double
+ *
+ * @str: source string to convert from
+ * @double_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
+ */
+int str2double(const char * str, double * double_ptr)
+{
+ char * end_ptr = 0;
+ if (!str || !double_ptr)
+ return (-1);
+
+ *double_ptr = 0;
+ errno = 0;
+ *double_ptr = strtod(str, &end_ptr);
+
+ if (*end_ptr != '\0')
+ return (-2);
+
+ if (errno != 0)
+ return (-3);
+
+ return 0;
+} /* str2double(...) */
+
+/* str2long - safely convert string to int64_t
+ *
+ * @str: source string to convert from
+ * @lng_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
+ */
+int str2long(const char * str, int64_t * lng_ptr)
+{
+ char * end_ptr = 0;
+ if (!str || !lng_ptr)
+ return (-1);
+
+ *lng_ptr = 0;
+ errno = 0;
+ *lng_ptr = strtol(str, &end_ptr, 0);
+
+ if (*end_ptr != '\0')
+ return (-2);
+
+ if (errno != 0)
+ return (-3);
+
+ return 0;
+} /* str2long(...) */
+
+/* str2ulong - safely convert string to uint64_t
+ *
+ * @str: source string to convert from
+ * @ulng_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
+ */
+int str2ulong(const char * str, uint64_t * ulng_ptr)
+{
+ char * end_ptr = 0;
+ if (!str || !ulng_ptr)
+ return (-1);
+
+ *ulng_ptr = 0;
+ errno = 0;
+ *ulng_ptr = strtoul(str, &end_ptr, 0);
+
+ if (*end_ptr != '\0')
+ return (-2);
+
+ if (errno != 0)
+ return (-3);
+
+ return 0;
+} /* str2ulong(...) */
+
+/* str2int - safely convert string to int32_t
+ *
+ * @str: source string to convert from
+ * @int_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
+ */
+int str2int(const char * str, int32_t * int_ptr)
+{
+ int rc = 0;
+ int64_t arg_long = 0;
+ if (!str || !int_ptr)
+ return (-1);
+
+ if ( (rc = str2long(str, &arg_long)) != 0 ) {
+ *int_ptr = 0;
+ return rc;
+ }
+
+ if (arg_long < INT32_MIN || arg_long > INT32_MAX)
+ return (-3);
+
+ *int_ptr = (int32_t)arg_long;
+ return 0;
+} /* str2int(...) */
+
+/* str2uint - safely convert string to uint32_t
+ *
+ * @str: source string to convert from
+ * @uint_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
+ */
+int str2uint(const char * str, uint32_t * uint_ptr)
+{
+ int rc = 0;
+ uint64_t arg_ulong = 0;
+ if (!str || !uint_ptr)
+ return (-1);
+
+ if ( (rc = str2ulong(str, &arg_ulong)) != 0) {
+ *uint_ptr = 0;
+ return rc;
+ }
+
+ if (arg_ulong > UINT32_MAX)
+ return (-3);
+
+ *uint_ptr = (uint32_t)arg_ulong;
+ return 0;
+} /* str2uint(...) */
+
+/* str2short - safely convert string to int16_t
+ *
+ * @str: source string to convert from
+ * @shrt_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
+ */
+int str2short(const char * str, int16_t * shrt_ptr)
+{
+ int rc = (-3);
+ int64_t arg_long = 0;
+ if (!str || !shrt_ptr)
+ return (-1);
+
+ if ( (rc = str2long(str, &arg_long)) != 0 ) {
+ *shrt_ptr = 0;
+ return rc;
+ }
+
+ if (arg_long < INT16_MIN || arg_long > INT16_MAX)
+ return (-3);
+
+ *shrt_ptr = (int16_t)arg_long;
+ return 0;
+} /* str2short(...) */
+
+/* str2ushort - safely convert string to uint16_t
+ *
+ * @str: source string to convert from
+ * @ushrt_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) invalid input, (-3) for *flow
+ */
+int str2ushort(const char * str, uint16_t * ushrt_ptr)
+{
+ int rc = (-3);
+ uint64_t arg_ulong = 0;
+ if (!str || !ushrt_ptr)
+ return (-1);
+
+ if ( (rc = str2ulong(str, &arg_ulong)) != 0 ) {
+ *ushrt_ptr = 0;
+ return rc;
+ }
+
+ if (arg_ulong > UINT16_MAX)
+ return (-3);
+
+ *ushrt_ptr = (uint16_t)arg_ulong;
+ return 0;
+} /* str2ushort(...) */
+
+/* str2char - safely convert string to int8
+ *
+ * @str: source string to convert from
+ * @chr_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) or (-3) if conversion fails
+ */
+int str2char(const char *str, int8_t * chr_ptr)
+{
+ int rc = (-3);
+ int64_t arg_long = 0;
+ if (!str || !chr_ptr) {
+ return (-1);
+ }
+ if ((rc = str2long(str, &arg_long)) != 0) {
+ *chr_ptr = 0;
+ return rc;
+ }
+ if (arg_long < INT8_MIN || arg_long > INT8_MAX) {
+ return (-3);
+ }
+ return 0;
+} /* str2char(...) */
+
+/* str2uchar - safely convert string to uint8
+ *
+ * @str: source string to convert from
+ * @uchr_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) if one of args is NULL, (-2) or (-3) if conversion fails
+ */
+int str2uchar(const char * str, uint8_t * uchr_ptr)
+{
+ int rc = (-3);
+ uint64_t arg_ulong = 0;
+ if (!str || !uchr_ptr)
+ return (-1);
+
+ if ( (rc = str2ulong(str, &arg_ulong)) != 0 ) {
+ *uchr_ptr = 0;
+ return rc;
+ }
+
+ if (arg_ulong > UINT8_MAX)
+ return (-3);
+
+ *uchr_ptr = (uint8_t)arg_ulong;
+ return 0;
+} /* str2uchar(...) */
+
+uint16_t str2val(const char *str, const struct valstr *vs)
+{
+ int i;
+
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (strncasecmp(vs[i].str, str, __maxlen(str, vs[i].str)) == 0)
+ return vs[i].val;
+ }
+
+ return vs[i].val;
+}
+
+/* print_valstr - print value string list to log or stdout
+ *
+ * @vs: value string list to print
+ * @title: name of this value string list
+ * @loglevel: what log level to print, -1 for stdout
+ */
+void
+print_valstr(const struct valstr * vs, const char * title, int loglevel)
+{
+ int i;
+
+ if (vs == NULL)
+ return;
+
+ if (title != NULL) {
+ if (loglevel < 0)
+ printf("\n%s:\n\n", title);
+ else
+ lprintf(loglevel, "\n%s:\n", title);
+ }
+
+ if (loglevel < 0) {
+ printf(" VALUE\tHEX\tSTRING\n");
+ printf("==============================================\n");
+ } else {
+ lprintf(loglevel, " VAL\tHEX\tSTRING");
+ lprintf(loglevel, "==============================================");
+ }
+
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (loglevel < 0) {
+ if (vs[i].val < 256)
+ printf(" %d\t0x%02x\t%s\n", vs[i].val, vs[i].val, vs[i].str);
+ else
+ printf(" %d\t0x%04x\t%s\n", vs[i].val, vs[i].val, vs[i].str);
+ } else {
+ if (vs[i].val < 256)
+ lprintf(loglevel, " %d\t0x%02x\t%s", vs[i].val, vs[i].val, vs[i].str);
+ else
+ lprintf(loglevel, " %d\t0x%04x\t%s", vs[i].val, vs[i].val, vs[i].str);
+ }
+ }
+
+ if (loglevel < 0)
+ printf("\n");
+ else
+ lprintf(loglevel, "");
+}
+
+/* print_valstr_2col - print value string list in two columns to log or stdout
+ *
+ * @vs: value string list to print
+ * @title: name of this value string list
+ * @loglevel: what log level to print, -1 for stdout
+ */
+void
+print_valstr_2col(const struct valstr * vs, const char * title, int loglevel)
+{
+ int i;
+
+ if (vs == NULL)
+ return;
+
+ if (title != NULL) {
+ if (loglevel < 0)
+ printf("\n%s:\n\n", title);
+ else
+ lprintf(loglevel, "\n%s:\n", title);
+ }
+
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (vs[i+1].str == NULL) {
+ /* last one */
+ if (loglevel < 0) {
+ printf(" %4d %-32s\n", vs[i].val, vs[i].str);
+ } else {
+ lprintf(loglevel, " %4d %-32s\n", vs[i].val, vs[i].str);
+ }
+ }
+ else {
+ if (loglevel < 0) {
+ printf(" %4d %-32s %4d %-32s\n",
+ vs[i].val, vs[i].str, vs[i+1].val, vs[i+1].str);
+ } else {
+ lprintf(loglevel, " %4d %-32s %4d %-32s\n",
+ vs[i].val, vs[i].str, vs[i+1].val, vs[i+1].str);
+ }
+ i++;
+ }
+ }
+
+ if (loglevel < 0)
+ printf("\n");
+ else
+ lprintf(loglevel, "");
+}
+
+/* ipmi_csum - calculate an ipmi checksum
+ *
+ * @d: buffer to check
+ * @s: position in buffer to start checksum from
+ */
+uint8_t
+ipmi_csum(uint8_t * d, int s)
+{
+ uint8_t c = 0;
+ for (; s > 0; s--, d++)
+ c += *d;
+ return -c;
+}
+
+/* ipmi_open_file - safely open a file for reading or writing
+ *
+ * @file: filename
+ * @rw: read-write flag, 1=write
+ *
+ * returns pointer to file handler on success
+ * returns NULL on error
+ */
+FILE *
+ipmi_open_file(const char * file, int rw)
+{
+ struct stat st1, st2;
+ FILE * fp;
+
+ /* verify existance */
+ if (lstat(file, &st1) < 0) {
+ if (rw) {
+ /* does not exist, ok to create */
+ fp = fopen(file, "w");
+ if (fp == NULL) {
+ lperror(LOG_ERR, "Unable to open file %s "
+ "for write", file);
+ return NULL;
+ }
+ /* created ok, now return the descriptor */
+ return fp;
+ } else {
+ lprintf(LOG_ERR, "File %s does not exist", file);
+ return NULL;
+ }
+ }
+
+#ifndef ENABLE_FILE_SECURITY
+ if (!rw) {
+ /* on read skip the extra checks */
+ fp = fopen(file, "r");
+ if (fp == NULL) {
+ lperror(LOG_ERR, "Unable to open file %s", file);
+ return NULL;
+ }
+ return fp;
+ }
+#endif
+
+ /* it exists - only regular files, not links */
+ if (S_ISREG(st1.st_mode) == 0) {
+ lprintf(LOG_ERR, "File %s has invalid mode: %d",
+ file, st1.st_mode);
+ return NULL;
+ }
+
+ /* allow only files with 1 link (itself) */
+ if (st1.st_nlink != 1) {
+ lprintf(LOG_ERR, "File %s has invalid link count: %d != 1",
+ file, (int)st1.st_nlink);
+ return NULL;
+ }
+
+ fp = fopen(file, rw ? "w+" : "r");
+ if (fp == NULL) {
+ lperror(LOG_ERR, "Unable to open file %s", file);
+ return NULL;
+ }
+
+ /* stat again */
+ if (fstat(fileno(fp), &st2) < 0) {
+ lperror(LOG_ERR, "Unable to stat file %s", file);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* verify inode */
+ if (st1.st_ino != st2.st_ino) {
+ lprintf(LOG_ERR, "File %s has invalid inode: %d != %d",
+ file, st1.st_ino, st2.st_ino);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* verify owner */
+ if (st1.st_uid != st2.st_uid) {
+ lprintf(LOG_ERR, "File %s has invalid user id: %d != %d",
+ file, st1.st_uid, st2.st_uid);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* verify inode */
+ if (st2.st_nlink != 1) {
+ lprintf(LOG_ERR, "File %s has invalid link count: %d != 1",
+ file, st2.st_nlink);
+ fclose(fp);
+ return NULL;
+ }
+
+ return fp;
+}
+
+void
+ipmi_start_daemon(struct ipmi_intf *intf)
+{
+ pid_t pid;
+ int fd;
+#ifdef SIGHUP
+ sigset_t sighup;
+#endif
+
+#ifdef SIGHUP
+ sigemptyset(&sighup);
+ sigaddset(&sighup, SIGHUP);
+ if (sigprocmask(SIG_UNBLOCK, &sighup, NULL) < 0)
+ fprintf(stderr, "ERROR: could not unblock SIGHUP signal\n");
+ signal(SIGHUP, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+ signal(SIGTTOU, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+ signal(SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGQUIT
+ signal(SIGQUIT, SIG_IGN);
+#endif
+#ifdef SIGTSTP
+ signal(SIGTSTP, SIG_IGN);
+#endif
+
+ pid = (pid_t) fork();
+ if (pid < 0 || pid > 0)
+ exit(0);
+
+#if defined(SIGTSTP) && defined(TIOCNOTTY)
+ if (setpgid(0, getpid()) == -1)
+ exit(1);
+ if ((fd = open(_PATH_TTY, O_RDWR)) >= 0) {
+ ioctl(fd, TIOCNOTTY, NULL);
+ close(fd);
+ }
+#else
+ if (setpgid(0, 0) == -1)
+ exit(1);
+ pid = (pid_t) fork();
+ if (pid < 0 || pid > 0)
+ exit(0);
+#endif
+
+ chdir("/");
+ umask(0);
+
+ for (fd=0; fd<64; fd++) {
+ if (fd != intf->fd)
+ close(fd);
+ }
+
+ fd = open("/dev/null", O_RDWR);
+ assert(0 == fd);
+ dup(fd);
+ dup(fd);
+}
+
+/* is_fru_id - wrapper for str-2-int FRU ID conversion. Message is printed
+ * on error.
+ * FRU ID range: <0..255>
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @fru_id_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) on error and message is printed on STDERR
+ */
+int
+is_fru_id(const char *argv_ptr, uint8_t *fru_id_ptr)
+{
+ if (!argv_ptr || !fru_id_ptr) {
+ lprintf(LOG_ERR, "is_fru_id(): invalid argument(s).");
+ return (-1);
+ }
+
+ if (str2uchar(argv_ptr, fru_id_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "FRU ID '%s' is either invalid or out of range.",
+ argv_ptr);
+ return (-1);
+} /* is_fru_id(...) */
+
+/* is_ipmi_channel_num - wrapper for str-2-int Channel conversion. Message is
+ * printed on error.
+ *
+ * 6.3 Channel Numbers, p. 45, IPMIv2 spec.
+ * Valid channel numbers are: <0..7>, <E-F>
+ * Reserved channel numbers: <8-D>
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @channel_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) on error and message is printed on STDERR
+ */
+int
+is_ipmi_channel_num(const char *argv_ptr, uint8_t *channel_ptr)
+{
+ if (!argv_ptr || !channel_ptr) {
+ lprintf(LOG_ERR,
+ "is_ipmi_channel_num(): invalid argument(s).");
+ return (-1);
+ }
+ if ((str2uchar(argv_ptr, channel_ptr) == 0)
+ && ((*channel_ptr >= 0x0 && *channel_ptr <= 0x7)
+ || (*channel_ptr >= 0xE && *channel_ptr <= 0xF))) {
+ return 0;
+ }
+ lprintf(LOG_ERR,
+ "Given Channel number '%s' is either invalid or out of range.",
+ argv_ptr);
+ lprintf(LOG_ERR, "Channel number must be from ranges: <0..7>, <0xE..0xF>");
+ return (-1);
+}
+
+/* is_ipmi_user_id() - wrapper for str-2-uint IPMI UID conversion. Message is
+ * printed on error.
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @ipmi_uid_ptr: pointer where to store result
+ *
+ * returns zero on success
+ * returns (-1) on error and message is printed on STDERR
+ */
+int
+is_ipmi_user_id(const char *argv_ptr, uint8_t *ipmi_uid_ptr)
+{
+ if (!argv_ptr || !ipmi_uid_ptr) {
+ lprintf(LOG_ERR,
+ "is_ipmi_user_id(): invalid argument(s).");
+ return (-1);
+ }
+ if ((str2uchar(argv_ptr, ipmi_uid_ptr) == 0)
+ && *ipmi_uid_ptr >= IPMI_UID_MIN
+ && *ipmi_uid_ptr <= IPMI_UID_MAX) {
+ return 0;
+ }
+ lprintf(LOG_ERR,
+ "Given User ID '%s' is either invalid or out of range.",
+ argv_ptr);
+ lprintf(LOG_ERR, "User ID is limited to range <%i..%i>.",
+ IPMI_UID_MIN, IPMI_UID_MAX);
+ return (-1);
+}
+
+uint16_t
+ipmi_get_oem_id(struct ipmi_intf *intf)
+{
+ /* Execute a Get Board ID command to determine the board */
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ uint16_t oem_id;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TSOL;
+ req.msg.cmd = 0x21;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Board ID command failed");
+ return 0;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Board ID command failed: %#x %s",
+ rsp->ccode, val2str(rsp->ccode, completion_code_vals));
+ return 0;
+ }
+ oem_id = rsp->data[0] | (rsp->data[1] << 8);
+ lprintf(LOG_DEBUG,"Board ID: %x", oem_id);
+
+ return oem_id;
+}
diff --git a/lib/hpm2.c b/lib/hpm2.c
new file mode 100644
index 0000000..e7d6c03
--- /dev/null
+++ b/lib/hpm2.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2012 Pigeon Point Systems. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Pigeon Point Systems nor the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <ipmitool/hpm2.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/log.h>
+#include <ipmitool/bswap.h>
+
+#if HAVE_PRAGMA_PACK
+# pragma pack(push, 1)
+#endif
+
+/* HPM.x Get Capabilities request */
+struct hpmx_cmd_get_capabilities_rq {
+ uint8_t picmg_id;
+ uint8_t hpmx_id;
+} ATTRIBUTE_PACKING;
+
+/* HPM.2 Get Capabilities response */
+struct hpm2_cmd_get_capabilities_rp {
+ uint8_t picmg_id;
+ struct hpm2_lan_attach_capabilities caps;
+} ATTRIBUTE_PACKING;
+
+#if HAVE_PRAGMA_PACK
+# pragma pack(pop)
+#endif
+
+/* IPMI Get LAN Configuration Parameters command */
+#define IPMI_LAN_GET_CONFIG 0x02
+
+int hpm2_get_capabilities(struct ipmi_intf * intf,
+ struct hpm2_lan_attach_capabilities * caps)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ struct hpmx_cmd_get_capabilities_rq rq;
+
+ /* reset result */
+ memset(caps, 0, sizeof(struct hpm2_lan_attach_capabilities));
+
+ /* prepare request */
+ rq.picmg_id = 0;
+ rq.hpmx_id = 2;
+
+ /* prepare request */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPM2_GET_LAN_ATTACH_CAPABILITIES;
+ req.msg.data = (uint8_t *)&rq;
+ req.msg.data_len = sizeof(rq);
+
+
+ /* send */
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_NOTICE, "Error sending request.");
+ return -1;
+ }
+
+ if (rsp->ccode == 0xC1) {
+ lprintf(LOG_DEBUG, "IPM Controller is not HPM.2 compatible");
+ return rsp->ccode;
+ } else if (rsp->ccode) {
+ lprintf(LOG_NOTICE, "Get HPM.x Capabilities request failed,"
+ " compcode = %x", rsp->ccode);
+ return rsp->ccode;
+ }
+
+ /* check response length */
+ if (rsp->data_len < 2 || rsp->data_len > 10) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check HPM.x identifier */
+ if (rsp->data[1] != 2) {
+ lprintf(LOG_NOTICE, "Bad HPM.x ID, id=%d", rsp->data[1]);
+ return rsp->ccode;
+ }
+
+ /*
+ * this hardly can happen, since completion code is already checked.
+ * but check for safety
+ */
+ if (rsp->data_len < 4) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* copy HPM.2 capabilities */
+ memcpy(caps, rsp->data + 2, rsp->data_len - 2);
+
+#if WORDS_BIGENDIAN
+ /* swap bytes to convert from little-endian format */
+ caps->lan_channel_mask = BSWAP_16(caps->lan_channel_mask);
+#endif
+
+ /* check HPM.2 revision */
+ if (caps->hpm2_revision_id != HPM2_REVISION) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 revision, rev=%d",
+ caps->hpm2_revision_id);
+ return -1;
+ }
+
+ if (!caps->lan_channel_mask) {
+ return -1;
+ }
+
+ /* check response length */
+ if (rsp->data_len < 8) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check HPM.2 LAN parameters start */
+ if (caps->hpm2_lan_params_start < 0xC0) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 LAN params start, start=%x",
+ caps->hpm2_lan_params_start);
+ return -1;
+ }
+
+ /* check HPM.2 LAN parameters revision */
+ if (caps->hpm2_lan_params_rev != HPM2_LAN_PARAMS_REV) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 LAN params revision, rev=%d",
+ caps->hpm2_lan_params_rev);
+ return -1;
+ }
+
+ /* check for HPM.2 SOL extension */
+ if (!(caps->hpm2_caps & HPM2_CAPS_SOL_EXTENSION)) {
+ /* no further checks */
+ return 0;
+ }
+
+ /* check response length */
+ if (rsp->data_len < 10) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check HPM.2 SOL parameters start */
+ if (caps->hpm2_sol_params_start < 0xC0) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 SOL params start, start=%x",
+ caps->hpm2_sol_params_start);
+ return -1;
+ }
+
+ /* check HPM.2 SOL parameters revision */
+ if (caps->hpm2_sol_params_rev != HPM2_SOL_PARAMS_REV) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 SOL params revision, rev=%d",
+ caps->hpm2_sol_params_rev);
+ return -1;
+ }
+
+ return 0;
+}
+
+int hpm2_get_lan_channel_capabilities(struct ipmi_intf * intf,
+ uint8_t hpm2_lan_params_start,
+ struct hpm2_lan_channel_capabilities * caps)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ uint8_t rq[4];
+
+ /* reset result */
+ memset(caps, 0, sizeof(struct hpm2_lan_channel_capabilities));
+
+ /* prepare request */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_LAN_GET_CONFIG;
+ req.msg.data = (uint8_t *)&rq;
+ req.msg.data_len = sizeof(rq);
+
+ /* prepare request data */
+ rq[0] = 0xE; /* sending channel */
+ rq[1] = hpm2_lan_params_start; /* HPM.2 Channel Caps */
+ rq[2] = rq[3] = 0;
+
+ /* send */
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp) {
+ lprintf(LOG_NOTICE, "Error sending request");
+ return -1;
+ }
+
+ if (rsp->ccode == 0x80) {
+ lprintf(LOG_DEBUG, "HPM.2 Channel Caps parameter is not supported");
+ return rsp->ccode;
+ } else if (rsp->ccode) {
+ lprintf(LOG_NOTICE, "Get LAN Configuration Parameters request failed,"
+ " compcode = %x", rsp->ccode);
+ return rsp->ccode;
+ }
+
+ /* check response length */
+ if (rsp->data_len != sizeof (struct hpm2_lan_channel_capabilities) + 1) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check parameter revision */
+ if (rsp->data[0] != HPM2_LAN_PARAMS_REV) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 LAN parameter revision, rev=%d",
+ rsp->data[0]);
+ return -1;
+ }
+
+ /* copy parameter data */
+ memcpy(caps, &rsp->data[1], sizeof (struct hpm2_lan_channel_capabilities));
+
+#if WORDS_BIGENDIAN
+ /* swap bytes to convert from little-endian format */
+ caps->max_inbound_pld_size = BSWAP_16(caps->max_inbound_pld_size);
+ caps->max_outbound_pld_size = BSWAP_16(caps->max_outbound_pld_size);
+#endif
+
+ return 0;
+}
+
+int hpm2_detect_max_payload_size(struct ipmi_intf * intf)
+{
+ struct hpm2_lan_attach_capabilities attach_caps;
+ struct hpm2_lan_channel_capabilities channel_caps;
+ int err;
+
+ /* query HPM.2 support */
+ err = hpm2_get_capabilities(intf, &attach_caps);
+
+ /* check if HPM.2 is supported */
+ if (err != 0 || !attach_caps.lan_channel_mask) {
+ return err;
+ }
+
+ /* query channel capabilities */
+ err = hpm2_get_lan_channel_capabilities(intf,
+ attach_caps.hpm2_lan_params_start, &channel_caps);
+
+ /* check if succeeded */
+ if (err != 0) {
+ return err;
+ }
+
+ /* update request and response sizes */
+ ipmi_intf_set_max_request_data_size(intf,
+ channel_caps.max_inbound_pld_size - 7);
+ ipmi_intf_set_max_response_data_size(intf,
+ channel_caps.max_outbound_pld_size - 8);
+
+ /* print debug info */
+ lprintf(LOG_DEBUG, "Set maximum request size to %d\n"
+ "Set maximum response size to %d",
+ intf->max_request_data_size, intf->max_response_data_size);
+
+ return 0;
+}
diff --git a/lib/ipmi_channel.c b/lib/ipmi_channel.c
new file mode 100644
index 0000000..43db338
--- /dev/null
+++ b/lib/ipmi_channel.c
@@ -0,0 +1,903 @@
+/* -*-mode: C; indent-tabs-mode: t; -*-
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_lanp.h>
+#include <ipmitool/ipmi_channel.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_constants.h>
+
+extern int csv_output;
+extern int verbose;
+
+void printf_channel_usage (void);
+
+/**
+ * ipmi_1_5_authtypes
+ *
+ * Create a string describing the supported authentication types as
+ * specificed by the parameter n
+ */
+static const char *
+ipmi_1_5_authtypes(uint8_t n)
+{
+ uint32_t i;
+ static char supportedTypes[128];
+
+ bzero(supportedTypes, 128);
+
+ for (i = 0; ipmi_authtype_vals[i].val != 0; i++) {
+ if (n & ipmi_authtype_vals[i].val) {
+ strcat(supportedTypes, ipmi_authtype_vals[i].str);
+ strcat(supportedTypes, " ");
+ }
+ }
+
+ return supportedTypes;
+}
+
+
+
+/**
+ * ipmi_get_channel_auth_cap
+ *
+ * return 0 on success
+ * -1 on failure
+ */
+int
+ipmi_get_channel_auth_cap(struct ipmi_intf * intf,
+ uint8_t channel,
+ uint8_t priv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct get_channel_auth_cap_rsp auth_cap;
+ uint8_t msg_data[2];
+
+ msg_data[0] = channel | 0x80; // Ask for IPMI v2 data as well
+ msg_data[1] = priv;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; // 0x06
+ req.msg.cmd = IPMI_GET_CHANNEL_AUTH_CAP; // 0x38
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if ((rsp == NULL) || (rsp->ccode > 0)) {
+ /*
+ * It's very possible that this failed because we asked for IPMI v2 data
+ * Ask again, without requesting IPMI v2 data
+ */
+ msg_data[0] &= 0x7F;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Authentication Capabilities");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Channel Authentication Capabilities failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ }
+
+ memcpy(&auth_cap, rsp->data, sizeof(struct get_channel_auth_cap_rsp));
+
+ printf("Channel number : %d\n",
+ auth_cap.channel_number);
+ printf("IPMI v1.5 auth types : %s\n",
+ ipmi_1_5_authtypes(auth_cap.enabled_auth_types));
+
+ if (auth_cap.v20_data_available)
+ printf("KG status : %s\n",
+ (auth_cap.kg_status) ? "non-zero" : "default (all zeroes)");
+
+ printf("Per message authentication : %sabled\n",
+ (auth_cap.per_message_auth) ? "dis" : "en");
+ printf("User level authentication : %sabled\n",
+ (auth_cap.user_level_auth) ? "dis" : "en");
+
+ printf("Non-null user names exist : %s\n",
+ (auth_cap.non_null_usernames) ? "yes" : "no");
+ printf("Null user names exist : %s\n",
+ (auth_cap.null_usernames) ? "yes" : "no");
+ printf("Anonymous login enabled : %s\n",
+ (auth_cap.anon_login_enabled) ? "yes" : "no");
+
+ if (auth_cap.v20_data_available) {
+ printf("Channel supports IPMI v1.5 : %s\n",
+ (auth_cap.ipmiv15_support) ? "yes" : "no");
+ printf("Channel supports IPMI v2.0 : %s\n",
+ (auth_cap.ipmiv20_support) ? "yes" : "no");
+ }
+
+ /*
+ * If there is support for an OEM authentication type, there is some
+ * information.
+ */
+ if (auth_cap.enabled_auth_types & IPMI_1_5_AUTH_TYPE_BIT_OEM) {
+ printf("IANA Number for OEM : %d\n",
+ auth_cap.oem_id[0] |
+ auth_cap.oem_id[1] << 8 |
+ auth_cap.oem_id[2] << 16);
+ printf("OEM Auxiliary Data : 0x%x\n",
+ auth_cap.oem_aux_data);
+ }
+
+ return 0;
+}
+
+
+
+/**
+ * ipmi_get_channel_info
+ *
+ * returns 0 on success
+ * -1 on failure
+ *
+ */
+int
+ipmi_get_channel_info(struct ipmi_intf * intf, uint8_t channel)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[2];
+ uint8_t medium;
+ struct get_channel_info_rsp channel_info;
+ struct get_channel_access_rsp channel_access;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; // 0x06
+ req.msg.cmd = IPMI_GET_CHANNEL_INFO; // 0x42
+ req.msg.data = &channel;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Info");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Channel Info failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(&channel_info, rsp->data, sizeof(struct get_channel_info_rsp));
+
+ printf("Channel 0x%x info:\n", channel_info.channel_number);
+
+ printf(" Channel Medium Type : %s\n",
+ val2str(channel_info.channel_medium, ipmi_channel_medium_vals));
+
+ printf(" Channel Protocol Type : %s\n",
+ val2str(channel_info.channel_protocol, ipmi_channel_protocol_vals));
+
+ printf(" Session Support : ");
+ switch (channel_info.session_support) {
+ case 0x0:
+ printf("session-less\n");
+ break;
+ case 0x1:
+ printf("single-session\n");
+ break;
+ case 0x2:
+ printf("multi-session\n");
+ break;
+ case 0x3:
+ default:
+ printf("session-based\n");
+ break;
+ }
+
+ printf(" Active Session Count : %d\n",
+ channel_info.active_sessions);
+
+ printf(" Protocol Vendor ID : %d\n",
+ channel_info.vendor_id[0] |
+ channel_info.vendor_id[1] << 8 |
+ channel_info.vendor_id[2] << 16);
+
+
+ /* only proceed if this is LAN channel */
+ medium = ipmi_get_channel_medium(intf, channel);
+ if (medium != IPMI_CHANNEL_MEDIUM_LAN &&
+ medium != IPMI_CHANNEL_MEDIUM_LAN_OTHER) {
+ return 0;
+ }
+
+ memset(&req, 0, sizeof(req));
+ rqdata[0] = channel & 0xf;
+
+ /* get volatile settings */
+
+ rqdata[1] = 0x80; /* 0x80=active */
+ req.msg.netfn = IPMI_NETFN_APP; // 0x06
+ req.msg.cmd = IPMI_GET_CHANNEL_ACCESS; // 0x41
+ req.msg.data = rqdata;
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Access (volatile)");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Channel Access (volatile) failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(&channel_access, rsp->data, sizeof(struct get_channel_access_rsp));
+
+
+ printf(" Volatile(active) Settings\n");
+ printf(" Alerting : %sabled\n",
+ (channel_access.alerting) ? "dis" : "en");
+ printf(" Per-message Auth : %sabled\n",
+ (channel_access.per_message_auth) ? "dis" : "en");
+ printf(" User Level Auth : %sabled\n",
+ (channel_access.user_level_auth) ? "dis" : "en");
+
+ printf(" Access Mode : ");
+ switch (channel_access.access_mode) {
+ case 0:
+ printf("disabled\n");
+ break;
+ case 1:
+ printf("pre-boot only\n");
+ break;
+ case 2:
+ printf("always available\n");
+ break;
+ case 3:
+ printf("shared\n");
+ break;
+ default:
+ printf("unknown\n");
+ break;
+ }
+
+ /* get non-volatile settings */
+
+ rqdata[1] = 0x40; /* 0x40=non-volatile */
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Access (non-volatile)");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Channel Access (non-volatile) failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(&channel_access, rsp->data, sizeof(struct get_channel_access_rsp));
+
+ printf(" Non-Volatile Settings\n");
+ printf(" Alerting : %sabled\n",
+ (channel_access.alerting) ? "dis" : "en");
+ printf(" Per-message Auth : %sabled\n",
+ (channel_access.per_message_auth) ? "dis" : "en");
+ printf(" User Level Auth : %sabled\n",
+ (channel_access.user_level_auth) ? "dis" : "en");
+
+ printf(" Access Mode : ");
+ switch (channel_access.access_mode) {
+ case 0:
+ printf("disabled\n");
+ break;
+ case 1:
+ printf("pre-boot only\n");
+ break;
+ case 2:
+ printf("always available\n");
+ break;
+ case 3:
+ printf("shared\n");
+ break;
+ default:
+ printf("unknown\n");
+ break;
+ }
+
+ return 0;
+}
+
+static int
+ipmi_get_user_access(struct ipmi_intf * intf, uint8_t channel, uint8_t userid)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req1, req2;
+ uint8_t rqdata[2];
+ struct get_user_access_rsp user_access;
+ int curr_uid, max_uid = 0, init = 1;
+
+ curr_uid = userid ? : 1;
+
+ memset(&req1, 0, sizeof(req1));
+ req1.msg.netfn = IPMI_NETFN_APP;
+ req1.msg.cmd = IPMI_GET_USER_ACCESS;
+ req1.msg.data = rqdata;
+ req1.msg.data_len = 2;
+
+ memset(&req2, 0, sizeof(req2));
+ req2.msg.netfn = IPMI_NETFN_APP;
+ req2.msg.cmd = IPMI_GET_USER_NAME;
+ req2.msg.data = rqdata;
+ req2.msg.data_len = 1;
+
+ do
+ {
+ rqdata[0] = channel & 0xf;
+ rqdata[1] = curr_uid & 0x3f;
+
+ rsp = intf->sendrecv(intf, &req1);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get User Access (channel %d id %d)",
+ rqdata[0], rqdata[1]);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get User Access (channel %d id %d) failed: %s",
+ rqdata[0], rqdata[1],
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(&user_access, rsp->data, sizeof(struct get_user_access_rsp));
+
+ rqdata[0] = curr_uid & 0x3f;
+
+ rsp = intf->sendrecv(intf, &req2);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get User Name (id %d)", rqdata[0]);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get User Name (id %d) failed: %s",
+ rqdata[0], val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ if (init) {
+ printf("Maximum User IDs : %d\n", user_access.max_user_ids);
+ printf("Enabled User IDs : %d\n", user_access.enabled_user_ids);
+ max_uid = user_access.max_user_ids;
+ init = 0;
+ }
+
+ printf("\n");
+ printf("User ID : %d\n", curr_uid);
+ printf("User Name : %s\n", rsp->data);
+ printf("Fixed Name : %s\n",
+ (curr_uid <= user_access.fixed_user_ids) ? "Yes" : "No");
+ printf("Access Available : %s\n",
+ (user_access.callin_callback) ? "callback" : "call-in / callback");
+ printf("Link Authentication : %sabled\n",
+ (user_access.link_auth) ? "en" : "dis");
+ printf("IPMI Messaging : %sabled\n",
+ (user_access.ipmi_messaging) ? "en" : "dis");
+ printf("Privilege Level : %s\n",
+ val2str(user_access.privilege_limit, ipmi_privlvl_vals));
+
+ curr_uid ++;
+
+ } while (!userid && curr_uid <= max_uid);
+
+ return 0;
+}
+
+static int
+ipmi_set_user_access(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ uint8_t channel, privilege_limit, userid;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[2];
+ struct get_user_access_rsp user_access;
+ struct set_user_access_data set_access;
+ int i;
+
+ if ((argc < 3) || (strncmp(argv[0], "help", 4) == 0)) {
+ printf_channel_usage();
+ return 0;
+ }
+
+ if (str2uchar(argv[0], &channel) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[0]);
+ return (-1);
+ }
+ if (str2uchar(argv[1], &userid) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[1]);
+ return (-1);
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_GET_USER_ACCESS;
+ req.msg.data = rqdata;
+ req.msg.data_len = 2;
+
+ rqdata[0] = channel & 0xf;
+ rqdata[1] = userid & 0x3f;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get User Access (channel %d id %d)",
+ rqdata[0], rqdata[1]);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get User Access (channel %d id %d) failed: %s",
+ rqdata[0], rqdata[1],
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(&user_access, rsp->data, sizeof(struct get_user_access_rsp));
+
+ memset(&set_access, 0, sizeof(set_access));
+ set_access.change_bits = 1;
+ set_access.callin_callback = user_access.callin_callback;
+ set_access.link_auth = user_access.link_auth;
+ set_access.ipmi_messaging = user_access.ipmi_messaging;
+ set_access.channel = channel;
+ set_access.user_id = userid;
+ set_access.privilege_limit = user_access.privilege_limit;
+ set_access.session_limit = 0;
+
+ for (i = 2; i < argc; i ++)
+ {
+ if (strncmp(argv[i], "callin=", 7) == 0) {
+ set_access.callin_callback = !(strncmp (argv[i]+7, "off", 3));
+ }
+ else if (strncmp(argv[i], "link=", 5) == 0) {
+ set_access.link_auth = strncmp (argv[i]+5, "off", 3);
+ }
+ else if (strncmp(argv[i], "ipmi=", 5) == 0) {
+ set_access.ipmi_messaging = strncmp (argv[i]+5, "off", 3);
+ }
+ else if (strncmp(argv[i], "privilege=", 10) == 0) {
+ if (str2uchar(argv[i]+10, &privilege_limit) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[i]+10);
+ return (-1);
+ }
+ set_access.privilege_limit = privilege_limit;
+ }
+ else {
+ printf ("Invalid option: %s\n", argv [i]);
+ return -1;
+ }
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_SET_USER_ACCESS;
+ req.msg.data = (uint8_t *) &set_access;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Set User Access (channel %d id %d)",
+ set_access.channel, set_access.user_id);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set User Access (channel %d id %d) failed: %s",
+ set_access.channel, set_access.user_id,
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static const char *
+iana_string(uint32_t iana)
+{
+ static char s[10];
+
+ if (iana)
+ {
+ sprintf(s, "%06x", iana);
+ return s;
+ }
+ else
+ return "N/A";
+}
+
+
+static int
+ipmi_get_channel_cipher_suites(struct ipmi_intf * intf,
+ const char * payload_type,
+ uint8_t channel)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ uint8_t oem_record;
+ uint8_t rqdata[3];
+ uint32_t iana;
+ uint8_t auth_alg, integrity_alg, crypt_alg;
+ uint8_t cipher_suite_id;
+ uint8_t list_index = 0;
+ uint8_t cipher_suite_data[1024]; // 0x40 sets * 16 bytes per set
+ uint16_t offset = 0;
+ uint16_t cipher_suite_data_length = 0; // how much was returned, total
+
+ memset(cipher_suite_data, 0, sizeof(cipher_suite_data));
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; // 0x06
+ req.msg.cmd = IPMI_GET_CHANNEL_CIPHER_SUITES; // 0x54
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ rqdata[0] = channel;
+ rqdata[1] = ((strncmp(payload_type, "ipmi", 4) == 0)? 0: 1);
+ rqdata[2] = 0x80; // Always ask for cipher suite format
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Cipher Suites");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Channel Cipher Suites failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+
+ // Grab the returned channel number once. We assume it's the same
+ // in future calls.
+ if (rsp->data_len >= 1)
+ channel = rsp->data[0];
+
+ while ((rsp->data_len > 1) && (rsp->data_len == 17) && (list_index < 0x3F))
+ {
+ //
+ // We got back cipher suite data -- store it.
+ //printf("copying data to offset %d\n", offset);
+ //printbuf(rsp->data + 1, rsp->data_len - 1, "this is the data");
+ memcpy(cipher_suite_data + offset, rsp->data + 1, rsp->data_len - 1);
+ offset += rsp->data_len - 1;
+
+ //
+ // Increment our list for the next call
+ //
+ ++list_index;
+ rqdata[2] = (rqdata[2] & 0x80) + list_index;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Cipher Suites");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Channel Cipher Suites failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ }
+
+ /* Copy last chunk */
+ if(rsp->data_len > 1)
+ {
+ //
+ // We got back cipher suite data -- store it.
+ //printf("copying data to offset %d\n", offset);
+ //printbuf(rsp->data + 1, rsp->data_len - 1, "this is the data");
+ memcpy(cipher_suite_data + offset, rsp->data + 1, rsp->data_len - 1);
+ offset += rsp->data_len - 1;
+ }
+
+ //
+ // We can chomp on all our data now.
+ //
+ cipher_suite_data_length = offset;
+ offset = 0;
+
+ if (! csv_output)
+ printf("ID IANA Auth Alg Integrity Alg Confidentiality Alg\n");
+
+ while (offset < cipher_suite_data_length)
+ {
+ if (cipher_suite_data[offset++] == 0xC0)
+ {
+ oem_record = 0; // standard type
+ iana = 0;
+
+ // Verify that we have at least a full record left
+ if ((cipher_suite_data_length - offset) < 4) // id + 3 algs
+ {
+ lprintf(LOG_ERR, "Incomplete data record in cipher suite data");
+ return -1;
+ }
+
+ cipher_suite_id = cipher_suite_data[offset++];
+
+ }
+ else if (cipher_suite_data[offset++] == 0xC1)
+ {
+ oem_record = 1; // OEM record type
+
+ // Verify that we have at least a full record left
+ if ((cipher_suite_data_length - offset) < 4) // id + iana + 3 algs
+ {
+ lprintf(LOG_ERR, "Incomplete data record in cipher suite data");
+ return -1;
+ }
+
+ cipher_suite_id = cipher_suite_data[offset++];
+
+ //
+ // Grab the IANA
+ //
+ iana =
+ cipher_suite_data[offset] |
+ (cipher_suite_data[offset + 1] << 8) |
+ (cipher_suite_data[offset + 2] << 16);
+ offset += 3;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Bad start of record byte in cipher suite data");
+ return -1;
+ }
+
+ //
+ // Grab the algorithms for this cipher suite. I guess we can't be
+ // sure of what order they'll come in. Also, I suppose we default
+ // to the NONE algorithm if one were absent. This part of the spec is
+ // poorly written -- I have read the errata document. For now, I'm only
+ // allowing one algorithm per type (auth, integrity, crypt) because I
+ // don't I understand how it could be otherwise.
+ //
+ auth_alg = IPMI_AUTH_RAKP_NONE;
+ integrity_alg = IPMI_INTEGRITY_NONE;
+ crypt_alg = IPMI_CRYPT_NONE;
+
+ while (((cipher_suite_data[offset] & 0xC0) != 0xC0) &&
+ ((cipher_suite_data_length - offset) > 0))
+ {
+ switch (cipher_suite_data[offset] & 0xC0)
+ {
+ case 0x00:
+ // Authentication algorithm specifier
+ auth_alg = cipher_suite_data[offset++] & 0x3F;
+ break;
+ case 0x40:
+ // Interity algorithm specifier
+ integrity_alg = cipher_suite_data[offset++] & 0x3F;
+ break;
+ case 0x80:
+ // Confidentiality algorithm specifier
+ crypt_alg = cipher_suite_data[offset++] & 0x3F;
+ break;
+ }
+ }
+
+
+ //
+ // We have everything we need to spit out a cipher suite record
+ //
+ printf((csv_output? "%d,%s,%s,%s,%s\n" :
+ "%-4d %-7s %-15s %-15s %-15s\n"),
+ cipher_suite_id,
+ iana_string(iana),
+ val2str(auth_alg, ipmi_auth_algorithms),
+ val2str(integrity_alg, ipmi_integrity_algorithms),
+ val2str(crypt_alg, ipmi_encryption_algorithms));
+ }
+
+
+ return 0;
+}
+
+
+
+uint8_t
+ipmi_get_channel_medium(struct ipmi_intf * intf, uint8_t channel)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct get_channel_info_rsp info;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_GET_CHANNEL_INFO;
+ req.msg.data = &channel;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Channel Info command failed");
+ return 0;
+ }
+ if (rsp->ccode > 0) {
+ if (rsp->ccode == 0xcc)
+ return IPMI_CHANNEL_MEDIUM_RESERVED;
+ lprintf(LOG_INFO, "Get Channel Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IPMI_CHANNEL_MEDIUM_RESERVED;
+ }
+
+ memcpy(&info, rsp->data, sizeof(struct get_channel_info_rsp));
+
+ lprintf(LOG_DEBUG, "Channel type: %s",
+ val2str(info.channel_medium, ipmi_channel_medium_vals));
+
+ return info.channel_medium;
+}
+
+uint8_t
+ipmi_current_channel_medium(struct ipmi_intf * intf)
+{
+ return ipmi_get_channel_medium(intf, 0xE);
+}
+
+void
+printf_channel_usage()
+{
+ lprintf(LOG_NOTICE, "Channel Commands: authcap <channel number> <max privilege>");
+ lprintf(LOG_NOTICE, " getaccess <channel number> [user id]");
+ lprintf(LOG_NOTICE, " setaccess <channel number> "
+ "<user id> [callin=on|off] [ipmi=on|off] [link=on|off] [privilege=level]");
+ lprintf(LOG_NOTICE, " info [channel number]");
+ lprintf(LOG_NOTICE, " getciphers <ipmi | sol> [channel]\n");
+ lprintf(LOG_NOTICE, "Possible privilege levels are:");
+ lprintf(LOG_NOTICE, " 1 Callback level");
+ lprintf(LOG_NOTICE, " 2 User level");
+ lprintf(LOG_NOTICE, " 3 Operator level");
+ lprintf(LOG_NOTICE, " 4 Administrator level");
+ lprintf(LOG_NOTICE, " 5 OEM Proprietary level");
+ lprintf(LOG_NOTICE, " 15 No access");
+}
+
+
+int
+ipmi_channel_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int retval = 0;
+ uint8_t channel, priv = 0;
+
+ if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0))
+ {
+ printf_channel_usage();
+ }
+ else if (strncmp(argv[0], "authcap", 7) == 0)
+ {
+ if (argc != 3) {
+ printf_channel_usage();
+ return (-1);
+ } else {
+ if (str2uchar(argv[1], &channel) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[1]);
+ return (-1);
+ }
+ if (str2uchar(argv[2], &priv) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[2]);
+ return (-1);
+ }
+ retval = ipmi_get_channel_auth_cap(intf, channel, priv);
+ }
+ }
+ else if (strncmp(argv[0], "getaccess", 10) == 0)
+ {
+ if ((argc < 2) || (argc > 3))
+ printf_channel_usage();
+ else {
+ uint8_t ch = 0;
+ uint8_t id = 0;
+ if (str2uchar(argv[1], &ch) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[1]);
+ return (-1);
+ }
+ if (argc == 3) {
+ if (str2uchar(argv[2], &id) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[2]);
+ return (-1);
+ }
+ }
+ retval = ipmi_get_user_access(intf, ch, id);
+ }
+ }
+ else if (strncmp(argv[0], "setaccess", 9) == 0)
+ {
+ retval = ipmi_set_user_access(intf, argc-1, &(argv[1]));
+ }
+ else if (strncmp(argv[0], "info", 4) == 0)
+ {
+ if (argc > 2)
+ printf_channel_usage();
+ else {
+ uint8_t ch = 0xe;
+ if (argc == 2) {
+ if (str2uchar(argv[1], &ch) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[1]);
+ return (-1);
+ }
+ }
+ retval = ipmi_get_channel_info(intf, ch);
+ }
+ }
+
+ // it channel getciphers <ipmi | sol> [channel]
+ else if (strncmp(argv[0], "getciphers", 10) == 0)
+ {
+ if ((argc < 2) || (argc > 3) ||
+ (strncmp(argv[1], "ipmi", 4) && strncmp(argv[1], "sol", 3)))
+ printf_channel_usage();
+ else
+ {
+ uint8_t ch = 0xe;
+ if (argc == 3) {
+ if (str2uchar(argv[2], &ch) != 0) {
+ lprintf(LOG_ERR, "Numeric value expected, but '%s' given.", argv[2]);
+ return (-1);
+ }
+ }
+ retval = ipmi_get_channel_cipher_suites(intf,
+ argv[1], // ipmi | sol
+ ch);
+ }
+ }
+ else
+ {
+ printf("Invalid CHANNEL command: %s\n", argv[0]);
+ printf_channel_usage();
+ retval = -1;
+ }
+
+ return retval;
+}
diff --git a/lib/ipmi_chassis.c b/lib/ipmi_chassis.c
new file mode 100644
index 0000000..d4e88ee
--- /dev/null
+++ b/lib/ipmi_chassis.c
@@ -0,0 +1,1393 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <ipmitool/bswap.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_chassis.h>
+
+extern int verbose;
+
+int
+ipmi_chassis_power_status(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x1;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to get Chassis Power Status");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Chassis Power Status failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return rsp->data[0] & 1;
+}
+
+static int
+ipmi_chassis_print_power_status(struct ipmi_intf * intf)
+{
+ int ps = ipmi_chassis_power_status(intf);
+
+ if (ps < 0)
+ return -1;
+
+ printf("Chassis Power is %s\n", ps ? "on" : "off");
+
+ return 0;
+}
+
+int
+ipmi_chassis_power_control(struct ipmi_intf * intf, uint8_t ctl)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x2;
+ req.msg.data = &ctl;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to set Chassis Power Control to %s",
+ val2str(ctl, ipmi_chassis_power_control_vals));
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Chassis Power Control to %s failed: %s",
+ val2str(ctl, ipmi_chassis_power_control_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("Chassis Power Control: %s\n",
+ val2str(ctl, ipmi_chassis_power_control_vals));
+
+#if 0 /* this can cause sessions to hang around after power commands */
+ /* sessions often get lost when changing chassis power */
+ intf->abort = 1;
+#endif
+
+ return 0;
+}
+
+static int
+ipmi_chassis_identify(struct ipmi_intf * intf, char * arg)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ int rc = (-3);
+
+ struct {
+ uint8_t interval;
+ uint8_t force_on;
+ } identify_data = { .interval = 0, .force_on = 0 };
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x4;
+
+ if (arg != NULL) {
+ if (strncmp(arg, "force", 5) == 0) {
+ identify_data.force_on = 1;
+ } else {
+ if ( (rc = str2uchar(arg, &identify_data.interval)) != 0) {
+ if (rc == (-2)) {
+ lprintf(LOG_ERR, "Invalid interval given.");
+ } else {
+ lprintf(LOG_ERR, "Given interval is too big.");
+ }
+ return (-1);
+ }
+ }
+ req.msg.data = (uint8_t *)&identify_data;
+ /* The Force Identify On byte is optional and not
+ * supported by all devices-- if force is not specified,
+ * we pass only one data byte; if specified, we pass two
+ * data bytes and check for an error completion code
+ */
+ req.msg.data_len = (identify_data.force_on) ? 2 : 1;
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to set Chassis Identify");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Chassis Identify failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ if (identify_data.force_on != 0) {
+ /* Intel SE7501WV2 F/W 1.2 returns CC 0xC7, but
+ * the IPMI v1.5 spec does not standardize a CC
+ * if unsupported, so we warn
+ */
+ lprintf(LOG_WARNING, "Chassis may not support Force Identify On\n");
+ }
+ return -1;
+ }
+
+ printf("Chassis identify interval: ");
+ if (arg == NULL) {
+ printf("default (15 seconds)\n");
+ } else {
+ if (identify_data.force_on != 0) {
+ printf("indefinite\n");
+ } else {
+ if (identify_data.interval == 0)
+ printf("off\n");
+ else
+ printf("%i seconds\n", identify_data.interval);
+ }
+ }
+ return 0;
+}
+
+static int
+ipmi_chassis_poh(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t mins_per_count;
+ uint32_t count;
+ float minutes;
+ uint32_t days, hours;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0xf;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to get Chassis Power-On-Hours");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Chassis Power-On-Hours failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ mins_per_count = rsp->data[0];
+ memcpy(&count, rsp->data+1, 4);
+#if WORDS_BIGENDIAN
+ count = BSWAP_32(count);
+#endif
+
+ minutes = (float)count * mins_per_count;
+ days = minutes / 1440;
+ minutes -= (float)days * 1440;
+ hours = minutes / 60;
+ minutes -= hours * 60;
+
+ if (mins_per_count < 60) {
+ printf("POH Counter : %i days, %i hours, %li minutes\n",
+ days, hours, (long)minutes);
+ } else {
+ printf("POH Counter : %i days, %i hours\n", days, hours);
+ }
+
+ return 0;
+}
+
+static int
+ipmi_chassis_restart_cause(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x7;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to get Chassis Restart Cause");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Chassis Restart Cause failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("System restart cause: ");
+
+ switch (rsp->data[0] & 0xf) {
+ case 0:
+ printf("unknown\n");
+ break;
+ case 1:
+ printf("chassis power control command\n");
+ break;
+ case 2:
+ printf("reset via pushbutton\n");
+ break;
+ case 3:
+ printf("power-up via pushbutton\n");
+ break;
+ case 4:
+ printf("watchdog expired\n");
+ break;
+ case 5:
+ printf("OEM\n");
+ break;
+ case 6:
+ printf("power-up due to always-restore power policy\n");
+ break;
+ case 7:
+ printf("power-up due to restore-previous power policy\n");
+ break;
+ case 8:
+ printf("reset via PEF\n");
+ break;
+ case 9:
+ printf("power-cycle via PEF\n");
+ break;
+ default:
+ printf("invalid\n");
+ }
+
+ return 0;
+}
+
+int
+ipmi_chassis_status(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error sending Chassis Status command");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error sending Chassis Status command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ /* byte 1 */
+ printf("System Power : %s\n", (rsp->data[0] & 0x1) ? "on" : "off");
+ printf("Power Overload : %s\n", (rsp->data[0] & 0x2) ? "true" : "false");
+ printf("Power Interlock : %s\n", (rsp->data[0] & 0x4) ? "active" : "inactive");
+ printf("Main Power Fault : %s\n", (rsp->data[0] & 0x8) ? "true" : "false");
+ printf("Power Control Fault : %s\n", (rsp->data[0] & 0x10) ? "true" : "false");
+ printf("Power Restore Policy : ");
+ switch ((rsp->data[0] & 0x60) >> 5) {
+ case 0x0:
+ printf("always-off\n");
+ break;
+ case 0x1:
+ printf("previous\n");
+ break;
+ case 0x2:
+ printf("always-on\n");
+ break;
+ case 0x3:
+ default:
+ printf("unknown\n");
+ }
+
+ /* byte 2 */
+ printf("Last Power Event : ");
+ if (rsp->data[1] & 0x1)
+ printf("ac-failed ");
+ if (rsp->data[1] & 0x2)
+ printf("overload ");
+ if (rsp->data[1] & 0x4)
+ printf("interlock ");
+ if (rsp->data[1] & 0x8)
+ printf("fault ");
+ if (rsp->data[1] & 0x10)
+ printf("command");
+ printf("\n");
+
+ /* byte 3 */
+ printf("Chassis Intrusion : %s\n", (rsp->data[2] & 0x1) ? "active" : "inactive");
+ printf("Front-Panel Lockout : %s\n", (rsp->data[2] & 0x2) ? "active" : "inactive");
+ printf("Drive Fault : %s\n", (rsp->data[2] & 0x4) ? "true" : "false");
+ printf("Cooling/Fan Fault : %s\n", (rsp->data[2] & 0x8) ? "true" : "false");
+
+ if (rsp->data_len > 3) {
+ /* optional byte 4 */
+ if (rsp->data[3] == 0) {
+ printf("Front Panel Control : none\n");
+ } else {
+ printf("Sleep Button Disable : %s\n", (rsp->data[3] & 0x80) ? "allowed" : "not allowed");
+ printf("Diag Button Disable : %s\n", (rsp->data[3] & 0x40) ? "allowed" : "not allowed");
+ printf("Reset Button Disable : %s\n", (rsp->data[3] & 0x20) ? "allowed" : "not allowed");
+ printf("Power Button Disable : %s\n", (rsp->data[3] & 0x10) ? "allowed" : "not allowed");
+ printf("Sleep Button Disabled: %s\n", (rsp->data[3] & 0x08) ? "true" : "false");
+ printf("Diag Button Disabled : %s\n", (rsp->data[3] & 0x04) ? "true" : "false");
+ printf("Reset Button Disabled: %s\n", (rsp->data[3] & 0x02) ? "true" : "false");
+ printf("Power Button Disabled: %s\n", (rsp->data[3] & 0x01) ? "true" : "false");
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+ipmi_chassis_selftest(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error sending Get Self Test command");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error sending Get Self Test command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("Self Test Results : ");
+ switch (rsp->data[0]) {
+ case 0x55:
+ printf("passed\n");
+ break;
+
+ case 0x56:
+ printf("not implemented\n");
+ break;
+
+ case 0x57:
+ {
+ int i;
+ const struct valstr broken_dev_vals[] = {
+ { 0, "firmware corrupted" },
+ { 1, "boot block corrupted" },
+ { 2, "FRU Internal Use Area corrupted" },
+ { 3, "SDR Repository empty" },
+ { 4, "IPMB not responding" },
+ { 5, "cannot access BMC FRU" },
+ { 6, "cannot access SDR Repository" },
+ { 7, "cannot access SEL Device" },
+ { 0xff, NULL },
+ };
+ printf("device error\n");
+ for (i=0; i<8; i++) {
+ if (rsp->data[1] & (1<<i)) {
+ printf(" [%s]\n",
+ val2str(i, broken_dev_vals));
+ }
+ }
+ }
+ break;
+
+ case 0x58:
+ printf("Fatal hardware error: %02xh\n", rsp->data[1]);
+ break;
+
+ default:
+ printf("Device-specific failure %02xh:%02xh\n",
+ rsp->data[0], rsp->data[1]);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+ipmi_chassis_set_bootparam(struct ipmi_intf * intf, uint8_t param, uint8_t * data, int len)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[16];
+
+ memset(msg_data, 0, 16);
+ msg_data[0] = param & 0x7f;
+ memcpy(msg_data+1, data, len);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x8;
+ req.msg.data = msg_data;
+ req.msg.data_len = len + 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ if (param != 0) {
+ lprintf(LOG_ERR, "Set Chassis Boot Parameter %d failed: %s",
+ param, val2str(rsp->ccode, completion_code_vals));
+ }
+ return -1;
+ }
+
+ lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len));
+ return 0;
+}
+
+static int
+ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[3];
+ uint8_t param_id = 0;
+
+ if (arg == NULL)
+ return -1;
+
+ if (str2uchar(arg, &param_id) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter '%s' given instead of bootparam.",
+ arg);
+ return (-1);
+ }
+
+ memset(msg_data, 0, 3);
+
+ msg_data[0] = param_id & 0x7f;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x9;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error Getting Chassis Boot Parameter %s", arg);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Chassis Boot Parameter %s failed: %s",
+ arg, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ if (verbose > 2)
+ printbuf(rsp->data, rsp->data_len, "Boot Option");
+
+ param_id = 0;
+ param_id = (rsp->data[1] & 0x7f);
+
+ printf("Boot parameter version: %d\n", rsp->data[0]);
+ printf("Boot parameter %d is %s\n", rsp->data[1] & 0x7f,
+ (rsp->data[1] & 0x80) ? "invalid/locked" : "valid/unlocked");
+ printf("Boot parameter data: %s\n", buf2str(rsp->data+2, rsp->data_len - 2));
+
+ switch(param_id)
+ {
+ case 0:
+ {
+ printf(" Set In Progress : ");
+ switch((rsp->data[2]) &0x03)
+ {
+ case 0: printf("set complete\n"); break;
+ case 1: printf("set in progress\n"); break;
+ case 2: printf("commit write\n"); break;
+ default: printf("error, reserved bit\n"); break;
+ }
+ }
+ break;
+ case 1:
+ {
+ printf(" Service Partition Selector : ");
+ if((rsp->data[2]) == 0)
+ {
+ printf("unspecified\n");
+ }
+ else
+ {
+ printf("%d\n",(rsp->data[2]));
+ }
+ }
+ break;
+ case 2:
+ {
+ printf( " Service Partition Scan :\n");
+ if((rsp->data[2]&0x03) != 0)
+ {
+ if((rsp->data[2]&0x01) == 0x01)
+ printf(" - Request BIOS to scan\n");
+ if((rsp->data[2]&0x02) == 0x02)
+ printf(" - Service Partition Discovered\n");
+ }
+ else
+ {
+ printf(" No flag set\n");
+ }
+ }
+ break;
+ case 3:
+ {
+ printf( " BMC boot flag valid bit clearing :\n");
+ if((rsp->data[2]&0x1f) != 0)
+ {
+ if((rsp->data[2]&0x10) == 0x10)
+ printf(" - Don't clear valid bit on reset/power cycle cause by PEF\n");
+ if((rsp->data[2]&0x08) == 0x08)
+ printf(" - Don't automatically clear boot flag valid bit on timeout\n");
+ if((rsp->data[2]&0x04) == 0x04)
+ printf(" - Don't clear valid bit on reset/power cycle cause by watchdog\n");
+ if((rsp->data[2]&0x02) == 0x02)
+ printf(" - Don't clear valid bit on push button reset // soft reset\n");
+ if((rsp->data[2]&0x01) == 0x01)
+ printf(" - Don't clear valid bit on power up via power push button or wake event\n");
+ }
+ else
+ {
+ printf(" No flag set\n");
+ }
+ }
+ break;
+ case 4:
+ {
+ printf( " Boot Info Acknowledge :\n");
+ if((rsp->data[3]&0x1f) != 0)
+ {
+ if((rsp->data[3]&0x10) == 0x10)
+ printf(" - OEM has handled boot info\n");
+ if((rsp->data[3]&0x08) == 0x08)
+ printf(" - SMS has handled boot info\n");
+ if((rsp->data[3]&0x04) == 0x04)
+ printf(" - OS // service partition has handled boot info\n");
+ if((rsp->data[3]&0x02) == 0x02)
+ printf(" - OS Loader has handled boot info\n");
+ if((rsp->data[3]&0x01) == 0x01)
+ printf(" - BIOS/POST has handled boot info\n");
+ }
+ else
+ {
+ printf(" No flag set\n");
+ }
+ }
+ break;
+ case 5:
+ {
+ printf( " Boot Flags :\n");
+
+ if((rsp->data[2]&0x80) == 0x80)
+ printf(" - Boot Flag Valid\n");
+ else
+ printf(" - Boot Flag Invalid\n");
+
+ if((rsp->data[2]&0x40) == 0x40)
+ printf(" - Options apply to all future boots\n");
+ else
+ printf(" - Options apply to only next boot\n");
+
+ if((rsp->data[2]&0x20) == 0x20)
+ printf(" - BIOS EFI boot \n");
+ else
+ printf(" - BIOS PC Compatible (legacy) boot \n");
+
+ if((rsp->data[3]&0x80) == 0x80)
+ printf(" - CMOS Clear\n");
+ if((rsp->data[3]&0x40) == 0x40)
+ printf(" - Lock Keyboard\n");
+ printf(" - Boot Device Selector : ");
+ switch( ((rsp->data[3]>>2)&0x0f))
+ {
+ case 0: printf("No override\n"); break;
+ case 1: printf("Force PXE\n"); break;
+ case 2: printf("Force Boot from default Hard-Drive\n"); break;
+ case 3: printf("Force Boot from default Hard-Drive, request Safe-Mode\n"); break;
+ case 4: printf("Force Boot from Diagnostic Partition\n"); break;
+ case 5: printf("Force Boot from CD/DVD\n"); break;
+ case 6: printf("Force Boot into BIOS Setup\n"); break;
+ case 15: printf("Force Boot from Floppy/primary removable media\n"); break;
+ default: printf("Flag error\n"); break;
+ }
+ if((rsp->data[3]&0x02) == 0x02)
+ printf(" - Screen blank\n");
+ if((rsp->data[3]&0x01) == 0x01)
+ printf(" - Lock out Reset buttons\n");
+
+ if((rsp->data[4]&0x80) == 0x80)
+ printf(" - Lock out (power off/sleep request) vi Power Button\n");
+ printf(" - Console Redirection control : ");
+ switch( ((rsp->data[4]>>5)&0x03))
+ {
+ case 0: printf("System Default\n"); break;
+ case 1: printf("Request Quiet Display\n"); break;
+ case 2: printf("Request Verbose Display\n"); break;
+ default: printf("Flag error\n"); break;
+ }
+ if((rsp->data[4]&0x10) == 0x10)
+ printf(" - Force progress event traps\n");
+ if((rsp->data[4]&0x08) == 0x08)
+ printf(" - User password bypass\n");
+ if((rsp->data[4]&0x04) == 0x04)
+ printf(" - Lock Out Sleep Button\n");
+ if((rsp->data[4]&0x02) == 0x02)
+ printf(" - Lock Out Sleep Button\n");
+ printf(" - BIOS verbosity : ");
+ switch( ((rsp->data[4]>>0)&0x03))
+ {
+ case 0: printf("Console redirection occurs per BIOS configuration setting (default)\n"); break;
+ case 1: printf("Suppress (skip) console redirection if enabled\n"); break;
+ case 2: printf("Request console redirection be enabled\n"); break;
+ default: printf("Flag error\n"); break;
+ }
+
+ if((rsp->data[5]&0x08) == 0x08)
+ printf(" - BIOS Shared Mode Override\n");
+ printf(" - BIOS Mux Control Override : ");
+ switch( ((rsp->data[5]>>0)&0x07))
+ {
+ case 0: printf("BIOS uses recommended setting of the mux at the end of POST\n"); break;
+ case 1: printf("Requests BIOS to force mux to BMC at conclusion of POST/start of OS boot\n"); break;
+ case 2: printf("Requests BIOS to force mux to system at conclusion of POST/start of OS boot\n"); break;
+ default: printf("Flag error\n"); break;
+ }
+ }
+ break;
+ case 6:
+ {
+ unsigned long session_id;
+ unsigned long timestamp;
+ char time_buf[40];
+ time_t out_time;
+
+ session_id = ((unsigned long) rsp->data[3]);
+ session_id |= (((unsigned long) rsp->data[4])<<8);
+ session_id |= (((unsigned long) rsp->data[5])<<16);
+ session_id |= (((unsigned long) rsp->data[6])<<24);
+
+ timestamp = ((unsigned long) rsp->data[7]);
+ timestamp |= (((unsigned long) rsp->data[8])<<8);
+ timestamp |= (((unsigned long) rsp->data[9])<<16);
+ timestamp |= (((unsigned long) rsp->data[10])<<24);
+
+ memset(time_buf, 0, 40);
+ strftime(
+ time_buf,
+ sizeof(time_buf),
+ "%m/%d/%Y %H:%M:%S", localtime(&out_time)
+ );
+
+ printf(" Boot Initiator Info :\n");
+ printf(" Channel Number : %d\n", (rsp->data[2] & 0x0f));
+ printf(" Session Id : %08lXh\n",session_id);
+ if(timestamp != 0)
+ {
+ printf(" Timestamp : %08lXh, %s\n",timestamp,time_buf);
+ }
+ else
+ {
+ printf(" Timestamp : %08lXh, undefined\n",timestamp);
+ }
+
+ }
+ break;
+ case 7:
+ {
+ printf(" Selector : %d\n", rsp->data[2] );
+ printf(" Block Data : %s\n", buf2str(rsp->data+3, rsp->data_len - 2));
+ }
+ break;
+ default:
+ printf(" Undefined byte\n");
+ break;
+ }
+
+ return 0;
+}
+
+static int
+get_bootparam_options(char *optstring,
+ unsigned char *set_flag, unsigned char *clr_flag)
+{
+ char *token;
+ char *saveptr = NULL;
+ int optionError = 0;
+ *set_flag = 0;
+ *clr_flag = 0;
+ static struct {
+ char *name;
+ unsigned char value;
+ char *desc;
+ } options[] = {
+ {"PEF", 0x10,
+ "Clear valid bit on reset/power cycle cause by PEF"},
+ {"timeout", 0x08,
+ "Automatically clear boot flag valid bit on timeout"},
+ {"watchdog", 0x04,
+ "Clear valid bit on reset/power cycle cause by watchdog"},
+ {"reset", 0x02,
+ "Clear valid bit on push button reset/soft reset"},
+ {"power", 0x01,
+ "Clear valid bit on power up via power push button or wake event"},
+
+ {NULL} /* End marker */
+ }, *op;
+
+ if (strncmp(optstring, "options=", 8) != 0) {
+ lprintf(LOG_ERR, "No options= keyword found \"%s\"", optstring);
+ return -1;
+ }
+ token = strtok_r(optstring + 8, ",", &saveptr);
+ while (token != NULL) {
+ int setbit = 0;
+ if (strcmp(token, "help") == 0) {
+ optionError = 1;
+ break;
+ }
+ if (strncmp(token, "no-", 3) == 0) {
+ setbit = 1;
+ token += 3;
+ }
+ for (op = options; op->name != NULL; ++op) {
+ if (strncmp(token, op->name, strlen(op->name)) == 0) {
+ if (setbit) {
+ *set_flag |= op->value;
+ } else {
+ *clr_flag |= op->value;
+ }
+ break;
+ }
+ }
+ if (op->name == NULL) {
+ /* Option not found */
+ optionError = 1;
+ if (setbit) {
+ token -=3;
+ }
+ lprintf(LOG_ERR, "Invalid option: %s", token);
+ }
+ token = strtok_r(NULL, ",", &saveptr);
+ }
+ if (optionError) {
+ lprintf(LOG_NOTICE, " Legal options are:");
+ lprintf(LOG_NOTICE, " %-8s: print this message", "help");
+ for (op = options; op->name != NULL; ++op) {
+ lprintf(LOG_NOTICE, " %-8s: %s", op->name, op->desc);
+ }
+ lprintf(LOG_NOTICE, " Any Option may be prepended with no-"
+ " to invert sense of operation\n");
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[3];
+ uint8_t param_id = IPMI_CHASSIS_BOOTPARAM_FLAG_VALID;
+ memset(msg_data, 0, 3);
+
+ msg_data[0] = param_id & 0x7f;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x9;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Error Getting Chassis Boot Parameter %d", param_id);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Chassis Boot Parameter %d failed: %s",
+ param_id, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ if (verbose > 2)
+ printbuf(rsp->data, rsp->data_len, "Boot Option");
+
+ return(rsp->data[2]);
+}
+
+static int
+ipmi_chassis_set_bootvalid(struct ipmi_intf *intf, uint8_t set_flag, uint8_t clr_flag)
+{
+ int bootvalid;
+ uint8_t flags[5];
+ int rc = 0;
+ int use_progress = 1;
+ uint8_t param_id = IPMI_CHASSIS_BOOTPARAM_FLAG_VALID;
+
+ if (use_progress) {
+ /* set set-in-progress flag */
+ memset(flags, 0, 5);
+ flags[0] = 0x01;
+ rc = ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, flags, 1);
+ if (rc < 0)
+ use_progress = 0;
+ }
+
+ memset(flags, 0, 5);
+ flags[0] = 0x01;
+ flags[1] = 0x01;
+ rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
+ flags, 2);
+
+ if (rc < 0) {
+ if (use_progress) {
+ /* set-in-progress = set-complete */
+ memset(flags, 0, 5);
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+ return -1;
+ }
+
+ bootvalid = ipmi_chassis_get_bootvalid(intf);
+
+ if (bootvalid < 0) {
+ if (use_progress) {
+ /* set-in-progress = set-complete */
+ memset(flags, 0, 5);
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+ return -1;
+ }
+ flags[0] = (bootvalid & ~clr_flag) | set_flag;
+
+ rc = ipmi_chassis_set_bootparam(intf, param_id, flags, 1);
+
+ if (rc == 0) {
+ if (use_progress) {
+ /* set-in-progress = commit-write */
+ memset(flags, 0, 5);
+ flags[0] = 0x02;
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+ }
+
+ if (use_progress) {
+ /* set-in-progress = set-complete */
+ memset(flags, 0, 5);
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+
+ return rc;
+}
+
+static int
+ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags)
+{
+ uint8_t flags[5];
+ int rc = 0;
+ int use_progress = 1;
+
+ if (use_progress) {
+ /* set set-in-progress flag */
+ memset(flags, 0, 5);
+ flags[0] = 0x01;
+ rc = ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, flags, 1);
+ if (rc < 0)
+ use_progress = 0;
+ }
+
+ memset(flags, 0, 5);
+ flags[0] = 0x01;
+ flags[1] = 0x01;
+ rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
+ flags, 2);
+
+ if (rc < 0) {
+ if (use_progress) {
+ /* set-in-progress = set-complete */
+ memset(flags, 0, 5);
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+ return -1;
+ }
+
+ if (iflags == NULL)
+ memset(flags, 0, 5);
+ else
+ memcpy(flags, iflags, sizeof (flags));
+
+ if (arg == NULL)
+ flags[1] |= 0x00;
+ else if (strncmp(arg, "none", 4) == 0)
+ flags[1] |= 0x00;
+ else if (strncmp(arg, "pxe", 3) == 0 ||
+ strncmp(arg, "force_pxe", 9) == 0)
+ flags[1] |= 0x04;
+ else if (strncmp(arg, "disk", 4) == 0 ||
+ strncmp(arg, "force_disk", 10) == 0)
+ flags[1] |= 0x08;
+ else if (strncmp(arg, "safe", 4) == 0 ||
+ strncmp(arg, "force_safe", 10) == 0)
+ flags[1] |= 0x0c;
+ else if (strncmp(arg, "diag", 4) == 0 ||
+ strncmp(arg, "force_diag", 10) == 0)
+ flags[1] |= 0x10;
+ else if (strncmp(arg, "cdrom", 5) == 0 ||
+ strncmp(arg, "force_cdrom", 11) == 0)
+ flags[1] |= 0x14;
+ else if (strncmp(arg, "floppy", 6) == 0 ||
+ strncmp(arg, "force_floppy", 12) == 0)
+ flags[1] |= 0x3c;
+ else if (strncmp(arg, "bios", 4) == 0 ||
+ strncmp(arg, "force_bios", 10) == 0)
+ flags[1] |= 0x18;
+ else {
+ lprintf(LOG_ERR, "Invalid argument: %s", arg);
+ if (use_progress) {
+ /* set-in-progress = set-complete */
+ memset(flags, 0, 5);
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+ return -1;
+ }
+
+ /* set flag valid bit */
+ flags[0] |= 0x80;
+
+ rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_BOOT_FLAGS,
+ flags, 5);
+ if (rc == 0) {
+ if (use_progress) {
+ /* set-in-progress = commit-write */
+ memset(flags, 0, 5);
+ flags[0] = 0x02;
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+
+ printf("Set Boot Device to %s\n", arg);
+ }
+
+ if (use_progress) {
+ /* set-in-progress = set-complete */
+ memset(flags, 0, 5);
+ ipmi_chassis_set_bootparam(intf,
+ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
+ flags, 1);
+ }
+
+ return rc;
+}
+
+static int
+ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_CHASSIS;
+ req.msg.cmd = 0x6;
+ req.msg.data = &policy;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in Power Restore Policy command");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Power Restore Policy command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ if (policy == IPMI_CHASSIS_POLICY_NO_CHANGE) {
+ printf("Supported chassis power policy: ");
+ if (rsp->data[0] & (1<<IPMI_CHASSIS_POLICY_ALWAYS_OFF))
+ printf("always-off ");
+ if (rsp->data[0] & (1<<IPMI_CHASSIS_POLICY_ALWAYS_ON))
+ printf("always-on ");
+ if (rsp->data[0] & (1<<IPMI_CHASSIS_POLICY_PREVIOUS))
+ printf("previous");
+ printf("\n");
+ }
+ else {
+ printf("Set chassis power restore policy to ");
+ switch (policy) {
+ case IPMI_CHASSIS_POLICY_ALWAYS_ON:
+ printf("always-on\n");
+ break;
+ case IPMI_CHASSIS_POLICY_ALWAYS_OFF:
+ printf("always-off\n");
+ break;
+ case IPMI_CHASSIS_POLICY_PREVIOUS:
+ printf("previous\n");
+ break;
+ default:
+ printf("unknown\n");
+ }
+ }
+ return 0;
+}
+
+int
+ipmi_power_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ uint8_t ctl = 0;
+
+ if ((argc < 1) || (strncmp(argv[0], "help", 4) == 0)) {
+ lprintf(LOG_NOTICE, "chassis power Commands: status, on, off, cycle, reset, diag, soft");
+ return 0;
+ }
+ if (strncmp(argv[0], "status", 6) == 0) {
+ rc = ipmi_chassis_print_power_status(intf);
+ return rc;
+ }
+ if ((strncmp(argv[0], "up", 2) == 0) || (strncmp(argv[0], "on", 2) == 0))
+ ctl = IPMI_CHASSIS_CTL_POWER_UP;
+ else if ((strncmp(argv[0], "down", 4) == 0) || (strncmp(argv[0], "off", 3) == 0))
+ ctl = IPMI_CHASSIS_CTL_POWER_DOWN;
+ else if (strncmp(argv[0], "cycle", 5) == 0)
+ ctl = IPMI_CHASSIS_CTL_POWER_CYCLE;
+ else if (strncmp(argv[0], "reset", 5) == 0)
+ ctl = IPMI_CHASSIS_CTL_HARD_RESET;
+ else if (strncmp(argv[0], "diag", 4) == 0)
+ ctl = IPMI_CHASSIS_CTL_PULSE_DIAG;
+ else if ((strncmp(argv[0], "acpi", 4) == 0) || (strncmp(argv[0], "soft", 4) == 0))
+ ctl = IPMI_CHASSIS_CTL_ACPI_SOFT;
+ else {
+ lprintf(LOG_ERR, "Invalid chassis power command: %s", argv[0]);
+ return -1;
+ }
+
+ rc = ipmi_chassis_power_control(intf, ctl);
+ return rc;
+}
+
+void
+ipmi_chassis_set_bootflag_help()
+{
+ unsigned char set_flag;
+ unsigned char clr_flag;
+ lprintf(LOG_NOTICE, "bootparam set bootflag <device> [options=...]");
+ lprintf(LOG_NOTICE, " Legal devices are:");
+ lprintf(LOG_NOTICE, " none : No override");
+ lprintf(LOG_NOTICE, " force_pxe : Force PXE boot");
+ lprintf(LOG_NOTICE, " force_disk : Force boot from default Hard-drive");
+ lprintf(LOG_NOTICE, " force_safe : Force boot from default Hard-drive, request Safe Mode");
+ lprintf(LOG_NOTICE, " force_diag : Force boot from Diagnostic Partition");
+ lprintf(LOG_NOTICE, " force_cdrom : Force boot from CD/DVD");
+ lprintf(LOG_NOTICE, " force_bios : Force boot into BIOS Setup");
+ get_bootparam_options("options=help", &set_flag, &clr_flag);
+}
+
+int
+ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
+ lprintf(LOG_NOTICE, "Chassis Commands: status, power, identify, policy, restart_cause, poh, bootdev, bootparam, selftest");
+ }
+ else if (strncmp(argv[0], "status", 6) == 0) {
+ rc = ipmi_chassis_status(intf);
+ }
+ else if (strncmp(argv[0], "selftest", 8) == 0) {
+ rc = ipmi_chassis_selftest(intf);
+ }
+ else if (strncmp(argv[0], "power", 5) == 0) {
+ uint8_t ctl = 0;
+
+ if ((argc < 2) || (strncmp(argv[1], "help", 4) == 0)) {
+ lprintf(LOG_NOTICE, "chassis power Commands: status, on, off, cycle, reset, diag, soft");
+ return 0;
+ }
+ if (strncmp(argv[1], "status", 6) == 0) {
+ rc = ipmi_chassis_print_power_status(intf);
+ return rc;
+ }
+ if ((strncmp(argv[1], "up", 2) == 0) || (strncmp(argv[1], "on", 2) == 0))
+ ctl = IPMI_CHASSIS_CTL_POWER_UP;
+ else if ((strncmp(argv[1], "down", 4) == 0) || (strncmp(argv[1], "off", 3) == 0))
+ ctl = IPMI_CHASSIS_CTL_POWER_DOWN;
+ else if (strncmp(argv[1], "cycle", 5) == 0)
+ ctl = IPMI_CHASSIS_CTL_POWER_CYCLE;
+ else if (strncmp(argv[1], "reset", 5) == 0)
+ ctl = IPMI_CHASSIS_CTL_HARD_RESET;
+ else if (strncmp(argv[1], "diag", 4) == 0)
+ ctl = IPMI_CHASSIS_CTL_PULSE_DIAG;
+ else if ((strncmp(argv[1], "acpi", 4) == 0) || (strncmp(argv[1], "soft", 4) == 0))
+ ctl = IPMI_CHASSIS_CTL_ACPI_SOFT;
+ else {
+ lprintf(LOG_ERR, "Invalid chassis power command: %s", argv[1]);
+ return -1;
+ }
+
+ rc = ipmi_chassis_power_control(intf, ctl);
+ }
+ else if (strncmp(argv[0], "identify", 8) == 0) {
+ if (argc < 2) {
+ rc = ipmi_chassis_identify(intf, NULL);
+ }
+ else if (strncmp(argv[1], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "chassis identify <interval>");
+ lprintf(LOG_NOTICE, " default is 15 seconds");
+ lprintf(LOG_NOTICE, " 0 to turn off");
+ lprintf(LOG_NOTICE, " force to turn on indefinitely");
+ } else {
+ rc = ipmi_chassis_identify(intf, argv[1]);
+ }
+ }
+ else if (strncmp(argv[0], "poh", 3) == 0) {
+ rc = ipmi_chassis_poh(intf);
+ }
+ else if (strncmp(argv[0], "restart_cause", 13) == 0) {
+ rc = ipmi_chassis_restart_cause(intf);
+ }
+ else if (strncmp(argv[0], "policy", 4) == 0) {
+ if ((argc < 2) || (strncmp(argv[1], "help", 4) == 0)) {
+ lprintf(LOG_NOTICE, "chassis policy <state>");
+ lprintf(LOG_NOTICE, " list : return supported policies");
+ lprintf(LOG_NOTICE, " always-on : turn on when power is restored");
+ lprintf(LOG_NOTICE, " previous : return to previous state when power is restored");
+ lprintf(LOG_NOTICE, " always-off : stay off after power is restored");
+ } else {
+ uint8_t ctl;
+ if (strncmp(argv[1], "list", 4) == 0)
+ ctl = IPMI_CHASSIS_POLICY_NO_CHANGE;
+ else if (strncmp(argv[1], "always-on", 9) == 0)
+ ctl = IPMI_CHASSIS_POLICY_ALWAYS_ON;
+ else if (strncmp(argv[1], "previous", 8) == 0)
+ ctl = IPMI_CHASSIS_POLICY_PREVIOUS;
+ else if (strncmp(argv[1], "always-off", 10) == 0)
+ ctl = IPMI_CHASSIS_POLICY_ALWAYS_OFF;
+ else {
+ lprintf(LOG_ERR, "Invalid chassis policy: %s", argv[1]);
+ return -1;
+ }
+ rc = ipmi_chassis_power_policy(intf, ctl);
+ }
+ }
+ else if (strncmp(argv[0], "bootparam", 9) == 0) {
+ if ((argc < 3) || (strncmp(argv[1], "help", 4) == 0)) {
+ lprintf(LOG_NOTICE, "bootparam get <param #>");
+ ipmi_chassis_set_bootflag_help();
+ }
+ else {
+ if (strncmp(argv[1], "get", 3) == 0) {
+ rc = ipmi_chassis_get_bootparam(intf, argv[2]);
+ }
+ else if (strncmp(argv[1], "set", 3) == 0) {
+ unsigned char set_flag=0;
+ unsigned char clr_flag=0;
+ if (strncmp(argv[2], "help", 4) == 0 ||
+ argc < 4 || (argc >= 4 &&
+ strncmp(argv[2], "bootflag", 8) != 0)) {
+ ipmi_chassis_set_bootflag_help();
+ } else {
+ if (argc == 5) {
+ get_bootparam_options(argv[4], &set_flag, &clr_flag);
+ }
+ rc = ipmi_chassis_set_bootdev(intf, argv[3], NULL);
+ if (argc == 5 && (set_flag != 0 || clr_flag != 0)) {
+ rc = ipmi_chassis_set_bootvalid(intf, set_flag, clr_flag);
+ }
+ }
+ }
+ else
+ lprintf(LOG_NOTICE, "bootparam get|set <option> [value ...]");
+ }
+ }
+ else if (strncmp(argv[0], "bootdev", 7) == 0) {
+ if ((argc < 2) || (strncmp(argv[1], "help", 4) == 0)) {
+ lprintf(LOG_NOTICE, "bootdev <device> [clear-cmos=yes|no]");
+ lprintf(LOG_NOTICE, "bootdev <device> [options=help,...]");
+ lprintf(LOG_NOTICE, " none : Do not change boot device order");
+ lprintf(LOG_NOTICE, " pxe : Force PXE boot");
+ lprintf(LOG_NOTICE, " disk : Force boot from default Hard-drive");
+ lprintf(LOG_NOTICE, " safe : Force boot from default Hard-drive, request Safe Mode");
+ lprintf(LOG_NOTICE, " diag : Force boot from Diagnostic Partition");
+ lprintf(LOG_NOTICE, " cdrom : Force boot from CD/DVD");
+ lprintf(LOG_NOTICE, " bios : Force boot into BIOS Setup");
+ lprintf(LOG_NOTICE, " floppy: Force boot from Floppy/primary removable media");
+ } else {
+ if (argc < 3)
+ rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
+ else if (strncmp(argv[2], "clear-cmos=", 11) == 0) {
+ if (strncmp(argv[2]+11, "yes", 3) == 0) {
+ uint8_t flags[5] = {0, (1<<7), 0, 0, 0};
+ rc = ipmi_chassis_set_bootdev(intf, argv[1], flags);
+ } else
+ rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
+ }
+ else if (strncmp(argv[2], "options=", 8) == 0) {
+ char *token;
+ char *saveptr = NULL;
+ int optionError = 0;
+ unsigned char flags[5];
+ static struct {
+ char *name;
+ int i;
+ unsigned char mask;
+ unsigned char value;
+ char *desc;
+ } options[] = {
+ /* data 1 */
+ {"valid", 0, (1<<7), (1<<7),
+ "Boot flags valid"},
+ {"persistent", 0, (1<<6), (1<<6),
+ "Changes are persistent for all future boots"},
+ {"efiboot", 0, (1<<5), (1<<5),
+ "Extensible Firmware Interface Boot (EFI)"},
+ /* data 2 */
+ {"clear-cmos", 1, (1<<7), (1<<7),
+ "CMOS clear"},
+ {"lockkbd", 1, (1<<6), (1<<6),
+ "Lock Keyboard"},
+ /* data2[5:2] is parsed elsewhere */
+ {"screenblank", 1, (1<<1), (1<<1),
+ "Screen Blank"},
+ {"lockoutreset", 1, (1<<0), (1<<0),
+ "Lock out Resetbuttons"},
+ /* data 3 */
+ {"lockout_power", 2, (1<<7), (1<<7),
+ "Lock out (power off/sleep request) via Power Button"},
+ {"verbose=default", 2, (3<<5), (0<<5),
+ "Request quiet BIOS display"},
+ {"verbose=no", 2, (3<<5), (1<<5),
+ "Request quiet BIOS display"},
+ {"verbose=yes", 2, (3<<5), (2<<5),
+ "Request verbose BIOS display"},
+ {"force_pet", 2, (1<<4), (1<<4),
+ "Force progress event traps"},
+ {"upw_bypass", 2, (1<<3), (1<<3),
+ "User password bypass"},
+ {"lockout_sleep", 2, (1<<2), (1<<2),
+ "Log Out Sleep Button"},
+ {"cons_redirect=default", 2, (3<<0), (0<<0),
+ "Console redirection occurs per BIOS configuration setting"},
+ {"cons_redirect=skip", 2, (3<<0), (1<<0),
+ "Suppress (skip) console redirection if enabled"},
+ {"cons_redirect=enable", 2, (3<<0), (2<<0),
+ "Suppress (skip) console redirection if enabled"},
+ /* data 4 */
+ /* data4[7:4] reserved */
+ /* data4[3] BIOS Shared Mode Override, not implemented here */
+ /* data4[2:0] BIOS Mux Control Override, not implemented here */
+
+ /* data5 reserved */
+
+ {NULL} /* End marker */
+ }, *op;
+
+ memset(&flags[0], 0, sizeof(flags));
+ token = strtok_r(argv[2] + 8, ",", &saveptr);
+ while (token != NULL) {
+ if (strcmp(token, "help") == 0) {
+ optionError = 1;
+ break;
+ }
+ for (op = options; op->name != NULL; ++op) {
+ if (strcmp(token, op->name) == 0) {
+ flags[op->i] &= op->mask;
+ flags[op->i] |= op->value;
+ break;
+ }
+ }
+ if (op->name == NULL) {
+ /* Option not found */
+ optionError = 1;
+ lprintf(LOG_ERR, "Invalid option: %s", token);
+ }
+ token = strtok_r(NULL, ",", &saveptr);
+ }
+ if (optionError) {
+ lprintf(LOG_NOTICE, "Legal options settings are:");
+ lprintf(LOG_NOTICE, "\thelp:\tprint this message");
+ for (op = options; op->name != NULL; ++op) {
+ lprintf(LOG_NOTICE, "\t%s:\t%s", op->name, op->desc);
+ }
+ return (-1);
+ }
+ rc = ipmi_chassis_set_bootdev(intf, argv[1], flags);
+ }
+ else
+ rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
+ }
+ }
+ else {
+ lprintf(LOG_ERR, "Invalid Chassis command: %s", argv[0]);
+ return -1;
+ }
+
+ return rc;
+}
diff --git a/lib/ipmi_dcmi.c b/lib/ipmi_dcmi.c
new file mode 100755
index 0000000..6e030f9
--- /dev/null
+++ b/lib/ipmi_dcmi.c
@@ -0,0 +1,2193 @@
+/*
+ * Copyright (C) 2008 Intel Corporation.
+ * All rights reserved
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Theory of operation
+ *
+ * DCMI is the Data Center Management Interface which is a subset of IPMI v2.0.
+ * DCMI incorporates the ability to locate a system with DCMI functionality,
+ * its available temperature sensors, and power limiting control.
+ *
+ * All of the available DCMI commands are contained in a struct with a numeric
+ * value and a string. When the user specifies a command the string is
+ * compared to one of several structs and is then given a numeric value based
+ * on the matched string. A case statement is used to select the desired
+ * action from the user. If an invalid string is entered, or a string that is
+ * not a command option is entered, the available commands are printed to the
+ * screen. This allows the strings to be changed quickly with the DCMI spec.
+ *
+ * Each called function usually executes whichever command was requested to
+ * keep the main() from being overly complicated.
+ *
+ * This code conforms to the 1.0 DCMI Specification
+ * released by Hari Ramachandran of the Intel Corporation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <time.h>
+#include <netdb.h>
+
+#include <ipmitool/ipmi_dcmi.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_entity.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/ipmi_sensor.h>
+
+#include "../src/plugins/lanplus/lanplus.h"
+
+#define IPMI_LAN_PORT 0x26f
+
+extern int verbose;
+
+static int ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id);
+
+/*******************************************************************************
+ * The structs below are the DCMI command option strings. They are printed *
+ * when the user does not issue enough options or the wrong ones. The reason *
+ * that the DMCI command strings are in a struct is so that when the *
+ * specification changes, the strings can be changed quickly with out having *
+ * to change a lot of the code in the main(). *
+ ******************************************************************************/
+
+/* Main set of DCMI commands */
+const struct dcmi_cmd dcmi_cmd_vals[] = {
+ { 0x00, "discover", " Used to discover supported DCMI capabilities" },
+ { 0x01, "power", " Platform power limit command options" },
+ { 0x02, "sensors", " Prints the available DCMI sensors" },
+ { 0x03, "asset_tag", " Prints the platform's asset tag" },
+ { 0x04, "set_asset_tag", " Sets the platform's asset tag" },
+ { 0x05, "get_mc_id_string", " Get management controller ID string" },
+ { 0x06, "set_mc_id_string", " Set management controller ID string" },
+ { 0x07, "thermalpolicy", " Thermal policy get/set" },
+ { 0x08, "get_temp_reading", " Get Temperature Readings" },
+ { 0x09, "get_conf_param", " Get DCMI Config Parameters" },
+ { 0x0A, "set_conf_param", " Set DCMI Config Parameters" },
+ { 0x0B, "oob_discover", " Ping/Pong Message for DCMI Discovery" },
+ { 0xFF, NULL, NULL }
+};
+
+/* get capabilites */
+const struct dcmi_cmd dcmi_capable_vals[] = {
+ { 0x01, "platform", " Lists the system capabilities" },
+ { 0x02, "mandatory_attributes", "Lists SEL, identification and"
+ "temperature attributes" },
+ { 0x03, "optional_attributes", " Lists power capabilities" },
+ { 0x04, "managebility access", " Lists OOB channel information" },
+ { 0xFF, NULL, NULL }
+};
+
+/* platform capabilities
+ * Since they are actually in two bytes, we need three structs to make this
+ * human readable...
+ */
+const struct dcmi_cmd dcmi_mandatory_platform_capabilities[] = {
+ { 0x01, "Identification support available", "" },
+ { 0x02, "SEL logging available", "" },
+ { 0x03, "Chassis power available", "" },
+ { 0x04, "Temperature monitor available", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* optional capabilities */
+const struct dcmi_cmd dcmi_optional_platform_capabilities[] = {
+ { 0x01, "Power management available", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* access capabilties */
+const struct dcmi_cmd dcmi_management_access_capabilities[] = {
+ { 0x01, "In-band KCS channel available", "" },
+ { 0x02, "Out-of-band serial TMODE available", "" },
+ { 0x03, "Out-of-band secondary LAN channel available", "" },
+ { 0x04, "Out-of-band primary LAN channel available", "" },
+ { 0x05, "SOL enabled", "" },
+ { 0x06, "VLAN capable", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* identification capabilities */
+const struct dcmi_cmd dcmi_id_capabilities_vals[] = {
+ { 0x01, "GUID", "" },
+ { 0x02, "DHCP hostname", "" },
+ { 0x03, "Asset tag", "" },
+ { 0xFF, NULL, NULL }
+};
+
+/* Configuration parameters*/
+const struct dcmi_cmd dcmi_conf_param_vals[] = {
+ { 0x01, "activate_dhcp", "\tActivate DHCP"},
+ { 0x02, "dhcp_config", "\tDHCP Configuration" },
+ { 0x03, "init", "\t\tInitial timeout interval" },
+ { 0x04, "timeout", "\t\tServer contact timeout interval" },
+ { 0x05, "retry", "\t\tServer contact retry interval" },
+ { 0xFF, NULL, NULL }
+};
+
+
+/* temperature monitoring capabilities */
+const struct dcmi_cmd dcmi_temp_monitoring_vals[] = {
+ { 0x01, "inlet", " Inlet air temperature sensors" },
+ { 0x02, "cpu", " CPU temperature sensors" },
+ { 0x03, "baseboard", "Baseboard temperature sensors" },
+ { 0xff, NULL, NULL }
+};
+
+/* These are not comands. These are the DCMI temp sensors and their numbers
+ * If new sensors are added, they need to be added to this list with their
+ * sensor number
+ */
+const struct dcmi_cmd dcmi_discvry_snsr_vals[] = {
+ { 0x40, "Inlet", " Inlet air temperature sensors" },
+ { 0x41, "CPU", " CPU temperature sensors" },
+ { 0x42, "Baseboard", "Baseboard temperature sensors" },
+ { 0xff, NULL, NULL }
+};
+
+/* Temperature Readings */
+const struct dcmi_cmd dcmi_temp_read_vals[] = {
+ { 0x40, "Inlet", "Inlet air temperature(40h) " },
+ { 0x41, "CPU", "CPU temperature sensors(41h) " },
+ { 0x42, "Baseboard", "Baseboard temperature sensors(42h) " },
+ { 0xff, NULL, NULL }
+};
+
+/* power management/control commands */
+const struct dcmi_cmd dcmi_pwrmgmt_vals[] = {
+ { 0x00, "reading", " Get power related readings from the system" },
+ { 0x01, "get_limit", " Get the configured power limits" },
+ { 0x02, "set_limit", " Set a power limit option" },
+ { 0x03, "activate", " Activate the set power limit" },
+ { 0x04, "deactivate", "Deactivate the set power limit" },
+ { 0xFF, NULL, NULL }
+};
+
+/* set power limit commands */
+const struct dcmi_cmd dcmi_pwrmgmt_set_usage_vals[] = {
+ { 0x00, "action", " <no_action | sel_logging | power_off>" },
+ { 0x01, "limit", " <number in Watts>" },
+ { 0x02, "correction", "<number in milliseconds>" },
+ { 0x03, "sample", " <number in seconds>" },
+ { 0xFF, NULL, NULL }
+};
+
+/* power management/get action commands */
+const struct dcmi_cmd dcmi_pwrmgmt_get_action_vals[] = {
+ { 0x00, "No Action", ""},
+ { 0x01, "Hard Power Off & Log Event to SEL", ""},
+
+ { 0x02, "OEM reserved (02h)", ""},
+ { 0x03, "OEM reserved (03h)", ""},
+ { 0x04, "OEM reserved (04h)", ""},
+ { 0x05, "OEM reserved (05h)", ""},
+ { 0x06, "OEM reserved (06h)", ""},
+ { 0x07, "OEM reserved (07h)", ""},
+ { 0x08, "OEM reserved (08h)", ""},
+ { 0x09, "OEM reserved (09h)", ""},
+ { 0x0a, "OEM reserved (0ah)", ""},
+ { 0x0b, "OEM reserved (0bh)", ""},
+ { 0x0c, "OEM reserved (0ch)", ""},
+ { 0x0d, "OEM reserved (0dh)", ""},
+ { 0x0e, "OEM reserved (0eh)", ""},
+ { 0x0f, "OEM reserved (0fh)", ""},
+ { 0x10, "OEM reserved (10h)", ""},
+
+ { 0x11, "Log Event to SEL", ""},
+ { 0xFF, NULL, NULL }
+};
+
+/* power management/set action commands */
+const struct dcmi_cmd dcmi_pwrmgmt_action_vals[] = {
+ { 0x00, "no_action", "No Action"},
+ { 0x01, "power_off", "Hard Power Off & Log Event to SEL"},
+ { 0x11, "sel_logging", "Log Event to SEL"},
+
+ { 0x02, "oem_02", "OEM reserved (02h)"},
+ { 0x03, "oem_03", "OEM reserved (03h)"},
+ { 0x04, "oem_04", "OEM reserved (04h)"},
+ { 0x05, "oem_05", "OEM reserved (05h)"},
+ { 0x06, "oem_06", "OEM reserved (06h)"},
+ { 0x07, "oem_07", "OEM reserved (07h)"},
+ { 0x08, "oem_08", "OEM reserved (08h)"},
+ { 0x09, "oem_09", "OEM reserved (09h)"},
+ { 0x0a, "oem_0a", "OEM reserved (0ah)"},
+ { 0x0b, "oem_0b", "OEM reserved (0bh)"},
+ { 0x0c, "oem_0c", "OEM reserved (0ch)"},
+ { 0x0d, "oem_0d", "OEM reserved (0dh)"},
+ { 0x0e, "oem_0e", "OEM reserved (0eh)"},
+ { 0x0f, "oem_0f", "OEM reserved (0fh)"},
+ { 0x10, "oem_10", "OEM reserved (10h)"},
+
+ { 0xFF, NULL, NULL }
+};
+
+/* thermal policy action commands */
+const struct dcmi_cmd dcmi_thermalpolicy_vals[] = {
+ { 0x00, "get", "Get thermal policy" },
+ { 0x01, "set", "Set thermal policy" },
+ { 0xFF, NULL, NULL }
+};
+
+/* thermal policy action commands */
+const struct dcmi_cmd dcmi_confparameters_vals[] = {
+ { 0x00, "get", "Get configuration parameters" },
+ { 0x01, "set", "Set configuration parameters" },
+ { 0xFF, NULL, NULL }
+};
+
+/* entityIDs used in thermap policy */
+const struct dcmi_cmd dcmi_thermalpolicy_set_parameters_vals[] = {
+ { 0x00, "volatile", " Current Power Cycle" },
+ { 0x01, "nonvolatile", "Set across power cycles" },
+ { 0x01, "poweroff", " Hard Power Off system" },
+ { 0x00, "nopoweroff", " No 'Hard Power Off' action" },
+ { 0x01, "sel", " Log event to SEL" },
+ { 0x00, "nosel", " No 'Log event to SEL' action" },
+ { 0x00, "disabled", " Disabled" },
+ { 0x00, NULL, NULL }
+};
+
+
+/* DCMI command specific completion code results per 1.0 spec
+ * 80h - parameter not supported.
+ * 81h - attempt to set the ‘set in progress’ value (in parameter #0) when not
+ * in the ‘set complete’ state. (This completion code provides a way to
+ * recognize that another party has already ‘claimed’ the parameters)
+ * 82h - attempt to write read-only parameter
+ * 82h - set not supported on selected channel (e.g. channel is session-less.)
+ * 83h - access mode not supported
+ * 84h – Power Limit out of range
+ * 85h – Correction Time out of range
+ * 89h – Statistics Reporting Period out of range
+ */
+const struct valstr dcmi_ccode_vals[] = {
+ { 0x80, "Parameter not supported" },
+ { 0x81, "Something else has already claimed these parameters" },
+ { 0x82, "Not supported or failed to write a read-only parameter" },
+ { 0x83, "Access mode is not supported" },
+ { 0x84, "Power/Thermal limit out of range" },
+ { 0x85, "Correction/Exception time out of range" },
+ { 0x89, "Sample/Statistics Reporting period out of range" },
+ { 0x8A, "Power limit already active" },
+ { 0xFF, NULL }
+};
+
+/* End strings */
+
+/* This was taken from print_valstr() from helper.c. It serves the same
+ * purpose but with out the extra formatting. This function simply prints
+ * the dcmi_cmd struct provided. verthorz specifies to print vertically or
+ * horizontally. If the string is printed horizontally then a | will be
+ * printed between each instance of vs[i].str until it is NULL
+ *
+ * @vs: value string list to print
+ * @title: name of this value string list
+ * @loglevel: what log level to print, -1 for stdout
+ * @verthorz: printed vertically or horizontally, 0 or 1
+ */
+void
+print_strs(const struct dcmi_cmd * vs, const char * title, int loglevel,
+ int verthorz)
+{
+ int i;
+
+ if (vs == NULL)
+ return;
+
+ if (title != NULL) {
+ if (loglevel < 0)
+ printf("\n%s\n", title);
+ else
+ lprintf(loglevel, "\n%s", title);
+ }
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (loglevel < 0) {
+ if (vs[i].val < 256)
+ if (verthorz == 0)
+ printf(" %s %s\n", vs[i].str, vs[i].desc);
+ else
+ printf("%s", vs[i].str);
+ else if (verthorz == 0)
+ printf(" %s %s\n", vs[i].str, vs[i].desc);
+ else
+ printf("%s", vs[i].str);
+ } else {
+ if (vs[i].val < 256)
+ lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc);
+ else
+ lprintf(loglevel, " %s %s", vs[i].str, vs[i].desc);
+ }
+ /* Check to see if this is NOT the last element in vs.str if true
+ * print the | else don't print anything.
+ */
+ if ((verthorz == 1) && (vs[i+1].str != NULL))
+ printf(" | ");
+ }
+ if (verthorz == 0) {
+ if (loglevel < 0) {
+ printf("\n");
+ } else {
+ lprintf(loglevel, "");
+ }
+ }
+}
+
+/* This was taken from str2val() from helper.c. It serves the same
+ * purpose but with the addition of a desc field from the structure.
+ * This function converts the str from the dcmi_cmd struct provided to the
+ * value associated to the compared string in the struct.
+ *
+ * @str: string to compare against
+ * @vs: dcmi_cmd structure
+ */
+uint16_t
+str2val2(const char *str, const struct dcmi_cmd *vs)
+{
+ int i;
+ if (vs == NULL || str == NULL) {
+ return 0;
+ }
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (strncasecmp(vs[i].str, str,
+ __maxlen(str, vs[i].str)) == 0) {
+ return vs[i].val;
+ }
+ }
+ return vs[i].val;
+}
+
+/* This was taken from val2str() from helper.c. It serves the same
+ * purpose but with the addition of a desc field from the structure.
+ * This function converts the val and returns a string from the dcmi_cmd
+ * struct provided in the struct.
+ *
+ * @val: value to compare against
+ * @vs: dcmi_cmd structure
+ */
+const char *
+val2str2(uint16_t val, const struct dcmi_cmd *vs)
+{
+ static char un_str[32];
+ int i;
+
+ if (vs == NULL)
+ return NULL;
+
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (vs[i].val == val)
+ return vs[i].str;
+ }
+ memset(un_str, 0, 32);
+ snprintf(un_str, 32, "Unknown (0x%x)", val);
+ return un_str;
+}
+
+/* check the DCMI response from the BMC
+ * @rsp: Response data structure
+ */
+static int
+chk_rsp(struct ipmi_rs * rsp)
+{
+ /* if the response from the intf is NULL then the BMC is experiencing
+ * some issue and cannot complete the command
+ */
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "\n Unable to get DCMI information");
+ return 1;
+ }
+ /* if the completion code is greater than zero there was an error. We'll
+ * use val2str from helper.c to print the error from either the DCMI
+ * completion code struct or the generic IPMI completion_code_vals struct
+ */
+ if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0x8F)) {
+ lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)",
+ val2str(rsp->ccode, dcmi_ccode_vals), rsp->ccode);
+ return 1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "\n DCMI request failed because: %s (%x)",
+ val2str(rsp->ccode, completion_code_vals), rsp->ccode);
+ return 1;
+ }
+ /* check to make sure this is a DCMI firmware */
+ if(rsp->data[0] != IPMI_DCMI) {
+ printf("\n A valid DCMI command was not returned! (%x)", rsp->data[0]);
+ return 1;
+ }
+ return 0;
+}
+
+/* Get capabilities ipmi response
+ *
+ * This function returns the available capabilities of the platform.
+ * The reason it returns in the rsp struct is so that it can be used for other
+ * purposes.
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ * @selector: Parameter selector
+ */
+struct ipmi_rs *
+ipmi_dcmi_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[2]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = selector;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.0 spec */
+ req.msg.cmd = IPMI_DCMI_COMPAT; /* 0x01 per 1.0 spec */
+ req.msg.data = msg_data; /* 0xDC 0x01 or the msg_data above */
+ req.msg.data_len = 2; /* How many times does req.msg.data need to read */
+
+ return intf->sendrecv(intf, &req);
+}
+/* end capabilities struct */
+
+/* Displays capabilities from structure
+ * returns void
+ *
+ * @cmd: dcmi_cmd structure
+ * @data_val: holds value of what to display
+ */
+void
+display_capabilities_attributes(const struct dcmi_cmd *cmd, uint8_t data_val)
+{
+ uint8_t i;
+ for (i = 0x01; cmd[i-1].val != 0xFF; i++) {
+ if (data_val & (1<<(i-1))) {
+ printf(" %s\n", val2str2(i, cmd));
+ }
+ }
+}
+
+static int
+ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf)
+{
+# ifndef IPMI_INTF_LANPLUS
+ lprintf(LOG_ERR,
+ "DCMI Discovery is available only when LANplus(IPMI v2.0) is enabled.");
+ return (-1);
+# else
+ int rc;
+ struct ipmi_session *s;
+
+ if (intf->opened == 0 && intf->open != NULL) {
+ if (intf->open(intf) < 0)
+ return (-1);
+ }
+ if (intf == NULL || intf->session == NULL)
+ return -1;
+
+ s = intf->session;
+
+ if (s->port == 0)
+ s->port = IPMI_LAN_PORT;
+ if (s->privlvl == 0)
+ s->privlvl = IPMI_SESSION_PRIV_ADMIN;
+ if (s->timeout == 0)
+ s->timeout = IPMI_LAN_TIMEOUT;
+ if (s->retry == 0)
+ s->retry = IPMI_LAN_RETRY;
+
+ if (s->hostname == NULL || strlen((const char *)s->hostname) == 0) {
+ lprintf(LOG_ERR, "No hostname specified!");
+ return -1;
+ }
+
+ intf->abort = 1;
+ intf->session->sol_data.sequence_number = 1;
+
+ if (ipmi_intf_socket_connect (intf) == -1) {
+ lprintf(LOG_ERR, "Could not open socket!");
+ return -1;
+ }
+
+ if (intf->fd < 0) {
+ lperror(LOG_ERR, "Connect to %s failed",
+ s->hostname);
+ intf->close(intf);
+ return -1;
+ }
+
+ intf->opened = 1;
+
+ /* Lets ping/pong */
+ return ipmiv2_lan_ping(intf);
+# endif
+}
+
+/* This is the get DCMI Capabilities function to see what the BMC supports.
+ *
+ * returns 0 with out error -1 with any errors
+ *
+ * @intf: ipmi interface handler
+ * @selector: selection parameter
+ */
+static int
+ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
+{
+ uint8_t i;
+ uint8_t bit_shifter = 0;
+ struct capabilities cape;
+ struct ipmi_rs * rsp;
+ rsp = ipmi_dcmi_getcapabilities(intf, selector);
+
+ if(chk_rsp(rsp))
+ return -1;
+
+ /* if there were no errors, the command worked! */
+ memcpy(&cape, rsp->data, sizeof (cape));
+ /* check to make sure that this is a 1.0/1.1/1.5 command */
+ if ((cape.conformance != IPMI_DCMI_CONFORM)
+ && (cape.conformance != IPMI_DCMI_1_1_CONFORM)
+ && (cape.conformance != IPMI_DCMI_1_5_CONFORM)) {
+ lprintf(LOG_ERR,
+ "ERROR! This command is not available on this platform");
+ return -1;
+ }
+ /* check to make sure that this is a rev .01 or .02 */
+ if (cape.revision != 0x01 && cape.revision != 0x02) {
+ lprintf(LOG_ERR,
+ "ERROR! This command is not compatible with this version");
+ return -1;
+ }
+ /* 0x01 - platform capabilities
+ * 0x02 - Manageability Access Capabilities
+ * 0x03 - SEL Capability
+ * 0x04 - Identification Capability
+ * 0x05 - LAN Out-Of-Band Capability
+ * 0x06 - Serial Out-Of-Band TMODE Capability
+ */
+ switch (selector) {
+ case 0x01:
+ printf(" Supported DCMI capabilities:\n");
+ /* loop through each of the entries in the first byte from the
+ * struct
+ */
+ printf("\n Mandatory platform capabilties\n");
+ display_capabilities_attributes(
+ dcmi_mandatory_platform_capabilities, cape.data_byte1);
+ /* loop through each of the entries in the second byte from the
+ * struct
+ */
+ printf("\n Optional platform capabilties\n");
+ display_capabilities_attributes(
+ dcmi_optional_platform_capabilities, cape.data_byte2);
+ /* loop through each of the entries in the third byte from the
+ * struct
+ */
+ printf("\n Managebility access capabilties\n");
+ display_capabilities_attributes(
+ dcmi_management_access_capabilities, cape.data_byte3);
+ break;
+ case 0x02:
+ printf("\n Mandatory platform attributes:\n");
+ /* byte 1 & 2 data */
+ printf("\n SEL Attributes: ");
+ printf("\n SEL automatic rollover is ");
+ /* mask the 2nd byte of the data response with 10000000b or 0x80
+ * because of the endian-ness the 15th bit is in the second byte
+ */
+ if ((cape.data_byte2 & 0x80))
+ printf("enabled");
+ else
+ printf("not present");
+ /* since the number of SEL entries is split across the two data
+ * bytes we will need to bit shift and append them together again
+ */
+ /* cast cape.data_byte1 as 16 bits */
+ uint16_t sel_entries = (uint16_t)cape.data_byte1;
+ /* or sel_entries with byte 2 and shift it 8 places */
+ sel_entries |= (uint16_t)cape.data_byte2 << 8;
+ printf("\n %d SEL entries\n", sel_entries & 0xFFF);
+ /* byte 3 data */
+ printf("\n Identification Attributes: \n");
+ display_capabilities_attributes(
+ dcmi_id_capabilities_vals, cape.data_byte3);
+ /* byte 4 data */
+ printf("\n Temperature Monitoring Attributes: \n");
+ display_capabilities_attributes(dcmi_temp_monitoring_vals,
+ cape.data_byte4);
+ break;
+ case 0x03:
+ printf("\n Optional Platform Attributes: \n");
+ /* Power Management */
+ printf("\n Power Management:\n");
+ if (cape.data_byte1 == 0x40) {
+ printf(" Slave address of device: 20h (BMC)\n" );
+ } else {
+ printf(" Slave address of device: %xh (8bits)"
+ "(Satellite/External controller)\n",
+ cape.data_byte1);
+ }
+ /* Controller channel number (4-7) bits */
+ if ((cape.data_byte2>>4) == 0x00) {
+ printf(" Channel number is 0h (Primary BMC)\n");
+ } else {
+ printf(" Channel number is %xh \n",
+ (cape.data_byte2>>4));
+ }
+ /* Device revision (0-3) */
+ printf(" Device revision is %d \n",
+ cape.data_byte2 &0xf);
+ break;
+ case 0x04:
+ /* LAN */
+ printf("\n Manageability Access Attributes: \n");
+ if (cape.data_byte1 == 0xFF) {
+ printf(" Primary LAN channel is not available for OOB\n");
+ } else {
+ printf(" Primary LAN channel number: %d is available\n",
+ cape.data_byte1);
+ }
+ if (cape.data_byte2 == 0xFF) {
+ printf(" Secondary LAN channel is not available for OOB\n");
+ } else {
+ printf(" Secondary LAN channel number: %d is available\n",
+ cape.data_byte2);
+ }
+ /* serial */
+ if (cape.data_byte3 == 0xFF) {
+ printf(" No serial channel is available\n");
+ } else {
+ printf(" Serial channel number: %d is available\n",
+ cape.data_byte3);
+ }
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+ /* return intf->sendrecv(intf, &req); */
+}
+
+/* This is the get asset tag command. This checks the length of the asset tag
+ * with the first read, then reads n number of bytes thereafter to get the
+ * complete asset tag.
+ *
+ * @intf: ipmi interface handler
+ * @offset: where to start reading the asset tag
+ * @length: how much to read
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_getassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_GETASSET; /* 0x01 per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ req.msg.data_len = 3; /* How many times does req.msg.data need to read */
+ return intf->sendrecv(intf, &req);
+}
+
+/* This is the get asset tag command. The function first checks to see if the
+ * platform is capable of getting the asset tag by calling the getcapabilities
+ * function and checking the response. Then it checks the length of the asset
+ * tag with the first read, then x number of reads thereafter to get the asset
+ * complete asset tag then print it.
+ *
+ * @intf: ipmi interface handler
+ *
+ * returns 0 if no failure, -1 with a failure
+ */
+static int
+ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+ /* now let's get the asset tag length */
+ rsp = ipmi_dcmi_getassettag(intf, 0, 0);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ taglength = rsp->data[1];
+ printf("\n Asset tag: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ rsp = ipmi_dcmi_getassettag(intf, offset, getlength);
+ /* macro has no effect here where can generate sig segv
+ * if rsp occurs with null
+ */
+ if (rsp != NULL) {
+ GOOD_ASSET_TAG_CCODE(rsp->ccode);
+ }
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", rsp->data[i+2]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* This is the set asset tag command. This checks the length of the asset tag
+ * with the first read, then reads n number of bytes thereafter to set the
+ * complete asset tag.
+ *
+ * @intf: ipmi interface handler
+ * @offset: offset to write
+ * @length: number of bytes to write (16 bytes maximum)
+ * @data: data to write
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_setassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
+ uint8_t *data)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_SETASSET; /* 0x08 per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ /* How many times does req.msg.data need to read */
+ req.msg.data_len = length + 3;
+ memcpy(req.msg.data + 3, data, length);
+
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf, uint8_t * data)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+
+ /* now let's get the asset tag length */
+ taglength = strlen(data);
+ if (taglength > 64){
+ lprintf(LOG_ERR, "\nValue is too long.");
+ return -1;
+ }
+ printf("\n Set Asset Tag: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ memcpy(tmpData, data + offset, getlength);
+ rsp = ipmi_dcmi_setassettag(intf, offset, getlength, tmpData);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", tmpData[i]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Management Controller Identifier String is provided in order to accommodate
+ * the requirement for the management controllers to identify themselves.
+ *
+ * @intf: ipmi interface handler
+ * @offset: offset to read
+ * @length: number of bytes to read (16 bytes maximum)
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_GETMNGCTRLIDS; /* 0x09 per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ /* How many times does req.msg.data need to read */
+ req.msg.data_len = 3;
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+
+ /* now let's get the asset tag length */
+ rsp = ipmi_dcmi_getmngctrlids(intf, 0, 1);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+
+ taglength = rsp->data[1];
+
+ printf("\n Get Management Controller Identifier String: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ rsp = ipmi_dcmi_getmngctrlids(intf, offset, getlength);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", rsp->data[i+2]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Management Controller Identifier String is provided in order to accommodate
+ * the requirement for the management controllers to identify themselves.
+ *
+ * @intf: ipmi interface handler
+ * @offset: offset to write
+ * @length: number of bytes to write (16 bytes maximum)
+ * @data: data to write
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
+ uint8_t *data)
+{
+ struct ipmi_rq req; /* request data to send to the BMC */
+ uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = offset; /* offset 0 */
+ msg_data[2] = length; /* read one byte */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
+ req.msg.cmd = IPMI_DCMI_SETMNGCTRLIDS; /* 0x0A per 1.1 spec */
+ req.msg.data = msg_data; /* msg_data above */
+ /* How many times does req.msg.data need to read */
+ req.msg.data_len = 3 + length;
+ memcpy(req.msg.data + 3, data, length);
+
+ return intf->sendrecv(intf, &req);
+}
+
+/* Set Asset Tag command provides ability for the management console to set the
+ * asset tag as appropriate. Management controller is not responsible for the
+ * data format used for the Asset Tag once modified by IPDC.
+ *
+ * @intf: ipmi interface handler
+ *
+ * returns 0 if no failure, -1 with a failure
+ */
+static int
+ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf, uint8_t * data)
+{
+ uint8_t data_byte2;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
+ uint8_t taglength = 0;
+ uint8_t getlength = 0;
+ uint8_t offset = 0;
+ uint8_t i;
+
+ data += '\0';
+ taglength = strlen(data) +1;
+
+ if (taglength > 64) {
+ lprintf(LOG_ERR, "\nValue is too long.");
+ return -1;
+ }
+
+ printf("\n Set Management Controller Identifier String Command: ");
+ while (taglength) {
+ getlength = taglength / DCMI_MAX_BYTE_SIZE ?
+ DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
+ memcpy(tmpData, data + offset, getlength);
+ rsp = ipmi_dcmi_setmngctrlids(intf, offset, getlength, tmpData);
+ /* because after call "Set mc id string" RMCP+ will go down
+ * we have no "rsp"
+ */
+ if (strncmp(intf->name, "lanplus", 7)) {
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ }
+ for (i=0; i<getlength; i++) {
+ printf("%c", tmpData[i]);
+ }
+ offset += getlength;
+ taglength -= getlength;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Issues a discovery command to see what sensors are available on the target.
+ * system.
+ *
+ * @intf: ipmi interface handler
+ * @isnsr: entity ID
+ * @offset: offset (Entity instace start)
+ *
+ * returns ipmi_rs structure
+ */
+struct ipmi_rs *
+ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr, uint8_t offset)
+{
+ struct ipmi_rq req; /* ipmi request struct */
+ uint8_t msg_data[5]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x01; /* Senser Type = Temp (01h) */
+ msg_data[2] = isnsr; /* Sensor Number */
+ msg_data[3] = 0x00; /* Entity Instance, set to read all instances */
+ msg_data[4] = offset; /* Entity instace start */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETSNSR;
+ req.msg.data = msg_data; /* Contents above */
+ req.msg.data_len = 5; /* how many times does req.msg.data need to read */
+
+ return intf->sendrecv(intf, &req);
+}
+
+/* DCMI sensor discovery
+ * Uses the dcmi_discvry_snsr_vals struct to print its string and
+ * uses the numeric values to request the sensor sdr record id.
+ *
+ * @intf: ipmi interface handler
+ * @isnsr: entity ID
+ * @ient: sensor entity id
+ */
+static int
+ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr)
+{
+ int i = 0;
+ struct ipmi_rs * rsp; /* ipmi response */
+ uint8_t records = 0;
+ int8_t instances = 0;
+ uint8_t offset = 0;
+ uint16_t record_id = 0;
+ uint8_t id_buff[16]; /* enough for 8 record IDs */
+ rsp = ipmi_dcmi_discvry_snsr(intf, isnsr, 0);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ instances = rsp->data[1];
+ printf("\n%s: %d temperature sensor%s found:\n",
+ val2str2(isnsr, dcmi_discvry_snsr_vals),
+ instances,
+ (instances > 1) ? "s" : "");
+ while(instances > 0) {
+ ipmi_dcmi_discvry_snsr(intf, isnsr, offset);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ records = rsp->data[2];
+ /* cache the data since it may be destroyed by subsequent
+ * ipmi_xxx calls
+ */
+ memcpy(id_buff, &rsp->data[3], 16);
+ for (i=0; i<records; i++) {
+ /* Record ID is in little endian format */
+ record_id = (id_buff[2*i + 1] << 8) + id_buff[2*i];
+ printf("Record ID 0x%04x: ", record_id);
+ ipmi_print_sensor_info(intf, record_id);
+ }
+ offset += 8;
+ instances -= records;
+ }
+ return 0;
+}
+/* end sensor discovery */
+
+/* Power Management get power reading
+ *
+ * @intf: ipmi interface handler
+ */
+static int
+ipmi_dcmi_pwr_rd(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct power_reading val;
+ struct tm tm_t;
+ time_t t;
+ uint8_t msg_data[4]; /* number of request data bytes */
+ memset(&tm_t, 0, sizeof(tm_t));
+ memset(&t, 0, sizeof(t));
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x01; /* Mode Power Status */
+ msg_data[2] = 0x00; /* reserved */
+ msg_data[3] = 0x00; /* reserved */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETRED; /* Get power reading */
+ req.msg.data = msg_data; /* msg_data above */
+ req.msg.data_len = 4; /* how many times does req.msg.data need to read */
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
+ memcpy(&val, rsp->data, sizeof (val));
+ t = val.time_stamp;
+ gmtime_r(&t, &tm_t);
+ printf("\n");
+ printf(" Instantaneous power reading: %8d Watts\n",
+ val.curr_pwr);
+ printf(" Minimum during sampling period: %8d Watts\n",
+ val.min_sample);
+ printf(" Maximum during sampling period: %8d Watts\n",
+ val.max_sample);
+ printf(" Average power reading over sample period: %8d Watts\n",
+ val.avg_pwr);
+ printf(" IPMI timestamp: %s",
+ asctime(&tm_t));
+ printf(" Sampling period: %08d Milliseconds\n",
+ val.sample);
+ printf(" Power reading state is: ");
+ /* mask the rsp->data so that we only care about bit 6 */
+ if((val.state & 0x40) == 0x40) {
+ printf("activated");
+ } else {
+ printf("deactivated");
+ }
+ printf("\n\n");
+ return 0;
+}
+/* end Power Management get reading */
+
+
+/* This is the get thermalpolicy command.
+ *
+ * @intf: ipmi interface handler
+ */
+int
+ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf, uint8_t entityID,
+ uint8_t entityInstance)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct thermal_limit val;
+ uint8_t msg_data[3]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
+ msg_data[2] = entityInstance; /* Entity Instance */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETTERMALLIMIT; /* Get thermal policy reading */
+ req.msg.data = msg_data; /* msg_data above */
+ req.msg.data_len = 3; /* how many times does req.msg.data need to read */
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ memcpy(&val, rsp->data, sizeof (val));
+ printf("\n");
+ printf(" Persistance flag is: %s\n",
+ ((val.exceptionActions & 0x80) ? "set" : "notset"));
+ printf(" Exception Actions, taken if the Temperature Limit exceeded:\n");
+ printf(" Hard Power Off system and log event: %s\n",
+ ((val.exceptionActions & 0x40) ? "active":"inactive"));
+ printf(" Log event to SEL only: %s\n",
+ ((val.exceptionActions & 0x20) ? "active":"inactive"));
+ printf(" Temperature Limit %d degrees\n",
+ val.tempLimit);
+ printf(" Exception Time %d seconds\n",
+ val.exceptionTime);
+ printf("\n\n");
+ return 0;
+}
+
+/* This is the set thermalpolicy command.
+ *
+ * @intf: ipmi interface handler
+ */
+int
+ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf,
+ uint8_t entityID,
+ uint8_t entityInst,
+ uint8_t persistanceFlag,
+ uint8_t actionHardPowerOff,
+ uint8_t actionLogToSEL,
+ uint8_t tempLimit,
+ uint8_t samplingTimeLSB,
+ uint8_t samplingTimeMSB)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[7]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
+ msg_data[2] = entityInst; /* Entity Instance */
+ /* persistance and actions or disabled if no actions */
+ msg_data[3] = (((persistanceFlag ? 1 : 0) << 7) |
+ ((actionHardPowerOff? 1 : 0) << 6) |
+ ((actionLogToSEL ? 1 : 0) << 5));
+ msg_data[4] = tempLimit;
+ msg_data[5] = samplingTimeLSB;
+ msg_data[6] = samplingTimeMSB;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ /* Get thermal policy reading */
+ req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT;
+ req.msg.data = msg_data; /* msg_data above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 7;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ printf("\nThermal policy %d for %0Xh entity successfully set.\n\n",
+ entityInst, entityID);
+ return 0;
+}
+
+/* This is Get Temperature Readings Command
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs *
+ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf,
+ uint8_t entityID,
+ uint8_t entityInst,
+ uint8_t entityInstStart)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[5]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x01; /* Sensor type */
+ msg_data[2] = entityID; /* Entity Instance */
+ msg_data[3] = entityInst;
+ msg_data[4] = entityInstStart;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETTEMPRED; /* Get thermal policy reading */
+ req.msg.data = msg_data; /* msg_data above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 5;
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ int i,j, tota_inst, get_inst, offset = 0;
+ /* Print sensor description */
+ printf("\n\tEntity ID\t\t\tEntity Instance\t Temp. Readings");
+ for (i = 0; dcmi_temp_read_vals[i].str != NULL; i++) {
+ /* get all of the information about this sensor */
+ rsp = ipmi_dcmi_get_temp_readings(intf,
+ dcmi_temp_read_vals[i].val, 0, 0);
+ if (chk_rsp(rsp)) {
+ continue;
+ }
+ /* Total number of available instances for the Entity ID */
+ offset = 0;
+ tota_inst = rsp->data[1];
+ while (tota_inst > 0) {
+ get_inst = ((tota_inst / DCMI_MAX_BYTE_TEMP_READ_SIZE) ?
+ DCMI_MAX_BYTE_TEMP_READ_SIZE :
+ (tota_inst % DCMI_MAX_BYTE_TEMP_READ_SIZE));
+ rsp = ipmi_dcmi_get_temp_readings(intf,
+ dcmi_temp_read_vals[i].val, offset, 0);
+ if (chk_rsp(rsp)) {
+ continue;
+ }
+ /* Number of sets of Temperature Data in this
+ * response (Max 8 per response)
+ */
+ for (j=0; j < rsp->data[2]*2; j=j+2) {
+ /* Print Instance temperature info */
+ printf("\n%s",dcmi_temp_read_vals[i].desc);
+ printf("\t\t%i\t\t%c%i C", rsp->data[j+4],
+ ((rsp->data[j+3]) >> 7) ?
+ '-' : '+', (rsp->data[j+3] & 127));
+ }
+ offset += get_inst;
+ tota_inst -= get_inst;
+ }
+ }
+ return 0;
+}
+
+/* This is Get DCMI Config Parameters Command
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs *
+ipmi_dcmi_getconfparam(struct ipmi_intf * intf, int param_selector)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[3]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = param_selector; /* Parameter selector */
+ /* Set Selector. Selects a given set of parameters under a given Parameter
+ * selector value. 00h if parameter doesn't use a Set Selector.
+ */
+ msg_data[2] = 0x00;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETCONFPARAM; /* Get DCMI Config Parameters */
+ req.msg.data = msg_data; /* Contents above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 3;
+ return intf->sendrecv(intf, &req);
+}
+
+static int
+ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ const int dcmi_conf_params = 5;
+ int param_selector;
+ uint16_t tmp_value = 0;
+ /* We are not interested in parameter 1 which always will return 0 */
+ for (param_selector = 2 ; param_selector <= dcmi_conf_params;
+ param_selector++) {
+ rsp = ipmi_dcmi_getconfparam(intf, param_selector);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* Time to print what we have got */
+ switch(param_selector) {
+ case 2:
+ tmp_value = (rsp->data[4])& 1;
+ printf("\n\tDHCP Discovery method\t: ");
+ printf("\n\t\tManagement Controller ID String is %s",
+ tmp_value ? "enabled" : "disabled");
+ printf("\n\t\tVendor class identifier DCMI IANA and Vendor class-specific Informationa are %s",
+ ((rsp->data[4])& 2) ? "enabled" : "disabled" );
+ break;
+ case 3:
+ printf("\n\tInitial timeout interval\t: %i seconds",
+ rsp->data[4]);
+ break;
+ case 4:
+ printf("\n\tServer contact timeout interval\t: %i seconds",
+ rsp->data[4] + (rsp->data[5]<<8));
+ break;
+ case 5:
+ printf("\n\tServer contact retry interval\t: %i seconds",
+ rsp->data[4] + (rsp->data[5] << 8));
+ break;
+ default:
+ printf("\n\tConfiguration Parameter not supported.");
+ }
+ }
+ return 0;
+}
+
+/* This is Set DCMI Config Parameters Command
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs *
+ipmi_dcmi_setconfparam(struct ipmi_intf * intf, uint8_t param_selector,
+ uint16_t value)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[5]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = param_selector; /* Parameter selector */
+ /* Set Selector (use 00h for parameters that only have one set). */
+ msg_data[2] = 0x00;
+
+ if (param_selector > 3) {
+ /* One bite more */
+ msg_data[3] = value & 0xFF;
+ msg_data[4] = value >> 8;
+ } else {
+ msg_data[3] = value;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_SETCONFPARAM; /* Set DCMI Config Parameters */
+ req.msg.data = msg_data; /* Contents above */
+ if (param_selector > 3) {
+ /* One bite more */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 5;
+ } else {
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 4;
+ }
+ return intf->sendrecv(intf, &req);
+}
+
+/* Power Management get limit ipmi response
+ *
+ * This function returns the currently set power management settings as an
+ * ipmi response structure. The reason it returns in the rsp struct is so
+ * that it can be used in the set limit [slimit()] function to populate
+ * un-changed or un-edited values.
+ *
+ * returns ipmi response structure
+ *
+ * @intf: ipmi interface handler
+ */
+struct ipmi_rs * ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf)
+{
+ struct ipmi_rq req;
+ uint8_t msg_data[3]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = 0x00; /* reserved */
+ msg_data[2] = 0x00; /* reserved */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_GETLMT; /* Get power limit */
+ req.msg.data = msg_data; /* Contents above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 3;
+
+ return intf->sendrecv(intf, &req);
+}
+/* end Power Management get limit response */
+
+/* Power Management print the get limit command
+ *
+ * This function calls the get limit function that returns an ipmi response.
+ *
+ * returns 0 else 1 with error
+ * @intf: ipmi interface handler
+ */
+static int
+ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct power_limit val;
+ uint8_t realCc = 0xff;
+
+ rsp = ipmi_dcmi_pwr_glimit(intf);
+ /* rsp can be a null so check response before any operation
+ * on it to avoid sig segv
+ */
+ if (rsp != NULL) {
+ realCc = rsp->ccode;
+ GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
+ }
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ /* rsp->data[0] is equal to response data byte 2 in spec */
+ /* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
+ memcpy(&val, rsp->data, sizeof (val));
+ printf("\n Current Limit State: %s\n",
+ (realCc == 0) ?
+ "Power Limit Active" : "No Active Power Limit");
+ printf(" Exception actions: %s\n",
+ val2str2(val.action, dcmi_pwrmgmt_get_action_vals));
+ printf(" Power Limit: %i Watts\n", val.limit);
+ printf(" Correction time: %i milliseconds\n", val.correction);
+ printf(" Sampling period: %i seconds\n", val.sample);
+ printf("\n");
+ return 0;
+}
+/* end print get limit */
+
+/* Power Management set limit
+ *
+ * Undocumented bounds:
+ * Power limit: 0 - 0xFFFF
+ * Correction period 5750ms to 28751ms or 0x1676 to 0x704F
+ * sample period: 3 sec to 65 sec and 69+
+ *
+ * @intf: ipmi interface handler
+ * @option: Power option to change
+ * @value: Value of the desired change
+ */
+static int
+ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf, const char * option,
+ const char * value)
+{
+ struct ipmi_rs * rsp; /* ipmi response */
+ struct ipmi_rq req; /* ipmi request (to send) */
+ struct power_limit val;
+ uint8_t msg_data[15]; /* number of request data bytes */
+ uint32_t lvalue = 0;
+ int i;
+
+ rsp = ipmi_dcmi_pwr_glimit(intf); /* get the power limit settings */
+# if 0
+ {
+ unsigned char counter = 0;
+ printf("DATA (%d): ", rsp->data_len);
+ for(counter = 0; counter < rsp->data_len; counter ++) {
+ printf("%02X ", rsp->data[counter]);
+ }
+ printf("\n");
+ }
+# endif
+ /* rsp can be a null so check response before any operation on it to
+ * avoid sig segv
+ */
+ if (rsp != NULL) {
+ GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
+ }
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ memcpy(&val, rsp->data, sizeof (val));
+ /* same as above; sets the values of the val struct
+ * DCMI group ID *
+ * val.grp_id = rsp->data[0];
+ * exception action *
+ * val.action = rsp->data[3]; *
+ *
+ * power limit in Watts *
+ * store 16 bits of the rsp from the 4th entity *
+ * val.limit = *(uint16_t*)(&rsp->data[4]);
+ * correction period in mS *
+ * store 32 bits of the rsp from the 6th entity *
+ * val.correction = *(uint32_t*)(&rsp->data[6]);
+ * store 16 bits of the rsp from the 12th entity *
+ * sample period in seconds *
+ * val.sample = *(uint16_t*)(&rsp->data[12]);
+ */
+ lprintf(LOG_INFO,
+ "DCMI IN Limit=%d Correction=%d Action=%d Sample=%d\n",
+ val.limit, val.correction, val.action, val.sample);
+ switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) {
+ case 0x00:
+ /* action */
+ switch (str2val2(value, dcmi_pwrmgmt_action_vals)) {
+ case 0x00:
+ /* no_action */
+ val.action = 0;
+ break;
+ case 0x01:
+ /* power_off */
+ val.action = 1;
+ break;
+ case 0x02:
+ /* OEM reserved action */
+ val.action = 0x02;
+ break;
+ case 0x03:
+ /* OEM reserved action */
+ val.action = 0x03;
+ break;
+ case 0x04:
+ /* OEM reserved action */
+ val.action = 0x04;
+ break;
+ case 0x05:
+ /* OEM reserved action */
+ val.action = 0x05;
+ break;
+ case 0x06:
+ /* OEM reserved action */
+ val.action = 0x06;
+ break;
+ case 0x07:
+ /* OEM reserved action */
+ val.action = 0x07;
+ break;
+ case 0x08:
+ /* OEM reserved action */
+ val.action = 0x08;
+ break;
+ case 0x09:
+ /* OEM reserved action */
+ val.action = 0x09;
+ break;
+ case 0x0a:
+ /* OEM reserved action */
+ val.action = 0x0a;
+ break;
+ case 0x0b:
+ /* OEM reserved action */
+ val.action = 0x0b;
+ break;
+ case 0x0c:
+ /* OEM reserved action */
+ val.action = 0x0c;
+ break;
+ case 0x0d:
+ /* OEM reserved action */
+ val.action = 0x0d;
+ break;
+ case 0x0e:
+ /* OEM reserved action */
+ val.action = 0x0e;
+ break;
+ case 0x0f:
+ /* OEM reserved action */
+ val.action = 0x0f;
+ break;
+ case 0x10:
+ /* OEM reserved action */
+ val.action = 0x10;
+ break;
+ case 0x11:
+ /* sel_logging*/
+ val.action = 0x11;
+ break;
+ case 0xFF:
+ /* error - not a string we knew what to do with */
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return -1;
+ }
+ break;
+ case 0x01:
+ /* limit */
+ if (str2uint(value, &lvalue) != 0) {
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return (-1);
+ }
+ val.limit = *(uint16_t*)(&lvalue);
+ break;
+ case 0x02:
+ /* correction */
+ if (str2uint(value, &lvalue) != 0) {
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return (-1);
+ }
+ val.correction = *(uint32_t*)(&lvalue);
+ break;
+ case 0x03:
+ /* sample */
+ if (str2uint(value, &lvalue) != 0) {
+ lprintf(LOG_ERR, "Given %s '%s' is invalid.",
+ option, value);
+ return (-1);
+ }
+ val.sample = *(uint16_t*)(&lvalue);
+ break;
+ case 0xff:
+ /* no valid options */
+ return -1;
+ }
+ lprintf(LOG_INFO, "DCMI OUT Limit=%d Correction=%d Action=%d Sample=%d\n", val.limit, val.correction, val.action, val.sample);
+
+ msg_data[0] = val.grp_id; /* Group Extension Identification */
+ msg_data[1] = 0x00; /* reserved */
+ msg_data[2] = 0x00; /* reserved */
+ msg_data[3] = 0x00; /* reserved */
+ msg_data[4] = val.action; /* exception action; 0x00 disables it */
+
+ /* fill msg_data[5] with the first 16 bits of val.limit */
+ *(uint16_t*)(&msg_data[5]) = val.limit;
+ /* msg_data[5] = 0xFF;
+ * msg_data[6] = 0xFF;
+ */
+ /* fill msg_data[7] with the first 32 bits of val.correction */
+ *(uint32_t*)(&msg_data[7]) = val.correction;
+ /* msg_data[7] = 0x76;
+ * msg_data[8] = 0x16;
+ * msg_data[9] = 0x00;
+ * msg_data[10] = 0x00;
+ */
+ msg_data[11] = 0x00; /* reserved */
+ msg_data[12] = 0x00; /* reserved */
+ /* fill msg_data[7] with the first 16 bits of val.sample */
+ *(uint16_t*)(&msg_data[13]) = val.sample;
+ /* msg_data[13] = 0x03; */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
+ req.msg.data = msg_data; /* Contents above */
+ /* how many times does req.msg.data need to read */
+ req.msg.data_len = 15;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ return 0;
+}
+/* end Power Management set limit */
+
+/* Power Management activate deactivate
+ *
+ * @intf: ipmi interface handler
+ * @option: uint8_t - 0 to deactivate or 1 to activate
+ */
+static int
+ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf, uint8_t option)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[4]; /* number of request data bytes */
+
+ msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
+ msg_data[1] = option; /* 0 = Deactivate 1 = Activate */
+ msg_data[2] = 0x00; /* reserved */
+ msg_data[3] = 0x00; /* reserved */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.cmd = IPMI_DCMI_PWRACT; /* Act-deactivate power limit */
+ req.msg.data = msg_data; /* Contents above */
+ req.msg.data_len = 4; /* how mant times does req.msg.data need to read */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ printf("\n Power limit successfully ");
+ if (option == 0x00) {
+ printf("deactivated");
+ } else {
+ printf("activated");
+ }
+ printf("\n");
+ return 0;
+}
+/* end power management activate/deactivate */
+
+/* main
+ *
+ * @intf: dcmi interface handler
+ * @argc: argument count
+ * @argv: argument vector
+ */
+int
+ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char **argv)
+{
+ int rc = 0;
+ uint8_t ctl = 0;
+ int i, ii, instances;
+ struct ipmi_rs *rsp;
+
+ if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ }
+ /* start the cmd requested */
+ switch (str2val2(argv[0], dcmi_cmd_vals)) {
+ case 0x00:
+ /* discover capabilities*/
+ for (i = 1; dcmi_capable_vals[i-1].str != NULL; i++) {
+ if (ipmi_dcmi_prnt_getcapabilities(intf, i) < 0) {
+ printf("Error discovering %s capabilities!\n",
+ val2str2(i, dcmi_capable_vals));
+ return -1;
+ }
+ }
+ break;
+ case 0x01:
+ /* power */
+ argv++;
+ if (argv[0] == NULL) {
+ print_strs(dcmi_pwrmgmt_vals, "power <command>",
+ -1, 0);
+ return -1;
+ }
+ /* power management */
+ switch (str2val2(argv[0], dcmi_pwrmgmt_vals)) {
+ case 0x00:
+ /* get reading */
+ rc = ipmi_dcmi_pwr_rd(intf);
+ break;
+ case 0x01:
+ /* get limit */
+ /* because the get limit function is also used to
+ * populate unchanged values for the set limit
+ * command it returns an ipmi response structure
+ */
+ rc = ipmi_dcmi_pwr_prnt_glimit(intf);
+ break;
+ case 0x02:
+ /* set limit */
+ if (argc < 4) {
+ print_strs(dcmi_pwrmgmt_set_usage_vals,
+ "set_limit <parameter> <value>",
+ -1, 0);
+ return -1;
+ }
+ if ( argc == 10) {
+ /* Let`s initialize dcmi power parameters */
+ struct ipmi_rq req;
+ uint8_t data[256];
+ uint16_t sample = 0;
+ uint16_t limit = 0;
+ uint32_t correction = 0;
+
+ memset(data, 0, sizeof(data));
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_DCGRP;
+ req.msg.lun = 0x00;
+ req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
+ req.msg.data = data; /* Contents above */
+ req.msg.data_len = 15;
+
+ data[0] = IPMI_DCMI; /* Group Extension Identification */
+ data[1] = 0x0; /* reserved */
+ data[2] = 0x0; /* reserved */
+ data[3] = 0x0; /* reserved */
+
+ /* action */
+ switch (str2val2(argv[2], dcmi_pwrmgmt_action_vals)) {
+ case 0x00:
+ /* no_action */
+ data[4] = 0x00;
+ break;
+ case 0x01:
+ /* power_off */
+ data[4] = 0x01;
+ break;
+ case 0x11:
+ /* sel_logging*/
+ data[4] = 0x11;
+ break;
+ case 0xFF:
+ /* error - not a string we knew what to do with */
+ lprintf(LOG_ERR, "Given Action '%s' is invalid.",
+ argv[2]);
+ return -1;
+ }
+ /* limit */
+ if (str2ushort(argv[4], &limit) != 0) {
+ lprintf(LOG_ERR,
+ "Given Limit '%s' is invalid.",
+ argv[4]);
+ return (-1);
+ }
+ data[5] = limit >> 0;
+ data[6] = limit >> 8;
+ /* correction */
+ if (str2uint(argv[6], &correction) != 0) {
+ lprintf(LOG_ERR,
+ "Given Correction '%s' is invalid.",
+ argv[6]);
+ return (-1);
+ }
+ data[7] = correction >> 0;
+ data[8] = correction >> 8;
+ data[9] = correction >> 16;
+ data[10] = correction >> 24;
+ data[11] = 0x00; /* reserved */
+ data[12] = 0x00; /* reserved */
+ /* sample */
+ if (str2ushort(argv[8], &sample) != 0) {
+ lprintf(LOG_ERR,
+ "Given Sample '%s' is invalid.",
+ argv[8]);
+ return (-1);
+ }
+ data[13] = sample >> 0;
+ data[14] = sample >> 8;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (chk_rsp(rsp)) {
+ return -1;
+ }
+ } else {
+ /* loop through each parameter and value until we have neither */
+ while ((argv[1] != NULL) && (argv[2] != NULL)) {
+ rc = ipmi_dcmi_pwr_slimit(intf, argv[1], argv[2]);
+ /* catch any error that the set limit function returned */
+ if (rc > 0) {
+ print_strs(dcmi_pwrmgmt_set_usage_vals,
+ "set_limit <parameter> <value>", -1, 0);
+ return -1;
+ }
+ /* the first argument is the command and the second is the
+ * value. Move argv two places; what is now 3 will be 1
+ */
+ argv+=2;
+ }
+ }
+ rc = ipmi_dcmi_pwr_prnt_glimit(intf);
+ break;
+ case 0x03:
+ /* activate */
+ rc = ipmi_dcmi_pwr_actdeact(intf, 1);
+ break;
+ case 0x04:
+ /* deactivate */
+ rc = ipmi_dcmi_pwr_actdeact(intf, 0);
+ break;
+ default:
+ /* no valid options */
+ print_strs(dcmi_pwrmgmt_vals,
+ "power <command>", -1, 0);
+ break;
+ }
+ /* power mgmt end */
+ break;
+ /* end power command */
+ case 0x02:
+ /* sensor print */
+ /* Look for each item in the dcmi_discvry_snsr_vals struct
+ * and if it exists, print the sdr record id(s) for it.
+ * Use the val from each one as the sensor number.
+ */
+ for (i = 0; dcmi_discvry_snsr_vals[i].str != NULL; i++) {
+ /* get all of the information about this sensor */
+ rc = ipmi_dcmi_prnt_discvry_snsr(intf,
+ dcmi_discvry_snsr_vals[i].val);
+ }
+ break;
+ /* end sensor print */
+ case 0x03:
+ /* asset tag */
+ if(ipmi_dcmi_prnt_getassettag(intf) < 0) {
+ lprintf(LOG_ERR, "Error getting asset tag!");
+ return -1;
+ }
+ break;
+ /* end asset tag */
+ case 0x04:
+ {
+ /* set asset tag */
+ if (argc == 1 ) {
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ }
+ if (ipmi_dcmi_prnt_setassettag(intf, argv[1]) < 0) {
+ lprintf(LOG_ERR, "\nError setting asset tag!");
+ return -1;
+ }
+ break;
+ }
+ /* end set asset tag */
+ case 0x05:
+ /* get management controller identifier string */
+ if (ipmi_dcmi_prnt_getmngctrlids(intf) < 0) {
+ lprintf(LOG_ERR,
+ "Error getting management controller identifier string!");
+ return -1;
+ }
+ break;
+ /* end get management controller identifier string */
+ case 0x06:
+ {
+ /* set management controller identifier string */
+ if (argc == 1 ) {
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ }
+ if (ipmi_dcmi_prnt_setmngctrlids(intf, argv[1]) < 0) {
+ lprintf(LOG_ERR,
+ "Error setting management controller identifier string!");
+ return -1;
+ }
+ break;
+ }
+ /* end set management controller identifier string */
+ case 0x07:
+ {
+ uint8_t entityID = 0;
+ uint8_t entityInst = 0;
+ uint8_t persistanceFlag;
+ uint8_t actionHardPowerOff;
+ uint8_t actionLogToSEL;
+ uint8_t tempLimit = 0;
+ uint8_t samplingTimeLSB;
+ uint8_t samplingTimeMSB;
+ uint16_t samplingTime = 0;
+ /* Thermal policy get/set */
+ /* dcmitool dcmi thermalpolicy get */
+ switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) {
+ case 0x00:
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "Get <entityID> <instanceID>");
+ return -1;
+ }
+ if (str2uchar(argv[2], &entityID) != 0) {
+ lprintf(LOG_ERR,
+ "Given Entity ID '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ if (str2uchar(argv[3], &entityInst) != 0) {
+ lprintf(LOG_ERR,
+ "Given Instance ID '%s' is invalid.",
+ argv[3]);
+ return (-1);
+ }
+ rc = ipmi_dcmi_getthermalpolicy(intf, entityID, entityInst);
+ break;
+ case 0x01:
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "Set <entityID> <instanceID>");
+ return -1;
+ } else if (argc < 9) {
+ print_strs(dcmi_thermalpolicy_set_parameters_vals,
+ "Set thermalpolicy instance parameters: "
+ "<volatile/nonvolatile/disabled> "
+ "<poweroff/nopoweroff/disabled> "
+ "<sel/nosel/disabled> <templimitByte> <exceptionTime>",
+ -1, 0);
+ return -1;
+ }
+ if (str2uchar(argv[2], &entityID) != 0) {
+ lprintf(LOG_ERR,
+ "Given Entity ID '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ if (str2uchar(argv[3], &entityInst) != 0) {
+ lprintf(LOG_ERR,
+ "Given Instance ID '%s' is invalid.",
+ argv[3]);
+ return (-1);
+ }
+ persistanceFlag = (uint8_t) str2val2(argv[4], dcmi_thermalpolicy_set_parameters_vals);
+ actionHardPowerOff = (uint8_t) str2val2(argv[5], dcmi_thermalpolicy_set_parameters_vals);
+ actionLogToSEL = (uint8_t) str2val2(argv[6], dcmi_thermalpolicy_set_parameters_vals);
+ if (str2uchar(argv[7], &tempLimit) != 0) {
+ lprintf(LOG_ERR,
+ "Given Temp Limit '%s' is invalid.",
+ argv[7]);
+ return (-1);
+ }
+ if (str2ushort(argv[8], &samplingTime) != 0) {
+ lprintf(LOG_ERR,
+ "Given Sampling Time '%s' is invalid.",
+ argv[8]);
+ return (-1);
+ }
+ samplingTimeLSB = (samplingTime & 0xFF);
+ samplingTimeMSB = ((samplingTime & 0xFF00) >> 8);
+
+ rc = ipmi_dcmi_setthermalpolicy(intf,
+ entityID,
+ entityInst,
+ persistanceFlag,
+ actionHardPowerOff,
+ actionLogToSEL,
+ tempLimit,
+ samplingTimeLSB,
+ samplingTimeMSB);
+
+ break;
+ default:
+ print_strs(dcmi_thermalpolicy_vals,
+ "thermalpolicy <command>",
+ -1, 0);
+ return -1;
+ }
+ break;
+ }
+ case 0x08:
+ if(ipmi_dcmi_prnt_get_temp_readings(intf) < 0 ) {
+ lprintf(LOG_ERR,
+ "Error get temperature readings!");
+ }
+ break;
+ case 0x09:
+ if(ipmi_dcmi_prnt_getconfparam(intf) < 0 ) {
+ lprintf(LOG_ERR,
+ "Error Get DCMI Configuration Parameters!");
+ };
+ break;
+ case 0x0A:
+ {
+ switch (argc) {
+ case 2:
+ if (strncmp(argv[1], "activate_dhcp", 13) != 0) {
+ print_strs( dcmi_conf_param_vals,
+ "DCMI Configuration Parameters",
+ -1, 0);
+ return -1;
+ }
+ break;
+ default:
+ if (argc != 3 || strncmp(argv[1], "help", 4) == 0) {
+ print_strs(dcmi_conf_param_vals,
+ "DCMI Configuration Parameters",
+ -1, 0);
+ return -1;
+ }
+ }
+ if (strncmp(argv[1], "activate_dhcp", 13) == 0) {
+ rsp = ipmi_dcmi_setconfparam(intf, 1, 1);
+ } else {
+ uint16_t tmp_val = 0;
+ if (str2ushort(argv[2], &tmp_val) != 0) {
+ lprintf(LOG_ERR,
+ "Given %s '%s' is invalid.",
+ argv[1], argv[2]);
+ return (-1);
+ }
+ rsp = ipmi_dcmi_setconfparam(intf,
+ str2val2(argv[1], dcmi_conf_param_vals),
+ tmp_val);
+ }
+ if (chk_rsp(rsp)) {
+ lprintf(LOG_ERR,
+ "Error Set DCMI Configuration Parameters!");
+ }
+ break;
+ }
+ case 0x0B:
+ {
+ if (intf->session == NULL) {
+ lprintf(LOG_ERR,
+ "\nOOB discovery is available only via RMCP interface.");
+ return -1;
+ }
+ if(ipmi_dcmi_prnt_oobDiscover(intf) < 0) {
+ lprintf(LOG_ERR, "\nOOB discovering capabilities failed.");
+ return -1;
+ }
+ break;
+ }
+ default:
+ /* couldn't detect what the user entered */
+ print_strs(dcmi_cmd_vals,
+ "Data Center Management Interface commands",
+ -1, 0);
+ return -1;
+ break;
+ }
+ printf("\n");
+ return 0;
+}
+
+/* Display DCMI sensor information
+ * Uses the ipmi_sdr_get_next_header to read SDR header and compare to the
+ * target Record ID. Then either ipmi_sensor_print_full or
+ * ipmi_sensor_print_compact is called to print the data
+ *
+ * @intf: ipmi interface handler
+ * @rec_id: target Record ID
+ */
+static int
+ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id)
+{
+ struct sdr_get_rs *header;
+ struct ipmi_sdr_iterator *itr;
+ int rc = 0;
+ uint8_t *rec = NULL;
+
+ itr = ipmi_sdr_start(intf, 0);
+ if (itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return (-1);
+ }
+
+ while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
+ if (header->id == rec_id) {
+ break;
+ }
+ }
+ if (header == NULL) {
+ lprintf(LOG_DEBUG, "header == NULL");
+ ipmi_sdr_end(intf, itr);
+ return (-1);
+ }
+ /* yes, we found the SDR for this record ID, now get full record */
+ rec = ipmi_sdr_get_record(intf, header, itr);
+ if (rec == NULL) {
+ lprintf(LOG_DEBUG, "rec == NULL");
+ ipmi_sdr_end(intf, itr);
+ return (-1);
+ }
+ if ((header->type == SDR_RECORD_TYPE_FULL_SENSOR) ||
+ (header->type == SDR_RECORD_TYPE_COMPACT_SENSOR)) {
+ rc = ipmi_sdr_print_rawentry(intf, header->type,
+ rec, header->length);
+ } else {
+ rc = (-1);
+ }
+ free(rec);
+ rec = NULL;
+ ipmi_sdr_end(intf, itr);
+ return rc;
+}
diff --git a/lib/ipmi_delloem.c b/lib/ipmi_delloem.c
new file mode 100644
index 0000000..e190cd4
--- /dev/null
+++ b/lib/ipmi_delloem.c
@@ -0,0 +1,4225 @@
+/*
+ * Copyright (c) 2008, Dell Inc
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of Dell Inc nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Thursday Oct 7 17:30:12 2009
+ * <deepaganesh_paulraj@dell.com>
+ *
+ * This code implements a dell OEM proprietary commands.
+ * This Code is edited and Implemented the License feature for Delloem
+ * Author Harsha S <Harsha_S1@dell.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include <limits.h>
+#include <time.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_delloem.h>
+#include <ipmitool/ipmi_fru.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_sensor.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/bswap.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_entity.h>
+#include <ipmitool/ipmi_fru.h>
+#include <ipmitool/ipmi_sensor.h>
+
+#define DELL_OEM_NETFN (uint8_t)(0x30)
+#define GET_IDRAC_VIRTUAL_MAC (uint8_t)(0xC9)
+/* 11g Support Macros */
+#define INVALID (-1)
+#define SHARED 0
+#define SHARED_WITH_FAILOVER_LOM2 1
+#define DEDICATED 2
+#define SHARED_WITH_FAILOVER_ALL_LOMS 3
+/* 11g Support Macros */
+#define SHARED 0
+#define SHARED_WITH_FAILOVER_LOM2 1
+#define DEDICATED 2
+#define SHARED_WITH_FAILOVER_ALL_LOMS 3
+/* 12g Support Strings for nic selection */
+#define INVAILD_FAILOVER_MODE -2
+#define INVAILD_FAILOVER_MODE_SETTINGS -3
+#define INVAILD_SHARED_MODE -4
+
+#define INVAILD_FAILOVER_MODE_STRING "ERROR: Cannot set shared with failover lom same as current shared lom."
+#define INVAILD_FAILOVER_MODE_SET "ERROR: Cannot set shared with failover loms when NIC is set to dedicated Mode."
+#define INVAILD_SHARED_MODE_SET_STRING "ERROR: Cannot set shared Mode for Blades."
+
+char AciveLOM_String [6] [10] = {
+ "None",
+ "LOM1",
+ "LOM2",
+ "LOM3",
+ "LOM4",
+ "dedicated"
+};
+/* 11g Support Strings for nic selection */
+char NIC_Selection_Mode_String [4] [50] = {
+ "shared",
+ "shared with failover lom2",
+ "dedicated",
+ "shared with Failover all loms"
+};
+
+char NIC_Selection_Mode_String_12g[] [50] = {
+ "dedicated",
+ "shared with lom1",
+ "shared with lom2",
+ "shared with lom3",
+ "shared with lom4",
+ "shared with failover lom1",
+ "shared with failover lom2",
+ "shared with failover lom3",
+ "shared with failover lom4",
+ "shared with failover all loms"
+};
+
+const struct vFlashstr vFlash_completion_code_vals[] = {
+ {0x00, "SUCCESS"},
+ {0x01, "NO_SD_CARD"},
+ {0x63, "UNKNOWN_ERROR"},
+ {0x00, NULL}
+};
+
+static int current_arg =0;
+uint8_t iDRAC_FLAG=0;
+LCD_MODE lcd_mode;
+static uint8_t LcdSupported=0;
+static uint8_t SetLEDSupported=0;
+
+volatile uint8_t IMC_Type = IMC_IDRAC_10G;
+
+POWER_HEADROOM powerheadroom;
+
+uint8_t PowercapSetable_flag=0;
+uint8_t PowercapstatusFlag=0;
+
+static void usage(void);
+/* LCD Function prototypes */
+static int ipmi_delloem_lcd_main(struct ipmi_intf *intf, int argc,
+ char **argv);
+int ipmi_lcd_get_platform_model_name(struct ipmi_intf *intf, char *lcdstring,
+ uint8_t max_length, uint8_t field_type);
+static int ipmi_idracvalidator_command(struct ipmi_intf *intf);
+static int ipmi_lcd_get_configure_command_wh(struct ipmi_intf *intf);
+static int ipmi_lcd_get_configure_command(struct ipmi_intf *intf,
+ uint8_t *command);
+static int ipmi_lcd_set_configure_command(struct ipmi_intf *intf, int command);
+static int ipmi_lcd_set_configure_command_wh(struct ipmi_intf *intf, uint32_t mode,
+ uint16_t lcdquallifier,uint8_t errordisp);
+static int ipmi_lcd_get_single_line_text(struct ipmi_intf *intf,
+ char *lcdstring, uint8_t max_length);
+static int ipmi_lcd_get_info_wh(struct ipmi_intf *intf);
+static int ipmi_lcd_get_info(struct ipmi_intf *intf);
+static int ipmi_lcd_get_status_val(struct ipmi_intf *intf,
+ LCD_STATUS *lcdstatus);
+static int IsLCDSupported();
+static void CheckLCDSupport(struct ipmi_intf *intf);
+static void ipmi_lcd_status_print(LCD_STATUS lcdstatus);
+static int ipmi_lcd_get_status(struct ipmi_intf *intf);
+static int ipmi_lcd_set_kvm(struct ipmi_intf *intf, char status);
+static int ipmi_lcd_set_lock(struct ipmi_intf *intf, char lock);
+static int ipmi_lcd_set_single_line_text(struct ipmi_intf *intf, char *text);
+static int ipmi_lcd_set_text(struct ipmi_intf *intf, char *text,
+ int line_number);
+static int ipmi_lcd_configure_wh(struct ipmi_intf *intf, uint32_t mode,
+ uint16_t lcdquallifier, uint8_t errordisp, int8_t line_number, char *text);
+static int ipmi_lcd_configure(struct ipmi_intf *intf, int command,
+ int8_t line_number, char *text);
+static void ipmi_lcd_usage(void);
+/* MAC Function prototypes */
+static int ipmi_delloem_mac_main(struct ipmi_intf *intf, int argc, char **argv);
+static void InitEmbeddedNICMacAddressValues();
+static int ipmi_macinfo_drac_idrac_virtual_mac(struct ipmi_intf *intf,
+ uint8_t NicNum);
+static int ipmi_macinfo_drac_idrac_mac(struct ipmi_intf *intf,uint8_t NicNum);
+static int ipmi_macinfo_10g(struct ipmi_intf *intf, uint8_t NicNum);
+static int ipmi_macinfo_11g(struct ipmi_intf *intf, uint8_t NicNum);
+static int ipmi_macinfo(struct ipmi_intf *intf, uint8_t NicNum);
+static void ipmi_mac_usage(void);
+/* LAN Function prototypes */
+static int ipmi_delloem_lan_main(struct ipmi_intf *intf, int argc, char **argv);
+static int IsLANSupported();
+static int get_nic_selection_mode(int current_arg, char **argv);
+static int ipmi_lan_set_nic_selection(struct ipmi_intf *intf,
+ uint8_t nic_selection);
+static int ipmi_lan_get_nic_selection(struct ipmi_intf *intf);
+static int ipmi_lan_get_active_nic(struct ipmi_intf *intf);
+static void ipmi_lan_usage(void);
+static int ipmi_lan_set_nic_selection_12g(struct ipmi_intf *intf,
+ uint8_t *nic_selection);
+/* Power monitor Function prototypes */
+static int ipmi_delloem_powermonitor_main(struct ipmi_intf *intf, int argc,
+ char **argv);
+static void ipmi_time_to_str(time_t rawTime, char *strTime);
+static int ipmi_get_sensor_reading(struct ipmi_intf *intf,
+ unsigned char sensorNumber, SensorReadingType *pSensorReadingData);
+static int ipmi_get_power_capstatus_command(struct ipmi_intf *intf);
+static int ipmi_set_power_capstatus_command(struct ipmi_intf *intf,
+ uint8_t val);
+static int ipmi_powermgmt(struct ipmi_intf *intf);
+static int ipmi_powermgmt_clear(struct ipmi_intf *intf, uint8_t clearValue);
+static uint64_t watt_to_btuphr_conversion(uint32_t powerinwatt);
+static uint32_t btuphr_to_watt_conversion(uint64_t powerinbtuphr);
+static int ipmi_get_power_headroom_command(struct ipmi_intf *intf, uint8_t unit);
+static int ipmi_get_power_consumption_data(struct ipmi_intf *intf, uint8_t unit);
+static int ipmi_get_instan_power_consmpt_data(struct ipmi_intf *intf,
+ IPMI_INST_POWER_CONSUMPTION_DATA *instpowerconsumptiondata);
+static void ipmi_print_get_instan_power_Amps_data(
+ IPMI_INST_POWER_CONSUMPTION_DATA instpowerconsumptiondata);
+static int ipmi_print_get_power_consmpt_data(struct ipmi_intf *intf,
+ uint8_t unit);
+static int ipmi_get_avgpower_consmpt_history(struct ipmi_intf *intf,
+ IPMI_AVGPOWER_CONSUMP_HISTORY *pavgpower);
+static int ipmi_get_peakpower_consmpt_history(struct ipmi_intf *intf,
+ IPMI_POWER_CONSUMP_HISTORY *pstPeakpower);
+static int ipmi_get_minpower_consmpt_history(struct ipmi_intf *intf,
+ IPMI_POWER_CONSUMP_HISTORY *pstMinpower);
+static int ipmi_print_power_consmpt_history(struct ipmi_intf *intf, int unit);
+static int ipmi_get_power_cap(struct ipmi_intf *intf,
+ IPMI_POWER_CAP *ipmipowercap);
+static int ipmi_print_power_cap(struct ipmi_intf *intf, uint8_t unit);
+static int ipmi_set_power_cap(struct ipmi_intf *intf, int unit, int val);
+static void ipmi_powermonitor_usage(void);
+/* vFlash Function prototypes */
+static int ipmi_delloem_vFlash_main(struct ipmi_intf *intf, int argc,
+ char **argv);
+const char *get_vFlash_compcode_str(uint8_t vflashcompcode,
+ const struct vFlashstr *vs);
+static int ipmi_get_sd_card_info(struct ipmi_intf *intf);
+static int ipmi_delloem_vFlash_process(struct ipmi_intf *intf, int current_arg,
+ char **argv);
+static void ipmi_vFlash_usage(void);
+/* LED Function prototypes */
+static int ipmi_getsesmask(int, char **argv);
+static void CheckSetLEDSupport(struct ipmi_intf *intf);
+static int IsSetLEDSupported(void);
+static void ipmi_setled_usage(void);
+static int ipmi_delloem_setled_main(struct ipmi_intf *intf, int argc,
+ char **argv);
+static int ipmi_setled_state(struct ipmi_intf *intf, int bayId, int slotId,
+ int state);
+static int ipmi_getdrivemap(struct ipmi_intf *intf, int b, int d, int f,
+ int *bayId, int *slotId);
+
+/* Function Name: ipmi_delloem_main
+ *
+ * Description: This function processes the delloem command
+ * Input: intf - ipmi interface
+ * argc - no of arguments
+ * argv - argument string array
+ * Output:
+ *
+ * Return: return code 0 - success
+ * -1 - failure
+ */
+int
+ipmi_delloem_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ current_arg = 0;
+ if (argc == 0 || strncmp(argv[0], "help\0", 5) == 0) {
+ usage();
+ return 0;
+ }
+ if (0 ==strncmp(argv[current_arg], "lcd\0", 4)) {
+ ipmi_delloem_lcd_main(intf,argc,argv);
+ } else if (strncmp(argv[current_arg], "mac\0", 4) == 0) {
+ /* mac address*/
+ ipmi_delloem_mac_main(intf,argc,argv);
+ } else if (strncmp(argv[current_arg], "lan\0", 4) == 0) {
+ /* lan address*/
+ ipmi_delloem_lan_main(intf,argc,argv);
+ } else if (strncmp(argv[current_arg], "setled\0", 7) == 0) {
+ /* SetLED support */
+ ipmi_delloem_setled_main(intf,argc,argv);
+ } else if (strncmp(argv[current_arg], "powermonitor\0", 13) == 0) {
+ /*Powermanagement report processing*/
+ ipmi_delloem_powermonitor_main(intf,argc,argv);
+ } else if (strncmp(argv[current_arg], "vFlash\0", 7) == 0) {
+ /* vFlash Support */
+ ipmi_delloem_vFlash_main(intf,argc,argv);
+ } else {
+ usage();
+ return -1;
+ }
+ return rc;
+}
+/*
+ * Function Name: usage
+ *
+ * Description: This function prints help message for delloem command
+ * Input:
+ * Output:
+ *
+ * Return:
+ *
+ */
+static void
+usage(void)
+{
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"usage: delloem <command> [option...]");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"commands:");
+ lprintf(LOG_NOTICE,
+" lcd");
+ lprintf(LOG_NOTICE,
+" mac");
+ lprintf(LOG_NOTICE,
+" lan");
+ lprintf(LOG_NOTICE,
+" setled");
+ lprintf(LOG_NOTICE,
+" powermonitor");
+ lprintf(LOG_NOTICE,
+" vFlash");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"For help on individual commands type:");
+ lprintf(LOG_NOTICE,
+"delloem <command> help");
+}
+/*
+ * Function Name: ipmi_delloem_lcd_main
+ *
+ * Description: This function processes the delloem lcd command
+ * Input: intf - ipmi interface
+ * argc - no of arguments
+ * argv - argument string array
+ * Output:
+ *
+ * Return: return code 0 - success
+ * -1 - failure
+ *
+ */
+static int
+ipmi_delloem_lcd_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ current_arg++;
+ if (argc < current_arg) {
+ usage();
+ return -1;
+ }
+ /* ipmitool delloem lcd info*/
+ if (argc == 1 || strcmp(argv[current_arg], "help") == 0) {
+ ipmi_lcd_usage();
+ return 0;
+ }
+ CheckLCDSupport(intf);
+ ipmi_idracvalidator_command(intf);
+ if (!IsLCDSupported()) {
+ lprintf(LOG_ERR, "lcd is not supported on this system.");
+ return -1;
+ } else if (strncmp(argv[current_arg], "info\0", 5) == 0) {
+ if ((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G)) {
+ rc = ipmi_lcd_get_info_wh(intf);
+ } else {
+ rc = ipmi_lcd_get_info(intf);
+ }
+ } else if (strncmp(argv[current_arg], "status\0", 7) == 0) {
+ rc = ipmi_lcd_get_status(intf);
+ } else if (strncmp(argv[current_arg], "set\0", 4) == 0) {
+ /* ipmitool delloem lcd set*/
+ uint8_t line_number = 0;
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (strncmp(argv[current_arg], "line\0", 5) == 0) {
+ current_arg++;
+ if (argc <= current_arg) {
+ usage();
+ return -1;
+ }
+ if (str2uchar(argv[current_arg], &line_number) != 0) {
+ lprintf(LOG_ERR,
+ "Argument '%s' is either not a number or out of range.",
+ argv[current_arg]);
+ return (-1);
+ }
+ current_arg++;
+ if (argc <= current_arg) {
+ usage();
+ return -1;
+ }
+ }
+ if ((strncmp(argv[current_arg], "mode\0", 5) == 0)
+ && ((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G))) {
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (argv[current_arg] == NULL) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (strncmp(argv[current_arg], "none\0", 5) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_CONFIG_NONE, 0xFF,
+ 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "modelname\0", 10) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_CONFIG_DEFAULT, 0xFF,
+ 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "userdefined\0", 12) == 0) {
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_CONFIG_USER_DEFINED,
+ 0xFF, 0XFF, line_number, argv[current_arg]);
+ } else if (strncmp(argv[current_arg], "ipv4address\0", 12) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_iDRAC_IPV4ADRESS,
+ 0xFF, 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "macaddress\0", 11) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_IDRAC_MAC_ADDRESS,
+ 0xFF, 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "systemname\0", 11) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_OS_SYSTEM_NAME, 0xFF,
+ 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "servicetag\0", 11) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_SERVICE_TAG, 0xFF,
+ 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "ipv6address\0", 12) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_iDRAC_IPV6ADRESS,
+ 0xFF, 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "ambienttemp\0", 12) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_AMBEINT_TEMP, 0xFF,
+ 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "systemwatt\0", 11) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_SYSTEM_WATTS, 0xFF,
+ 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "assettag\0", 9) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, IPMI_DELL_LCD_ASSET_TAG, 0xFF,
+ 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "help\0", 5) == 0) {
+ ipmi_lcd_usage();
+ } else {
+ ipmi_lcd_usage();
+ }
+ } else if ((strncmp(argv[current_arg], "lcdqualifier\0", 13) == 0)
+ && ((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G))) {
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (argv[current_arg] == NULL) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (strncmp(argv[current_arg], "watt\0", 5) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, 0xFF, 0x00, 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "btuphr\0",7) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, 0xFF, 0x01, 0XFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "celsius\0", 8) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, 0xFF, 0x02, 0xFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "fahrenheit", 11) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, 0xFF, 0x03, 0xFF, 0, NULL);
+ } else if (strncmp(argv[current_arg], "help\0", 5) == 0) {
+ ipmi_lcd_usage();
+ } else {
+ ipmi_lcd_usage();
+ }
+ } else if ((strncmp(argv[current_arg], "errordisplay\0", 13) == 0)
+ && ((iDRAC_FLAG==IDRAC_11G) || (iDRAC_FLAG==IDRAC_12G))) {
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (argv[current_arg] == NULL) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (strncmp(argv[current_arg], "sel\0", 4) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, 0xFF, 0xFF,
+ IPMI_DELL_LCD_ERROR_DISP_SEL, 0, NULL);
+ } else if (strncmp(argv[current_arg], "simple\0", 7) == 0) {
+ rc = ipmi_lcd_configure_wh(intf, 0xFF, 0xFF,
+ IPMI_DELL_LCD_ERROR_DISP_VERBOSE, 0, NULL);
+ } else if (strncmp(argv[current_arg], "help\0", 5) == 0) {
+ ipmi_lcd_usage();
+ } else {
+ ipmi_lcd_usage();
+ }
+ } else if ((strncmp(argv[current_arg], "none\0", 5) == 0)
+ && (iDRAC_FLAG==0)) {
+ rc = ipmi_lcd_configure(intf, IPMI_DELL_LCD_CONFIG_NONE, 0, NULL);
+ } else if ((strncmp(argv[current_arg], "default\0", 8) == 0)
+ && (iDRAC_FLAG==0)) {
+ rc = ipmi_lcd_configure(intf, IPMI_DELL_LCD_CONFIG_DEFAULT, 0, NULL);
+ } else if ((strncmp(argv[current_arg], "custom\0", 7) == 0)
+ && (iDRAC_FLAG==0)) {
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ rc = ipmi_lcd_configure(intf, IPMI_DELL_LCD_CONFIG_USER_DEFINED,
+ line_number, argv[current_arg]);
+ } else if (strncmp(argv[current_arg], "vkvm\0", 5) == 0) {
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (strncmp(argv[current_arg], "active\0", 7) == 0) {
+ rc = ipmi_lcd_set_kvm(intf, 1);
+ } else if (strncmp(argv[current_arg], "inactive\0", 9) == 0) {
+ rc = ipmi_lcd_set_kvm(intf, 0);
+ } else if (strncmp(argv[current_arg], "help\0", 5) == 0) {
+ ipmi_lcd_usage();
+ } else {
+ ipmi_lcd_usage();
+ }
+ } else if (strncmp(argv[current_arg], "frontpanelaccess\0", 17) == 0) {
+ current_arg++;
+ if (argc <= current_arg) {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ if (strncmp(argv[current_arg], "viewandmodify\0", 14) == 0) {
+ rc = ipmi_lcd_set_lock(intf, 0);
+ } else if (strncmp(argv[current_arg], "viewonly\0", 9)==0) {
+ rc = ipmi_lcd_set_lock(intf, 1);
+ } else if (strncmp(argv[current_arg], "disabled\0", 9)==0) {
+ rc = ipmi_lcd_set_lock(intf, 2);
+ } else if (strncmp(argv[current_arg], "help\0", 5) == 0) {
+ ipmi_lcd_usage();
+ } else {
+ ipmi_lcd_usage();
+ }
+ } else if( (strncmp(argv[current_arg], "help\0", 5) == 0)
+ && (iDRAC_FLAG==0)) {
+ ipmi_lcd_usage();
+ } else {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ } else {
+ ipmi_lcd_usage();
+ return -1;
+ }
+ return rc;
+}
+/* ipmi_lcd_get_platform_model_name - This function retrieves the platform model
+ * name, or any other parameter which stores data in the same format
+ *
+ * @intf: pointer to interface
+ * @lcdstring: hostname/platform model string(output)
+ * @max_length: length of the platform model string
+ * @field_type: either hostname/platform model
+ *
+ * returns: 0 => success, other value means error
+ */
+int
+ipmi_lcd_get_platform_model_name(struct ipmi_intf * intf, char* lcdstring,
+ uint8_t max_length, uint8_t field_type)
+{
+ uint8_t data[4];
+ int bytes_copied = 0;
+ int ii = 0;
+ int lcdstring_len = 0;
+ int rc = 0;
+ IPMI_DELL_LCD_STRING lcdstringblock;
+
+ for (ii = 0; ii < 4; ii++) {
+ int bytes_to_copy;
+ rc = ipmi_mc_getsysinfo(intf, field_type, ii, 0, sizeof(lcdstringblock),
+ &lcdstringblock);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting platform model name");
+ break;
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting platform model name: %s",
+ val2str(rc, completion_code_vals));
+ break;
+ }
+ /* first block is different - 14 bytes*/
+ if (ii == 0) {
+ lcdstring_len = lcdstringblock.lcd_string.selector_0_string.length;
+ lcdstring_len = MIN(lcdstring_len,max_length);
+ bytes_to_copy = MIN(lcdstring_len, IPMI_DELL_LCD_STRING1_SIZE);
+ memcpy(lcdstring, lcdstringblock.lcd_string.selector_0_string.data,
+ bytes_to_copy);
+ } else {
+ int string_offset;
+ bytes_to_copy = MIN(lcdstring_len - bytes_copied,
+ IPMI_DELL_LCD_STRINGN_SIZE);
+ if (bytes_to_copy < 1) {
+ break;
+ }
+ string_offset = IPMI_DELL_LCD_STRING1_SIZE + IPMI_DELL_LCD_STRINGN_SIZE
+ * (ii-1);
+ memcpy(lcdstring + string_offset,
+ lcdstringblock.lcd_string.selector_n_data, bytes_to_copy);
+ }
+ bytes_copied += bytes_to_copy;
+ if (bytes_copied >= lcdstring_len) {
+ break;
+ }
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_idracvalidator_command
+ *
+ * Description: This function returns the iDRAC6 type
+ * Input: intf - ipmi interface
+ * Output:
+ *
+ * Return: iDRAC6 type 1 - whoville
+ * 0 - others
+ */
+static int
+ipmi_idracvalidator_command(struct ipmi_intf * intf)
+{
+ int rc;
+ uint8_t data[11];
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_IDRAC_VALIDATOR, 2, 0, sizeof(data),
+ data);
+ if (rc < 0) {
+ /*lprintf(LOG_ERR, " Error getting IMC type"); */
+ return -1;
+ } else if (rc > 0) {
+ /*lprintf(LOG_ERR, " Error getting IMC type: %s",
+ val2str(rsp->ccode, completion_code_vals)); */
+ return -1;
+ }
+ /* Support the 11G Monolithic, modular, Maisy and Coaster */
+ if ((IMC_IDRAC_11G_MONOLITHIC == data[10])
+ || (IMC_IDRAC_11G_MODULAR == data[10])
+ || (IMC_MASER_LITE_BMC == data[10])
+ || (IMC_MASER_LITE_NU == data[10])) {
+ iDRAC_FLAG=IDRAC_11G;
+ } else if((IMC_IDRAC_12G_MONOLITHIC == data[10])
+ || (IMC_IDRAC_12G_MODULAR == data[10])) {
+ iDRAC_FLAG = IDRAC_12G;
+ } else {
+ iDRAC_FLAG = 0;
+ }
+ IMC_Type = data[10];
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_get_configure_command_wh
+ *
+ * Description: This function returns current lcd configuration for Dell OEM LCD command
+ * Input: intf - ipmi interface
+ * Global: lcd_mode - lcd mode setting
+ * Output:
+ *
+ * Return: returns the current lcd configuration
+ * 0 = User defined
+ * 1 = Default
+ * 2 = None
+ */
+static int
+ipmi_lcd_get_configure_command_wh(struct ipmi_intf * intf)
+{
+ uint8_t data[4];
+ int rc;
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_CONFIG_SELECTOR, 0, 0,
+ sizeof(lcd_mode), &lcd_mode);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting LCD configuration");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)){
+ lprintf(LOG_ERR, "Error getting LCD configuration: "
+ "Command not supported on this system.");
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting LCD configuration: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_get_configure_command
+ *
+ * Description: This function returns current lcd configuration for Dell OEM
+ * LCD command
+ * Input: intf - ipmi interface
+ * Output: command - user defined / default / none / ipv4 / mac address /
+ * system name / service tag / ipv6 / temp / system watt / asset tag
+ *
+ * Return:
+ */
+static int
+ipmi_lcd_get_configure_command(struct ipmi_intf * intf, uint8_t *command)
+{
+ uint8_t data[4];
+ int rc;
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_CONFIG_SELECTOR, 0, 0,
+ sizeof(data), data);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting LCD configuration");
+ return -1;
+ } else if ((rc == 0xc1)||(rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting LCD configuration: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting LCD configuration: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ /* rsp->data[0] is the rev */
+ *command = data[1];
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_set_configure_command
+ *
+ * Description: This function updates current lcd configuration
+ * Input: intf - ipmi interface
+ * command - user defined / default / none / ipv4 / mac address /
+ * system name / service tag / ipv6 / temp / system watt / asset tag
+ * Output:
+ * Return:
+ */
+static int
+ipmi_lcd_set_configure_command(struct ipmi_intf * intf, int command)
+{
+ #define LSCC_DATA_LEN 2
+ uint8_t data[2];
+ int rc;
+ data[0] = IPMI_DELL_LCD_CONFIG_SELECTOR;
+ data[1] = command; /* command - custom, default, none */
+ rc = ipmi_mc_setsysinfo(intf, 2, data);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error setting LCD configuration");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error setting LCD configuration: "
+ "Command not supported on this system.");
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error setting LCD configuration: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_set_configure_command
+ *
+ * Description: This function updates current lcd configuration
+ * Input: intf - ipmi interface
+ * mode - user defined / default / none
+ * lcdquallifier - lcd quallifier id
+ * errordisp - error number
+ * Output:
+ * Return:
+ */
+static int
+ipmi_lcd_set_configure_command_wh(struct ipmi_intf * intf, uint32_t mode,
+ uint16_t lcdquallifier, uint8_t errordisp)
+{
+ #define LSCC_DATA_LEN 2
+ uint8_t data[13];
+ int rc;
+ ipmi_lcd_get_configure_command_wh(intf);
+ data[0] = IPMI_DELL_LCD_CONFIG_SELECTOR;
+ if (mode != 0xFF) {
+ data[1] = mode & 0xFF; /* command - custom, default, none*/
+ data[2] = (mode & 0xFF00) >> 8;
+ data[3] = (mode & 0xFF0000) >> 16;
+ data[4] = (mode & 0xFF000000) >> 24;
+ } else {
+ data[1] = (lcd_mode.lcdmode) & 0xFF; /* command - custom, default, none*/
+ data[2] = ((lcd_mode.lcdmode) & 0xFF00) >> 8;
+ data[3] = ((lcd_mode.lcdmode) & 0xFF0000) >> 16;
+ data[4] = ((lcd_mode.lcdmode) & 0xFF000000) >> 24;
+ }
+ if (lcdquallifier != 0xFF) {
+ if(lcdquallifier == 0x01) {
+ data[5] = (lcd_mode.lcdquallifier) | 0x01; /* command - custom, default, none*/
+ } else if (lcdquallifier == 0x00) {
+ data[5] = (lcd_mode.lcdquallifier) & 0xFE; /* command - custom, default, none*/
+ } else if (lcdquallifier == 0x03) {
+ data[5] = (lcd_mode.lcdquallifier) | 0x02; /* command - custom, default, none*/
+ } else if (lcdquallifier == 0x02) {
+ data[5] = (lcd_mode.lcdquallifier) & 0xFD;
+ }
+ } else {
+ data[5] = lcd_mode.lcdquallifier;
+ }
+ if (errordisp != 0xFF) {
+ data[11] = errordisp;
+ } else {
+ data[11] = lcd_mode.error_display;
+ }
+ rc = ipmi_mc_setsysinfo(intf, 13, data);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error setting LCD configuration");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error setting LCD configuration: "
+ "Command not supported on this system.");
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error setting LCD configuration: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_get_single_line_text
+ *
+ * Description: This function updates current lcd configuration
+ * Input: intf - ipmi interface
+ * lcdstring - new string to be updated
+ * max_length - length of the string
+ * Output:
+ * Return:
+ */
+static int
+ipmi_lcd_get_single_line_text(struct ipmi_intf * intf, char* lcdstring,
+ uint8_t max_length)
+{
+ IPMI_DELL_LCD_STRING lcdstringblock;
+ int lcdstring_len = 0;
+ int bytes_copied = 0;
+ int ii, rc;
+ for (ii = 0; ii < 4; ii++) {
+ int bytes_to_copy;
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_STRING_SELECTOR, ii, 0,
+ sizeof(lcdstringblock), &lcdstringblock);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting text data");
+ return -1;
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting text data: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ /* first block is different - 14 bytes*/
+ if (0 == ii) {
+ lcdstring_len = lcdstringblock.lcd_string.selector_0_string.length;
+ if (lcdstring_len < 1 || lcdstring_len > max_length) {
+ break;
+ }
+ bytes_to_copy = MIN(lcdstring_len, IPMI_DELL_LCD_STRING1_SIZE);
+ memcpy(lcdstring, lcdstringblock.lcd_string.selector_0_string.data,
+ bytes_to_copy);
+ } else {
+ int string_offset;
+ bytes_to_copy = MIN(lcdstring_len - bytes_copied,
+ IPMI_DELL_LCD_STRINGN_SIZE);
+ if (bytes_to_copy < 1) {
+ break;
+ }
+ string_offset = IPMI_DELL_LCD_STRING1_SIZE + IPMI_DELL_LCD_STRINGN_SIZE
+ * (ii-1);
+ memcpy(lcdstring+string_offset,
+ lcdstringblock.lcd_string.selector_n_data, bytes_to_copy);
+ }
+ bytes_copied += bytes_to_copy;
+ if (bytes_copied >= lcdstring_len) {
+ break;
+ }
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_get_info_wh
+ *
+ * Description: This function prints current lcd configuration for whoville platform
+ * Input: intf - ipmi interface
+ * Output:
+ * Return:
+ */
+static int
+ipmi_lcd_get_info_wh(struct ipmi_intf * intf)
+{
+ IPMI_DELL_LCD_CAPS lcd_caps;
+ char lcdstring[IPMI_DELL_LCD_STRING_LENGTH_MAX+1] = {0};
+ int rc;
+ printf("LCD info\n");
+ if (ipmi_lcd_get_configure_command_wh(intf) != 0) {
+ return -1;
+ }
+ if (lcd_mode.lcdmode== IPMI_DELL_LCD_CONFIG_DEFAULT) {
+ char text[IPMI_DELL_LCD_STRING_LENGTH_MAX+1] = {0};
+ if (ipmi_lcd_get_platform_model_name(intf, text,
+ IPMI_DELL_LCD_STRING_LENGTH_MAX,
+ IPMI_DELL_PLATFORM_MODEL_NAME_SELECTOR) != 0) {
+ return (-1);
+ }
+ printf(" Setting:Model name\n");
+ printf(" Line 1: %s\n", text);
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_CONFIG_NONE) {
+ printf(" Setting: none\n");
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_CONFIG_USER_DEFINED) {
+ printf(" Setting: User defined\n");
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_GET_CAPS_SELECTOR, 0, 0,
+ sizeof(lcd_caps), &lcd_caps);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities.");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities: "
+ "Command not supported on this system.");
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (lcd_caps.number_lines > 0) {
+ memset(lcdstring, 0, IPMI_DELL_LCD_STRING_LENGTH_MAX + 1);
+ rc = ipmi_lcd_get_single_line_text(intf, lcdstring,
+ lcd_caps.max_chars[0]);
+ printf(" Text: %s\n", lcdstring);
+ } else {
+ printf(" No lines to show\n");
+ }
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_iDRAC_IPV4ADRESS) {
+ printf(" Setting: IPV4 Address\n");
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_IDRAC_MAC_ADDRESS) {
+ printf(" Setting: MAC Address\n");
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_OS_SYSTEM_NAME) {
+ printf(" Setting: OS System Name\n");
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_SERVICE_TAG) {
+ printf(" Setting: System Tag\n");
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_iDRAC_IPV6ADRESS) {
+ printf(" Setting: IPV6 Address\n");
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_ASSET_TAG) {
+ printf(" Setting: Asset Tag\n");
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_AMBEINT_TEMP) {
+ printf(" Setting: Ambient Temp\n");
+ if (lcd_mode.lcdquallifier & 0x02) {
+ printf(" Unit: F\n");
+ } else {
+ printf(" Unit: C\n");
+ }
+ } else if (lcd_mode.lcdmode == IPMI_DELL_LCD_SYSTEM_WATTS) {
+ printf(" Setting: System Watts\n");
+ if (lcd_mode.lcdquallifier & 0x01) {
+ printf(" Unit: BTU/hr\n");
+ } else {
+ printf(" Unit: Watt\n");
+ }
+ }
+ if (lcd_mode.error_display == IPMI_DELL_LCD_ERROR_DISP_SEL) {
+ printf(" Error Display: SEL\n");
+ } else if (lcd_mode.error_display == IPMI_DELL_LCD_ERROR_DISP_VERBOSE) {
+ printf(" Error Display: Simple\n");
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_get_info
+ *
+ * Description: This function prints current lcd configuration for platform other than whoville
+ * Input: intf - ipmi interface
+ * Output:
+ * Return:
+ */
+static int
+ipmi_lcd_get_info(struct ipmi_intf * intf)
+{
+ IPMI_DELL_LCD_CAPS lcd_caps;
+ uint8_t command = 0;
+ char lcdstring[IPMI_DELL_LCD_STRING_LENGTH_MAX+1] = {0};
+ int rc;
+
+ printf("LCD info\n");
+
+ if (ipmi_lcd_get_configure_command(intf, &command) != 0) {
+ return -1;
+ }
+ if (command == IPMI_DELL_LCD_CONFIG_DEFAULT) {
+ memset(lcdstring,0,IPMI_DELL_LCD_STRING_LENGTH_MAX+1);
+ if (ipmi_lcd_get_platform_model_name(intf, lcdstring,
+ IPMI_DELL_LCD_STRING_LENGTH_MAX,
+ IPMI_DELL_PLATFORM_MODEL_NAME_SELECTOR) != 0) {
+ return (-1);
+ }
+ printf(" Setting: default\n");
+ printf(" Line 1: %s\n", lcdstring);
+ } else if (command == IPMI_DELL_LCD_CONFIG_NONE) {
+ printf(" Setting: none\n");
+ } else if (command == IPMI_DELL_LCD_CONFIG_USER_DEFINED) {
+ printf(" Setting: custom\n");
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_GET_CAPS_SELECTOR, 0, 0,
+ sizeof(lcd_caps), &lcd_caps);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities.");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities: "
+ "Command not supported on this system.");
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (lcd_caps.number_lines > 0) {
+ memset(lcdstring, 0, IPMI_DELL_LCD_STRING_LENGTH_MAX + 1);
+ rc = ipmi_lcd_get_single_line_text(intf, lcdstring,
+ lcd_caps.max_chars[0]);
+ printf(" Text: %s\n", lcdstring);
+ } else {
+ printf(" No lines to show\n");
+ }
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_lcd_get_status_val
+ *
+ * Description: This function gets current lcd configuration
+ * Input: intf - ipmi interface
+ * Output: lcdstatus - KVM Status & Lock Status
+ * Return:
+ */
+static int
+ipmi_lcd_get_status_val(struct ipmi_intf * intf, LCD_STATUS* lcdstatus)
+{
+ int rc;
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_STATUS_SELECTOR, 0, 0,
+ sizeof(*lcdstatus), lcdstatus);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting LCD Status");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting LCD status: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting LCD Status: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: IsLCDSupported
+ *
+ * Description: This function returns whether lcd supported or not
+ * Input:
+ * Output:
+ * Return:
+ */
+static int
+IsLCDSupported()
+{
+ return LcdSupported;
+}
+/*
+ * Function Name: CheckLCDSupport
+ *
+ * Description: This function checks whether lcd supported or not
+ * Input: intf - ipmi interface
+ * Output:
+ * Return:
+ */
+static void
+CheckLCDSupport(struct ipmi_intf * intf)
+{
+ int rc;
+ LcdSupported = 0;
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_STATUS_SELECTOR, 0, 0, 0, NULL);
+ if (rc == 0) {
+ LcdSupported = 1;
+ }
+}
+/*
+ * Function Name: ipmi_lcd_status_print
+ *
+ * Description: This function prints current lcd configuration KVM Status & Lock Status
+ * Input: lcdstatus - KVM Status & Lock Status
+ * Output:
+ * Return:
+ */
+static void
+ipmi_lcd_status_print(LCD_STATUS lcdstatus)
+{
+ switch (lcdstatus.vKVM_status) {
+ case 0x00:
+ printf("LCD KVM Status :Inactive\n");
+ break;
+ case 0x01:
+ printf("LCD KVM Status :Active\n");
+ break;
+ default:
+ printf("LCD KVM Status :Invalid Status\n");
+ break;
+ }
+ switch (lcdstatus.lock_status) {
+ case 0x00:
+ printf("LCD lock Status :View and modify\n");
+ break;
+ case 0x01:
+ printf("LCD lock Status :View only\n");
+ break;
+ case 0x02:
+ printf("LCD lock Status :disabled\n");
+ break;
+ default:
+ printf("LCD lock Status :Invalid\n");
+ break;
+ }
+}
+/*
+ * Function Name: ipmi_lcd_get_status
+ *
+ * Description: This function gets current lcd KVM active status & lcd access mode
+ * Input: intf - ipmi interface
+ * Output:
+ * Return: -1 on error
+ * 0 if successful
+ */
+static int
+ipmi_lcd_get_status(struct ipmi_intf * intf)
+{
+ int rc=0;
+ LCD_STATUS lcdstatus;
+ rc =ipmi_lcd_get_status_val( intf, &lcdstatus);
+ if (rc < 0) {
+ return -1;
+ }
+ ipmi_lcd_status_print(lcdstatus);
+ return rc;
+}
+/*
+ * Function Name: ipmi_lcd_set_kvm
+ *
+ * Description: This function sets lcd KVM active status
+ * Input: intf - ipmi interface
+ * status - Inactive / Active
+ * Output:
+ * Return: -1 on error
+ * 0 if successful
+ */
+static int
+ipmi_lcd_set_kvm(struct ipmi_intf * intf, char status)
+{
+ #define LSCC_DATA_LEN 2
+ LCD_STATUS lcdstatus;
+ int rc=0;
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint8_t data[5];
+ rc = ipmi_lcd_get_status_val(intf,&lcdstatus);
+ if (rc < 0) {
+ return -1;
+ }
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_SET_SYS_INFO;
+ req.msg.data_len = 5;
+ req.msg.data = data;
+ data[0] = IPMI_DELL_LCD_STATUS_SELECTOR;
+ data[1] = status; /* active- incative*/
+ data[2] = lcdstatus.lock_status; /* full-veiw-locked */
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error setting LCD status");
+ rc= -1;
+ } else if ((rsp->ccode == 0xc1) || (rsp->ccode == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting LCD status: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error setting LCD status: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ rc= -1;
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_lcd_set_lock
+ *
+ * Description: This function sets lcd access mode
+ * Input: intf - ipmi interface
+ * lock - View and modify / View only / Diabled
+ * Output:
+ * Return: -1 on error
+ * 0 if successful
+ */
+static int
+ipmi_lcd_set_lock(struct ipmi_intf * intf, char lock)
+{
+ #define LSCC_DATA_LEN 2
+ LCD_STATUS lcdstatus;
+ int rc =0;
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint8_t data[5];
+ rc = ipmi_lcd_get_status_val(intf,&lcdstatus);
+ if (rc < 0) {
+ return -1;
+ }
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_SET_SYS_INFO;
+ req.msg.data_len = 5;
+ req.msg.data = data;
+ data[0] = IPMI_DELL_LCD_STATUS_SELECTOR;
+ data[1] = lcdstatus.vKVM_status; /* active- incative */
+ data[2] = lock; /* full- veiw-locked */
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error setting LCD status");
+ rc = -1;
+ } else if ((rsp->ccode == 0xc1) || (rsp->ccode == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting LCD status: "
+ "Command not supported on this system.");
+ rc = -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error setting LCD status: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ rc= -1;
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_lcd_set_single_line_text
+ *
+ * Description: This function sets lcd line text
+ * Input: intf - ipmi interface
+ * text - lcd string
+ * Output:
+ * Return: -1 on error
+ * 0 if successful
+ */
+static int
+ipmi_lcd_set_single_line_text(struct ipmi_intf * intf, char * text)
+{
+ uint8_t data[18];
+ int bytes_to_store = strlen(text);
+ int bytes_stored = 0;
+ int ii;
+ int rc = 0;
+ if (bytes_to_store > IPMI_DELL_LCD_STRING_LENGTH_MAX) {
+ lprintf(LOG_ERR, "Out of range Max limit is 62 characters");
+ return (-1);
+ } else {
+ bytes_to_store = MIN(bytes_to_store, IPMI_DELL_LCD_STRING_LENGTH_MAX);
+ for (ii = 0; ii < 4; ii++) {
+ /*first block, 2 bytes parms and 14 bytes data*/
+ if (0 == ii) {
+ int size_of_copy = MIN((bytes_to_store - bytes_stored),
+ IPMI_DELL_LCD_STRING1_SIZE);
+ if (size_of_copy < 0) {
+ /* allow 0 string length*/
+ break;
+ }
+ data[0] = IPMI_DELL_LCD_STRING_SELECTOR;
+ data[1] = ii; /* block number to use (0)*/
+ data[2] = 0; /*string encoding*/
+ data[3] = bytes_to_store; /* total string length*/
+ memcpy(data + 4, text+bytes_stored, size_of_copy);
+ bytes_stored += size_of_copy;
+ } else {
+ int size_of_copy = MIN((bytes_to_store - bytes_stored),
+ IPMI_DELL_LCD_STRINGN_SIZE);
+ if (size_of_copy <= 0) {
+ break;
+ }
+ data[0] = IPMI_DELL_LCD_STRING_SELECTOR;
+ data[1] = ii; /* block number to use (1,2,3)*/
+ memcpy(data + 2, text+bytes_stored, size_of_copy);
+ bytes_stored += size_of_copy;
+ }
+ rc = ipmi_mc_setsysinfo(intf, 18, data);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error setting text data");
+ rc = -1;
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error setting text data: %s",
+ val2str(rc, completion_code_vals));
+ rc = -1;
+ }
+ }
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_lcd_set_text
+ *
+ * Description: This function sets lcd line text
+ * Input: intf - ipmi interface
+ * text - lcd string
+ * line_number- line number
+ * Output:
+ * Return: -1 on error
+ * 0 if successful
+ */
+static int
+ipmi_lcd_set_text(struct ipmi_intf * intf, char * text, int line_number)
+{
+ int rc = 0;
+ IPMI_DELL_LCD_CAPS lcd_caps;
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_LCD_GET_CAPS_SELECTOR, 0, 0,
+ sizeof(lcd_caps), &lcd_caps);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities");
+ return -1;
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error getting LCD capabilities: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (lcd_caps.number_lines > 0) {
+ rc = ipmi_lcd_set_single_line_text(intf, text);
+ } else {
+ lprintf(LOG_ERR, "LCD does not have any lines that can be set");
+ rc = -1;
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_lcd_configure_wh
+ *
+ * Description: This function updates the current lcd configuration
+ * Input: intf - ipmi interface
+ * lcdquallifier- lcd quallifier
+ * errordisp - error number
+ * line_number-line number
+ * text - lcd string
+ * Output:
+ * Return: -1 on error
+ * 0 if successful
+ */
+static int
+ipmi_lcd_configure_wh(struct ipmi_intf * intf, uint32_t mode,
+ uint16_t lcdquallifier, uint8_t errordisp, int8_t line_number, char * text)
+{
+ int rc = 0;
+ if (IPMI_DELL_LCD_CONFIG_USER_DEFINED == mode) {
+ /* Any error was reported earlier. */
+ rc = ipmi_lcd_set_text(intf, text, line_number);
+ }
+ if (rc == 0) {
+ rc = ipmi_lcd_set_configure_command_wh(intf, mode ,lcdquallifier,errordisp);
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_lcd_configure
+ *
+ * Description: This function updates the current lcd configuration
+ * Input: intf - ipmi interface
+ * command- lcd command
+ * line_number-line number
+ * text - lcd string
+ * Output:
+ * Return: -1 on error
+ * 0 if successful
+ */
+static int
+ipmi_lcd_configure(struct ipmi_intf * intf, int command,
+ int8_t line_number, char * text)
+{
+ int rc = 0;
+ if (IPMI_DELL_LCD_CONFIG_USER_DEFINED == command) {
+ rc = ipmi_lcd_set_text(intf, text, line_number);
+ }
+ if (rc == 0) {
+ rc = ipmi_lcd_set_configure_command(intf, command);
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_lcd_usage
+ *
+ * Description: This function prints help message for lcd command
+ * Input:
+ * Output:
+ *
+ * Return:
+ */
+static void
+ipmi_lcd_usage(void)
+{
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"Generic DELL HW:");
+ lprintf(LOG_NOTICE,
+" lcd set {none}|{default}|{custom <text>}");
+ lprintf(LOG_NOTICE,
+" Set LCD text displayed during non-fault conditions");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"iDRAC 11g or iDRAC 12g:");
+ lprintf(LOG_NOTICE,
+" lcd set {mode}|{lcdqualifier}|{errordisplay}");
+ lprintf(LOG_NOTICE,
+" Allows you to set the LCD mode and user-defined string.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lcd set mode {none}|{modelname}|{ipv4address}|{macaddress}|");
+ lprintf(LOG_NOTICE,
+" {systemname}|{servicetag}|{ipv6address}|{ambienttemp}");
+ lprintf(LOG_NOTICE,
+" {systemwatt }|{assettag}|{userdefined}<text>");
+ lprintf(LOG_NOTICE,
+" Allows you to set the LCD display mode to any of the preceding");
+ lprintf(LOG_NOTICE,
+" parameters");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lcd set lcdqualifier {watt}|{btuphr}|{celsius}|{fahrenheit}");
+ lprintf(LOG_NOTICE,
+" Allows you to set the unit for the system ambient temperature mode.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lcd set errordisplay {sel}|{simple}");
+ lprintf(LOG_NOTICE,
+" Allows you to set the error display.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lcd info");
+ lprintf(LOG_NOTICE,
+" Show LCD text that is displayed during non-fault conditions");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lcd set vkvm{active}|{inactive}");
+ lprintf(LOG_NOTICE,
+" Set vKVM active and inactive, message will be displayed on lcd");
+ lprintf(LOG_NOTICE,
+" when vKVM is active and vKVM session is in progress");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lcd set frontpanelaccess {viewandmodify}|{viewonly}|{disabled}");
+ lprintf(LOG_NOTICE,
+" Set LCD mode to view and modify, view only or disabled ");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lcd status");
+ lprintf(LOG_NOTICE,
+" Show LCD Status for vKVM display<active|inactive>");
+ lprintf(LOG_NOTICE,
+" and Front Panel access mode {viewandmodify}|{viewonly}|{disabled}");
+ lprintf(LOG_NOTICE,
+"");
+}
+/*
+ * Function Name: ipmi_delloem_mac_main
+ *
+ * Description: This function processes the delloem mac command
+ * Input: intf - ipmi interface
+ * argc - no of arguments
+ * argv - argument string array
+ * Output:
+ *
+ * Return: return code 0 - success
+ * -1 - failure
+ */
+static int
+ipmi_delloem_mac_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ int currIdInt = -1;
+ current_arg++;
+ if (argc > 1 && strcmp(argv[current_arg], "help") == 0) {
+ ipmi_mac_usage();
+ return 0;
+ }
+ ipmi_idracvalidator_command(intf);
+ if (argc == 1) {
+ rc = ipmi_macinfo(intf, 0xff);
+ } else if (strncmp(argv[current_arg], "list\0", 5) == 0) {
+ rc = ipmi_macinfo(intf, 0xff);
+ } else if (strncmp(argv[current_arg], "get\0", 4) == 0) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ ipmi_mac_usage();
+ return -1;
+ }
+ if (str2int(argv[current_arg],&currIdInt) != 0) {
+ lprintf(LOG_ERR,
+ "Invalid NIC number. The NIC number should be between 0-8");
+ return -1;
+ }
+ if ((currIdInt > 8) || (currIdInt < 0)) {
+ lprintf(LOG_ERR,
+ "Invalid NIC number. The NIC number should be between 0-8");
+ return -1;
+ }
+ rc = ipmi_macinfo(intf, currIdInt);
+ } else {
+ ipmi_mac_usage();
+ }
+ return rc;
+}
+
+EmbeddedNICMacAddressType EmbeddedNICMacAddress;
+
+EmbeddedNICMacAddressType_10G EmbeddedNICMacAddress_10G;
+
+static void
+InitEmbeddedNICMacAddressValues()
+{
+ uint8_t i;
+ uint8_t j;
+ for (i = 0; i < MAX_LOM; i++) {
+ EmbeddedNICMacAddress.LOMMacAddress[i].BladSlotNumber = 0;
+ EmbeddedNICMacAddress.LOMMacAddress[i].MacType = LOM_MACTYPE_RESERVED;
+ EmbeddedNICMacAddress.LOMMacAddress[i].EthernetStatus =
+ LOM_ETHERNET_RESERVED;
+ EmbeddedNICMacAddress.LOMMacAddress[i].NICNumber = 0;
+ EmbeddedNICMacAddress.LOMMacAddress[i].Reserved = 0;
+ for (j = 0; j < MACADDRESSLENGH; j++) {
+ EmbeddedNICMacAddress.LOMMacAddress[i].MacAddressByte[j] = 0;
+ EmbeddedNICMacAddress_10G.MacAddress[i].MacAddressByte[j] = 0;
+ }
+ }
+}
+
+uint8_t UseVirtualMacAddress = 0;
+static int
+ipmi_macinfo_drac_idrac_virtual_mac(struct ipmi_intf* intf,uint8_t NicNum)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[30];
+ uint8_t VirtualMacAddress [MACADDRESSLENGH];
+ uint8_t input_length=0;
+ uint8_t j;
+ uint8_t i;
+ if (NicNum != 0xff && NicNum != IDRAC_NIC_NUMBER) {
+ return 0;
+ }
+ UseVirtualMacAddress = 0;
+ input_length = 0;
+ msg_data[input_length++] = 1; /*Get*/
+
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_IDRAC_VIRTUAL_MAC;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ return -1;
+ }
+ if ((IMC_IDRAC_12G_MODULAR == IMC_Type)
+ || (IMC_IDRAC_12G_MONOLITHIC== IMC_Type)) {
+ /* Get the Chasiss Assigned MAC Addresss for 12g Only */
+ memcpy(VirtualMacAddress, ((rsp->data) + 1), MACADDRESSLENGH);
+ for (i = 0; i < MACADDRESSLENGH; i++) {
+ if (VirtualMacAddress[i] != 0) {
+ UseVirtualMacAddress = 1;
+ }
+ }
+ /* Get the Server Assigned MAC Addresss for 12g Only */
+ if (!UseVirtualMacAddress) {
+ memcpy(VirtualMacAddress, ((rsp->data) + 1 + MACADDRESSLENGH),
+ MACADDRESSLENGH);
+ for (i = 0; i < MACADDRESSLENGH; i++) {
+ if (VirtualMacAddress[i] != 0) {
+ UseVirtualMacAddress = 1;
+ }
+ }
+ }
+ } else {
+ memcpy(VirtualMacAddress, ((rsp->data) + VIRTUAL_MAC_OFFSET),
+ MACADDRESSLENGH);
+ for (i = 0; i < MACADDRESSLENGH; i++) {
+ if (VirtualMacAddress[i] != 0) {
+ UseVirtualMacAddress = 1;
+ }
+ }
+ }
+ if (UseVirtualMacAddress == 0) {
+ return -1;
+ }
+ if (IMC_IDRAC_10G == IMC_Type) {
+ printf("\nDRAC MAC Address ");
+ } else if ((IMC_IDRAC_11G_MODULAR == IMC_Type)
+ || (IMC_IDRAC_11G_MONOLITHIC== IMC_Type)) {
+ printf("\niDRAC6 MAC Address ");
+ } else if ((IMC_IDRAC_12G_MODULAR == IMC_Type)
+ || (IMC_IDRAC_12G_MONOLITHIC== IMC_Type)) {
+ printf("\niDRAC7 MAC Address ");
+ } else if ((IMC_MASER_LITE_BMC== IMC_Type)
+ || (IMC_MASER_LITE_NU== IMC_Type)) {
+ printf("\nBMC MAC Address ");
+ } else {
+ printf("\niDRAC6 MAC Address ");
+ }
+
+ for (j = 0; j < 5; j++) {
+ printf("%02x:", VirtualMacAddress[j]);
+ }
+ printf("%02x", VirtualMacAddress[j]);
+ printf("\n");
+ return 0;
+}
+/*
+ * Function Name: ipmi_macinfo_drac_idrac_mac
+ *
+ * Description: This function retrieves the mac address of DRAC or iDRAC
+ * Input: NicNum
+ * Output:
+ * Return:
+ */
+static int
+ipmi_macinfo_drac_idrac_mac(struct ipmi_intf* intf,uint8_t NicNum)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[30];
+ uint8_t input_length=0;
+ uint8_t iDRAC6MacAddressByte[MACADDRESSLENGH];
+ uint8_t j;
+ ipmi_macinfo_drac_idrac_virtual_mac(intf,NicNum);
+ if ((NicNum != 0xff && NicNum != IDRAC_NIC_NUMBER)
+ || UseVirtualMacAddress != 0) {
+ return 0;
+ }
+ input_length = 0;
+ msg_data[input_length++] = LAN_CHANNEL_NUMBER;
+ msg_data[input_length++] = MAC_ADDR_PARAM;
+ msg_data[input_length++] = 0x00;
+ msg_data[input_length++] = 0x00;
+
+ req.msg.netfn = TRANSPORT_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_LAN_PARAM_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting MAC Address");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting MAC Address (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ memcpy(iDRAC6MacAddressByte, ((rsp->data) + PARAM_REV_OFFSET),
+ MACADDRESSLENGH);
+
+ if (IMC_IDRAC_10G == IMC_Type) {
+ printf("\nDRAC MAC Address ");
+ } else if ((IMC_IDRAC_11G_MODULAR == IMC_Type)
+ || (IMC_IDRAC_11G_MONOLITHIC== IMC_Type)) {
+ printf("\niDRAC6 MAC Address ");
+ } else if ((IMC_IDRAC_12G_MODULAR == IMC_Type)
+ || (IMC_IDRAC_12G_MONOLITHIC== IMC_Type)) {
+ printf("\niDRAC7 MAC Address ");
+ } else if ((IMC_MASER_LITE_BMC== IMC_Type)
+ || (IMC_MASER_LITE_NU== IMC_Type)) {
+ printf("\n\rBMC MAC Address ");
+ } else {
+ printf("\niDRAC6 MAC Address ");
+ }
+
+ for (j = 0; j < 5; j++) {
+ printf("%02x:", iDRAC6MacAddressByte[j]);
+ }
+ printf("%02x", iDRAC6MacAddressByte[j]);
+ printf("\n");
+ return 0;
+}
+/*
+ * Function Name: ipmi_macinfo_10g
+ *
+ * Description: This function retrieves the mac address of LOMs
+ * Input: intf - ipmi interface
+ * NicNum - NIC number
+ * Output:
+ * Return:
+ */
+static int
+ipmi_macinfo_10g(struct ipmi_intf* intf, uint8_t NicNum)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[30];
+ uint8_t input_length=0;
+ uint8_t j;
+ uint8_t i;
+ uint8_t Total_No_NICs = 0;
+ InitEmbeddedNICMacAddressValues();
+ memset(msg_data, 0, sizeof(msg_data));
+ input_length = 0;
+ msg_data[input_length++] = 0x00; /* Get Parameter Command */
+ msg_data[input_length++] = EMB_NIC_MAC_ADDRESS_9G_10G; /* OEM Param */
+ msg_data[input_length++] = 0x00;
+ msg_data[input_length++] = 0x00;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_GET_SYS_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting MAC Address");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting MAC Address (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ Total_No_NICs = (uint8_t)rsp->data[0 + PARAM_REV_OFFSET]; /* Byte 1: Total Number of Embedded NICs */
+ if (IDRAC_NIC_NUMBER != NicNum) {
+ if (0xff == NicNum) {
+ printf("\nSystem LOMs");
+ }
+ printf("\nNIC Number\tMAC Address\n");
+ memcpy(&EmbeddedNICMacAddress_10G,
+ ((rsp->data) + PARAM_REV_OFFSET+TOTAL_N0_NICS_INDEX),
+ Total_No_NICs* MACADDRESSLENGH);
+ /*Read the LOM type and Mac Addresses */
+ for (i = 0; i < Total_No_NICs; i++) {
+ if ((0xff == NicNum) || (i == NicNum)) {
+ printf("\n%d",i);
+ printf("\t\t");
+ for (j = 0 ; j < 5; j++) {
+ printf("%02x:",
+ EmbeddedNICMacAddress_10G.MacAddress[i].MacAddressByte[j]);
+ }
+ printf("%02x",
+ EmbeddedNICMacAddress_10G.MacAddress[i].MacAddressByte[j]);
+ }
+ }
+ printf("\n");
+ }
+ ipmi_macinfo_drac_idrac_mac(intf,NicNum);
+ return 0;
+}
+/*
+ * Function Name: ipmi_macinfo_11g
+ *
+ * Description: This function retrieves the mac address of LOMs
+ * Input: intf - ipmi interface
+ * Output:
+ * Return:
+ */
+static int
+ipmi_macinfo_11g(struct ipmi_intf* intf, uint8_t NicNum)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t input_length = 0;
+ uint8_t i;
+ uint8_t j;
+ uint8_t len;
+ uint8_t loop_count;
+ uint8_t maxlen;
+ uint8_t msg_data[30];
+ uint8_t offset;
+ offset = 0;
+ len = 8; /*eigher 8 or 16 */
+ maxlen = 64;
+ loop_count = maxlen / len;
+ InitEmbeddedNICMacAddressValues();
+ memset(msg_data, 0, sizeof(msg_data));
+ input_length = 0;
+ msg_data[input_length++] = 0x00; /* Get Parameter Command */
+ msg_data[input_length++] = EMB_NIC_MAC_ADDRESS_11G; /* OEM Param */
+ msg_data[input_length++] = 0x00;
+ msg_data[input_length++] = 0x00;
+ msg_data[input_length++] = 0x00;
+ msg_data[input_length++] = 0x00;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_GET_SYS_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting MAC Address");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting MAC Address (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ len = 8; /*eigher 8 or 16 */
+ maxlen = (uint8_t)rsp->data[0 + PARAM_REV_OFFSET];
+ loop_count = maxlen / len;
+ if (IDRAC_NIC_NUMBER != NicNum) {
+ if (0xff == NicNum) {
+ printf("\nSystem LOMs");
+ }
+ printf("\nNIC Number\tMAC Address\t\tStatus\n");
+ /*Read the LOM type and Mac Addresses */
+ offset=0;
+ for (i = 0; i < loop_count; i++, offset = offset + len) {
+ input_length = 4;
+ msg_data[input_length++] = offset;
+ msg_data[input_length++] = len;
+
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_GET_SYS_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting MAC Address");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting MAC Address (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ memcpy(&(EmbeddedNICMacAddress.LOMMacAddress[i]),
+ ((rsp->data)+PARAM_REV_OFFSET), len);
+ if (LOM_MACTYPE_ETHERNET == EmbeddedNICMacAddress.LOMMacAddress[i].MacType) {
+ if ((0xff==NicNum)
+ || (NicNum == EmbeddedNICMacAddress.LOMMacAddress[i].NICNumber)) {
+ printf("\n%d",EmbeddedNICMacAddress.LOMMacAddress[i].NICNumber);
+ printf("\t\t");
+ for (j = 0; j < 5; j++) {
+ printf("%02x:",
+ EmbeddedNICMacAddress.LOMMacAddress[i].MacAddressByte[j]);
+ }
+ printf("%02x",
+ EmbeddedNICMacAddress.LOMMacAddress[i].MacAddressByte[j]);
+
+ if (LOM_ETHERNET_ENABLED
+ == EmbeddedNICMacAddress.LOMMacAddress[i].EthernetStatus) {
+ printf("\tEnabled");
+ } else {
+ printf("\tDisabled");
+ }
+ }
+ }
+ }
+ printf("\n");
+ }
+ ipmi_macinfo_drac_idrac_mac(intf,NicNum);
+ return 0;
+}
+/*
+ * Function Name: ipmi_macinfo
+ *
+ * Description: This function retrieves the mac address of LOMs
+ * Input: intf - ipmi interface
+ * Output:
+ * Return:
+ */
+static int
+ipmi_macinfo(struct ipmi_intf* intf, uint8_t NicNum)
+{
+ if (IMC_IDRAC_10G == IMC_Type) {
+ return ipmi_macinfo_10g(intf,NicNum);
+ } else if ((IMC_IDRAC_11G_MODULAR == IMC_Type
+ || IMC_IDRAC_11G_MONOLITHIC == IMC_Type)
+ || (IMC_IDRAC_12G_MODULAR == IMC_Type
+ || IMC_IDRAC_12G_MONOLITHIC == IMC_Type)
+ || (IMC_MASER_LITE_NU == IMC_Type || IMC_MASER_LITE_BMC== IMC_Type)) {
+ return ipmi_macinfo_11g(intf,NicNum);
+ } else {
+ lprintf(LOG_ERR, "Error in getting MAC Address : Not supported platform");
+ return (-1);
+ }
+}
+/*
+ * Function Name: ipmi_mac_usage
+ *
+ * Description: This function prints help message for mac command
+ * Input:
+ * Output:
+ *
+ * Return:
+ */
+static void
+ipmi_mac_usage(void)
+{
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" mac list");
+ lprintf(LOG_NOTICE,
+" Lists the MAC address of LOMs");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" mac get <NIC number>");
+ lprintf(LOG_NOTICE,
+" Shows the MAC address of specified LOM. 0-7 System LOM, 8- DRAC/iDRAC.");
+ lprintf(LOG_NOTICE,
+"");
+}
+/*
+ * Function Name: ipmi_delloem_lan_main
+ *
+ * Description: This function processes the delloem lan command
+ * Input: intf - ipmi interface
+ * argc - no of arguments
+ * argv - argument string array
+ * Output:
+ *
+ * Return: return code 0 - success
+ * -1 - failure
+ */
+static int
+ipmi_delloem_lan_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ int nic_selection = 0;
+ char nic_set[2] = {0};
+ current_arg++;
+ if (argv[current_arg] == NULL || strcmp(argv[current_arg], "help") == 0) {
+ ipmi_lan_usage();
+ return 0;
+ }
+ ipmi_idracvalidator_command(intf);
+ if (!IsLANSupported()) {
+ lprintf(LOG_ERR, "lan is not supported on this system.");
+ return -1;
+ } else if (strncmp(argv[current_arg], "set\0", 4) == 0) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ ipmi_lan_usage();
+ return -1;
+ }
+ if (iDRAC_FLAG == IDRAC_12G) {
+ nic_selection = get_nic_selection_mode_12g(intf, current_arg, argv,
+ nic_set);
+ if (INVALID == nic_selection) {
+ ipmi_lan_usage();
+ return -1;
+ } else if (INVAILD_FAILOVER_MODE == nic_selection) {
+ lprintf(LOG_ERR, INVAILD_FAILOVER_MODE_STRING);
+ return (-1);
+ } else if (INVAILD_FAILOVER_MODE_SETTINGS == nic_selection) {
+ lprintf(LOG_ERR, INVAILD_FAILOVER_MODE_SET);
+ return (-1);
+ } else if (INVAILD_SHARED_MODE == nic_selection) {
+ lprintf(LOG_ERR, INVAILD_SHARED_MODE_SET_STRING);
+ return (-1);
+ }
+ rc = ipmi_lan_set_nic_selection_12g(intf,nic_set);
+ } else {
+ nic_selection = get_nic_selection_mode(current_arg, argv);
+ if (INVALID == nic_selection) {
+ ipmi_lan_usage();
+ return -1;
+ }
+ if (IMC_IDRAC_11G_MODULAR == IMC_Type) {
+ lprintf(LOG_ERR, INVAILD_SHARED_MODE_SET_STRING);
+ return (-1);
+ }
+ rc = ipmi_lan_set_nic_selection(intf,nic_selection);
+ }
+ return 0;
+ } else if (strncmp(argv[current_arg], "get\0", 4) == 0) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ rc = ipmi_lan_get_nic_selection(intf);
+ return rc;
+ } else if (strncmp(argv[current_arg], "active\0", 7) == 0) {
+ rc = ipmi_lan_get_active_nic(intf);
+ return rc;
+ } else {
+ ipmi_lan_usage();
+ }
+ } else {
+ ipmi_lan_usage();
+ return -1;
+ }
+ return rc;
+}
+
+static int
+IsLANSupported()
+{
+ if (IMC_IDRAC_11G_MODULAR == IMC_Type) {
+ return 0;
+ }
+ return 1;
+}
+
+int
+get_nic_selection_mode_12g(struct ipmi_intf* intf,int current_arg,
+ char ** argv, char *nic_set)
+{
+ /* First get the current settings. */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ int failover = 0;
+ int nic_selection_mode = 0;
+ uint8_t input_length = 0;
+ uint8_t msg_data[30];
+
+ input_length = 0;
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_NIC_SELECTION_12G_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting nic selection");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting nic selection (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ nic_set[0] = rsp->data[0];
+ nic_set[1] = rsp->data[1];
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "dedicated\0", 10) == 0) {
+ nic_set[0] = 1;
+ nic_set[1] = 0;
+ return 0;
+ }
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "shared\0", 7) == 0) {
+ /* placeholder */
+ } else {
+ return INVALID;
+ }
+
+ current_arg++;
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "with\0", 5) == 0) {
+ /* placeholder */
+ } else {
+ return INVALID;
+ }
+
+ current_arg++;
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "failover\0", 9) == 0) {
+ failover = 1;
+ }
+ if (failover) {
+ current_arg++;
+ }
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "lom1\0", 5) == 0) {
+ if (IMC_IDRAC_12G_MODULAR == IMC_Type) {
+ return INVAILD_SHARED_MODE;
+ }
+ if (failover) {
+ if (nic_set[0] == 2) {
+ return INVAILD_FAILOVER_MODE;
+ } else if (nic_set[0] == 1) {
+ return INVAILD_FAILOVER_MODE_SETTINGS;
+ }
+ nic_set[1] = 2;
+ } else {
+ nic_set[0] = 2;
+ if (nic_set[1] == 2) {
+ nic_set[1] = 0;
+ }
+ }
+ return 0;
+ } else if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "lom2\0", 5) == 0) {
+ if (IMC_IDRAC_12G_MODULAR == IMC_Type) {
+ return INVAILD_SHARED_MODE;
+ }
+ if (failover) {
+ if (nic_set[0] == 3) {
+ return INVAILD_FAILOVER_MODE;
+ } else if(nic_set[0] == 1) {
+ return INVAILD_FAILOVER_MODE_SETTINGS;
+ }
+ nic_set[1] = 3;
+ } else {
+ nic_set[0] = 3;
+ if (nic_set[1] == 3) {
+ nic_set[1] = 0;
+ }
+ }
+ return 0;
+ } else if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "lom3\0", 5) == 0) {
+ if (IMC_IDRAC_12G_MODULAR == IMC_Type) {
+ return INVAILD_SHARED_MODE;
+ }
+ if (failover) {
+ if (nic_set[0] == 4) {
+ return INVAILD_FAILOVER_MODE;
+ } else if(nic_set[0] == 1) {
+ return INVAILD_FAILOVER_MODE_SETTINGS;
+ }
+ nic_set[1] = 4;
+ } else {
+ nic_set[0] = 4;
+ if (nic_set[1] == 4) {
+ nic_set[1] = 0;
+ }
+ }
+ return 0;
+ } else if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "lom4\0", 5) == 0) {
+ if (IMC_IDRAC_12G_MODULAR == IMC_Type) {
+ return INVAILD_SHARED_MODE;
+ }
+ if (failover) {
+ if (nic_set[0] == 5) {
+ return INVAILD_FAILOVER_MODE;
+ } else if(nic_set[0] == 1) {
+ return INVAILD_FAILOVER_MODE_SETTINGS;
+ }
+ nic_set[1] = 5;
+ } else {
+ nic_set[0] = 5;
+ if (nic_set[1] == 5) {
+ nic_set[1] = 0;
+ }
+ }
+ return 0;
+ } else if (failover && argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "none\0", 5) == 0) {
+ if (IMC_IDRAC_12G_MODULAR == IMC_Type) {
+ return INVAILD_SHARED_MODE;
+ }
+ if (failover) {
+ if (nic_set[0] == 1) {
+ return INVAILD_FAILOVER_MODE_SETTINGS;
+ }
+ nic_set[1] = 0;
+ }
+ return 0;
+ } else if (failover && argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "all\0", 4) == 0) {
+ /* placeholder */
+ } else {
+ return INVALID;
+ }
+
+ current_arg++;
+ if (failover && argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "loms\0", 5) == 0) {
+ if (IMC_IDRAC_12G_MODULAR == IMC_Type) {
+ return INVAILD_SHARED_MODE;
+ }
+ if (nic_set[0] == 1) {
+ return INVAILD_FAILOVER_MODE_SETTINGS;
+ }
+ nic_set[1] = 6;
+ return 0;
+ }
+ return INVALID;
+}
+
+static int
+get_nic_selection_mode(int current_arg, char ** argv)
+{
+ int nic_selection_mode = 0;
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "dedicated\0", 10) == 0) {
+ return DEDICATED;
+ }
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "shared\0", 7) == 0) {
+ if (argv[current_arg+1] == NULL) {
+ return SHARED;
+ }
+ }
+
+ current_arg++;
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "with\0", 5) == 0) {
+ /* place holder */
+ } else {
+ return INVALID;
+ }
+
+ current_arg++;
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "failover\0", 9) == 0) {
+ /* place holder */
+ } else {
+ return INVALID;
+ }
+
+ current_arg++;
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "lom2\0", 5) == 0) {
+ return SHARED_WITH_FAILOVER_LOM2;
+ } else if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "all\0", 4) == 0) {
+ /* place holder */
+ } else {
+ return INVALID;
+ }
+
+ current_arg++;
+ if (argv[current_arg] != NULL
+ && strncmp(argv[current_arg], "loms\0", 5) == 0) {
+ return SHARED_WITH_FAILOVER_ALL_LOMS;
+ }
+ return INVALID;
+}
+
+static int
+ipmi_lan_set_nic_selection_12g(struct ipmi_intf * intf, uint8_t * nic_selection)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t input_length = 0;
+ uint8_t msg_data[30];
+
+ input_length = 0;
+ msg_data[input_length++] = nic_selection[0];
+ msg_data[input_length++] = nic_selection[1];
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = SET_NIC_SELECTION_12G_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in setting nic selection");
+ return -1;
+ } else if( (nic_selection[0] == 1)
+ && ((iDRAC_FLAG == IDRAC_12G) && (rsp->ccode == LICENSE_NOT_SUPPORTED))) {
+ /* Check license only for setting the dedicated nic. */
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in setting nic selection (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ printf("configured successfully");
+ return 0;
+}
+
+static int
+ipmi_lan_set_nic_selection(struct ipmi_intf * intf, uint8_t nic_selection)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t input_length = 0;
+ uint8_t msg_data[30];
+
+ input_length = 0;
+ msg_data[input_length++] = nic_selection;
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = SET_NIC_SELECTION_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in setting nic selection");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in setting nic selection (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ printf("configured successfully");
+ return 0;
+}
+
+static int
+ipmi_lan_get_nic_selection(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t input_length=0;
+ uint8_t msg_data[30];
+ uint8_t nic_selection=-1;
+ uint8_t nic_selection_failover = 0;
+
+ input_length = 0;
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ if (iDRAC_FLAG == IDRAC_12G) {
+ req.msg.cmd = GET_NIC_SELECTION_12G_CMD;
+ } else {
+ req.msg.cmd = GET_NIC_SELECTION_CMD;
+ }
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting nic selection");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting nic selection (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ nic_selection = rsp->data[0];
+ if (iDRAC_FLAG == IDRAC_12G) {
+ nic_selection_failover = rsp->data[1];
+ if ((nic_selection < 6) && (nic_selection > 0)
+ && (nic_selection_failover < 7)) {
+ if(nic_selection == 1) {
+ printf("%s\n",NIC_Selection_Mode_String_12g[nic_selection-1]);
+ } else if(nic_selection) {
+ printf("Shared LOM : %s\n",
+ NIC_Selection_Mode_String_12g[nic_selection-1]);
+ if(nic_selection_failover == 0) {
+ printf("Failover LOM : None\n");
+ } else if(nic_selection_failover >= 2 && nic_selection_failover <= 6) {
+ printf("Failover LOM : %s\n",
+ NIC_Selection_Mode_String_12g[nic_selection_failover + 3]);
+ }
+ }
+ } else {
+ lprintf(LOG_ERR, "Error Outof bond Value received (%d) (%d)",
+ nic_selection,nic_selection_failover);
+ return -1;
+ }
+ } else {
+ printf("%s\n",NIC_Selection_Mode_String[nic_selection]);
+ }
+ return 0;
+}
+
+static int
+ipmi_lan_get_active_nic(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t active_nic=0;
+ uint8_t current_lom =0;
+ uint8_t input_length=0;
+ uint8_t msg_data[30];
+
+ input_length = 0;
+ msg_data[input_length++] = 0; /* Get Status */
+ msg_data[input_length++] = 0; /* Reserved */
+ msg_data[input_length++] = 0; /* Reserved */
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_ACTIVE_NIC_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting Active LOM Status");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting Active LOM Status (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ current_lom = rsp->data[0];
+ input_length = 0;
+ msg_data[input_length++] = 1; /* Get Link status */
+ msg_data[input_length++] = 0; /* Reserved */
+ msg_data[input_length++] = 0; /* Reserved */
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_ACTIVE_NIC_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting Active LOM Status");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting Active LOM Status (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ active_nic = rsp->data[1];
+ if (current_lom < 6 && active_nic) {
+ printf("\n%s\n", AciveLOM_String[current_lom]);
+ } else {
+ printf("\n%s\n", AciveLOM_String[0]);
+ }
+ return 0;
+}
+
+static void
+ipmi_lan_usage(void)
+{
+ /* TODO:
+ * - rewrite
+ * - review
+ * - make it fit into 80 chars per line
+ * - this ``shared with Failover None).'' seems like a typo
+ */
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lan set <Mode>");
+ lprintf(LOG_NOTICE,
+" sets the NIC Selection Mode :");
+ lprintf(LOG_NOTICE,
+" on iDRAC12g :");
+ lprintf(LOG_NOTICE,
+" dedicated, shared with lom1, shared with lom2,shared with lom3,shared");
+ lprintf(LOG_NOTICE,
+" with lom4,shared with failover lom1,shared with failover lom2,shared");
+ lprintf(LOG_NOTICE,
+" with failover lom3,shared with failover lom4,shared with Failover all");
+ lprintf(LOG_NOTICE,
+" loms, shared with Failover None).");
+ lprintf(LOG_NOTICE,
+" on other systems :");
+ lprintf(LOG_NOTICE,
+" dedicated, shared, shared with failover lom2,");
+ lprintf(LOG_NOTICE,
+" shared with Failover all loms.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lan get ");
+ lprintf(LOG_NOTICE,
+" on iDRAC12g :");
+ lprintf(LOG_NOTICE,
+" returns the current NIC Selection Mode (dedicated, shared with lom1, shared");
+ lprintf(LOG_NOTICE,
+" with lom2, shared with lom3, shared with lom4,shared with failover lom1,");
+ lprintf(LOG_NOTICE,
+" shared with failover lom2,shared with failover lom3,shared with failover");
+ lprintf(LOG_NOTICE,
+" lom4,shared with Failover all loms,shared with Failover None).");
+ lprintf(LOG_NOTICE,
+" on other systems :");
+ lprintf(LOG_NOTICE,
+" dedicated, shared, shared with failover,");
+ lprintf(LOG_NOTICE,
+" lom2, shared with Failover all loms.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" lan get active");
+ lprintf(LOG_NOTICE,
+" returns the current active NIC (dedicated, LOM1, LOM2, LOM3, LOM4).");
+ lprintf(LOG_NOTICE,
+"");
+}
+/*
+ * Function Name: ipmi_delloem_powermonitor_main
+ *
+ * Description: This function processes the delloem powermonitor command
+ * Input: intf - ipmi interface
+ * argc - no of arguments
+ * argv - argument string array
+ * Output:
+ *
+ * Return: return code 0 - success
+ * -1 - failure
+ */
+static int
+ipmi_delloem_powermonitor_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ current_arg++;
+ if (argc > 1 && strcmp(argv[current_arg], "help") == 0) {
+ ipmi_powermonitor_usage();
+ return 0;
+ }
+ ipmi_idracvalidator_command(intf);
+ if (argc == 1) {
+ rc = ipmi_powermgmt(intf);
+ } else if (strncmp(argv[current_arg], "status\0", 7) == 0) {
+ rc = ipmi_powermgmt(intf);
+ } else if (strncmp(argv[current_arg], "clear\0", 6) == 0) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ ipmi_powermonitor_usage();
+ return -1;
+ } else if (strncmp(argv[current_arg], "peakpower\0", 10) == 0) {
+ rc = ipmi_powermgmt_clear(intf, 1);
+ } else if (strncmp(argv[current_arg], "cumulativepower\0", 16) == 0) {
+ rc = ipmi_powermgmt_clear(intf, 0);
+ } else {
+ ipmi_powermonitor_usage();
+ return -1;
+ }
+ } else if (strncmp(argv[current_arg], "powerconsumption\0", 17) == 0) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ rc = ipmi_print_get_power_consmpt_data(intf,watt);
+ } else if (strncmp(argv[current_arg], "watt\0", 5) == 0) {
+ rc = ipmi_print_get_power_consmpt_data(intf, watt);
+ } else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) {
+ rc = ipmi_print_get_power_consmpt_data(intf, btuphr);
+ } else {
+ ipmi_powermonitor_usage();
+ return -1;
+ }
+ } else if (strncmp(argv[current_arg], "powerconsumptionhistory\0", 23) == 0) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ rc = ipmi_print_power_consmpt_history(intf,watt);
+ } else if (strncmp(argv[current_arg], "watt\0", 5) == 0) {
+ rc = ipmi_print_power_consmpt_history(intf, watt);
+ } else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) {
+ rc = ipmi_print_power_consmpt_history(intf, btuphr);
+ } else {
+ ipmi_powermonitor_usage();
+ return -1;
+ }
+ } else if (strncmp(argv[current_arg], "getpowerbudget\0", 15) == 0) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ rc=ipmi_print_power_cap(intf,watt);
+ } else if (strncmp(argv[current_arg], "watt\0", 5) == 0) {
+ rc = ipmi_print_power_cap(intf, watt);
+ } else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) {
+ rc = ipmi_print_power_cap(intf, btuphr);
+ } else {
+ ipmi_powermonitor_usage();
+ return -1;
+ }
+ } else if (strncmp(argv[current_arg], "setpowerbudget\0", 15) == 0) {
+ int val;
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ ipmi_powermonitor_usage();
+ return -1;
+ }
+ if (strchr(argv[current_arg], '.')) {
+ lprintf(LOG_ERR,
+ "Cap value in Watts, Btu/hr or percent should be whole number");
+ return -1;
+ }
+ if (str2int(argv[current_arg], &val) != 0) {
+ lprintf(LOG_ERR, "Given capacity value '%s' is invalid.",
+ argv[current_arg]);
+ return (-1);
+ }
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ ipmi_powermonitor_usage();
+ } else if (strncmp(argv[current_arg], "watt\0", 5) == 0) {
+ rc = ipmi_set_power_cap(intf,watt,val);
+ } else if (strncmp(argv[current_arg], "btuphr\0", 7) == 0) {
+ rc = ipmi_set_power_cap(intf, btuphr,val);
+ } else if (strncmp(argv[current_arg], "percent\0", 8) == 0) {
+ rc = ipmi_set_power_cap(intf,percent,val);
+ } else {
+ ipmi_powermonitor_usage();
+ return -1;
+ }
+ } else if (strncmp(argv[current_arg], "enablepowercap\0", 15) == 0) {
+ ipmi_set_power_capstatus_command(intf,1);
+ } else if (strncmp(argv[current_arg], "disablepowercap\0", 16) == 0) {
+ ipmi_set_power_capstatus_command(intf,0);
+ } else {
+ ipmi_powermonitor_usage();
+ return -1;
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_time_to_str
+ *
+ * Description: This function converts ipmi time format into gmtime format
+ * Input: rawTime - ipmi time format
+ * Output: strTime - gmtime format
+ *
+ * Return:
+ */
+static void
+ipmi_time_to_str(time_t rawTime, char * strTime)
+{
+ struct tm *tm;
+ char *temp;
+ tm = gmtime(&rawTime);
+ temp = asctime(tm);
+ strcpy(strTime,temp);
+}
+/*
+ * Function Name: ipmi_get_sensor_reading
+ *
+ * Description: This function retrieves a raw sensor reading
+ * Input: sensorOwner - sensor owner id
+ * sensorNumber - sensor id
+ * intf - ipmi interface
+ * Output: sensorReadingData - ipmi response structure
+ * Return: 1 on error
+ * 0 if successful
+ */
+static int
+ipmi_get_sensor_reading(struct ipmi_intf *intf, unsigned char sensorNumber,
+ SensorReadingType* pSensorReadingData)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ int rc = 0;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_SENSOR_READING;
+ req.msg.data = &sensorNumber;
+ req.msg.data_len = 1;
+ if (pSensorReadingData == NULL) {
+ return -1;
+ }
+ memset(pSensorReadingData, 0, sizeof(SensorReadingType));
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ return 1;
+ } else if (rsp->ccode > 0) {
+ return 1;
+ }
+ memcpy(pSensorReadingData, rsp->data, sizeof(SensorReadingType));
+ /* if there is an error transmitting ipmi command, return error */
+ if (rsp->ccode != 0) {
+ rc = 1;
+ }
+ /* if sensor messages are disabled, return error*/
+ if ((!(rsp->data[1]& 0xC0)) || ((rsp->data[1] & 0x20))) {
+ rc =1;
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_get_power_capstatus_command
+ *
+ * Description: This function gets the power cap status
+ * Input: intf - ipmi interface
+ * Global: PowercapSetable_flag - power cap status
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_get_power_capstatus_command(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint8_t data[2];
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_DELL_POWER_CAP_STATUS;
+ req.msg.data_len = 2;
+ req.msg.data = data;
+ data[0] = 01;
+ data[1] = 0xFF;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error getting powercap status");
+ return -1;
+ } else if((iDRAC_FLAG == IDRAC_12G) && (rsp->ccode == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1; /* Return Error as unlicensed */
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error getting powercap statusr: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ if (rsp->data[0] & 0x02) {
+ PowercapSetable_flag=1;
+ }
+ if (rsp->data[0] & 0x01) {
+ PowercapstatusFlag=1;
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_set_power_capstatus_command
+ *
+ * Description: This function sets the power cap status
+ * Input: intf - ipmi interface
+ * val - power cap status
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_set_power_capstatus_command(struct ipmi_intf * intf, uint8_t val)
+{
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint8_t data[2];
+ if (ipmi_get_power_capstatus_command(intf) < 0) {
+ return -1;
+ }
+ if (PowercapSetable_flag != 1) {
+ lprintf(LOG_ERR, "Can not set powercap on this system");
+ return -1;
+ }
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_DELL_POWER_CAP_STATUS;
+ req.msg.data_len = 2;
+ req.msg.data = data;
+ data[0] = 00;
+ data[1] = val;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error setting powercap status");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G) && (rsp->ccode == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1; /* return unlicensed Error code */
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error setting powercap statusr: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_powermgmt
+ *
+ * Description: This function print the powermonitor details
+ * Input: intf - ipmi interface
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_powermgmt(struct ipmi_intf * intf)
+{
+ time_t now;
+ struct tm* tm;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[2];
+ uint32_t cumStartTimeConv;
+ uint32_t cumReadingConv;
+ uint32_t maxPeakStartTimeConv;
+ uint32_t ampPeakTimeConv;
+ uint16_t ampReadingConv;
+ uint32_t wattPeakTimeConv;
+ uint32_t wattReadingConv;
+ uint32_t bmctimeconv;
+ uint32_t * bmctimeconvval;
+
+ IPMI_POWER_MONITOR * pwrMonitorInfo;
+
+ char cumStartTime[26];
+ char maxPeakStartTime[26];
+ char ampPeakTime[26];
+ char wattPeakTime[26];
+ char bmctime[26];
+
+ int ampReading;
+ int ampReadingRemainder;
+ int remainder;
+ int wattReading;
+
+ now = time(0);
+ tm = gmtime(&now);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_CMD_GET_SEL_TIME;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error getting BMC time info.");
+ return -1;
+ }
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR,
+ "Error getting power management information, return code %x",
+ rsp->ccode);
+ return -1;
+ }
+ bmctimeconvval=(uint32_t*)rsp->data;
+# if WORDS_BIGENDIAN
+ bmctimeconv=BSWAP_32(*bmctimeconvval);
+# else
+ bmctimeconv=*bmctimeconvval;
+# endif
+
+ /* get powermanagement info*/
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0x0;
+ req.msg.cmd = GET_PWRMGMT_INFO_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ memset(msg_data, 0, 2);
+ msg_data[0] = 0x07;
+ msg_data[1] = 0x01;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error getting power management information.");
+ return -1;
+ }
+
+ if((iDRAC_FLAG == IDRAC_12G) && (rsp->ccode == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if ((rsp->ccode == 0xc1)||(rsp->ccode == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting power management information: "
+ "Command not supported on this system.");
+ return -1;
+ }else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR,
+ "Error getting power management information, return code %x",
+ rsp->ccode);
+ return -1;
+ }
+
+ pwrMonitorInfo = (IPMI_POWER_MONITOR*)rsp->data;
+# if WORDS_BIGENDIAN
+ cumStartTimeConv = BSWAP_32(pwrMonitorInfo->cumStartTime);
+ cumReadingConv = BSWAP_32(pwrMonitorInfo->cumReading);
+ maxPeakStartTimeConv = BSWAP_32(pwrMonitorInfo->maxPeakStartTime);
+ ampPeakTimeConv = BSWAP_32(pwrMonitorInfo->ampPeakTime);
+ ampReadingConv = BSWAP_16(pwrMonitorInfo->ampReading);
+ wattPeakTimeConv = BSWAP_32(pwrMonitorInfo->wattPeakTime);
+ wattReadingConv = BSWAP_16(pwrMonitorInfo->wattReading);
+# else
+ cumStartTimeConv = pwrMonitorInfo->cumStartTime;
+ cumReadingConv = pwrMonitorInfo->cumReading;
+ maxPeakStartTimeConv = pwrMonitorInfo->maxPeakStartTime;
+ ampPeakTimeConv = pwrMonitorInfo->ampPeakTime;
+ ampReadingConv = pwrMonitorInfo->ampReading;
+ wattPeakTimeConv = pwrMonitorInfo->wattPeakTime;
+ wattReadingConv = pwrMonitorInfo->wattReading;
+# endif
+
+ ipmi_time_to_str(cumStartTimeConv, cumStartTime);
+ ipmi_time_to_str(maxPeakStartTimeConv, maxPeakStartTime);
+ ipmi_time_to_str(ampPeakTimeConv, ampPeakTime);
+ ipmi_time_to_str(wattPeakTimeConv, wattPeakTime);
+ ipmi_time_to_str(bmctimeconv, bmctime);
+ now = time(0);
+
+ remainder = (cumReadingConv % 1000);
+ cumReadingConv = cumReadingConv / 1000;
+ remainder = (remainder + 50) / 100;
+
+ ampReading = ampReadingConv;
+ ampReadingRemainder = ampReading%10;
+ ampReading = ampReading/10;
+
+ wattReading = wattReadingConv;
+
+ printf("Power Tracking Statistics\n");
+ printf("Statistic : Cumulative Energy Consumption\n");
+ printf("Start Time : %s", cumStartTime);
+ printf("Finish Time : %s", bmctime);
+ printf("Reading : %d.%d kWh\n\n", cumReadingConv, remainder);
+
+ printf("Statistic : System Peak Power\n");
+ printf("Start Time : %s", maxPeakStartTime);
+ printf("Peak Time : %s", wattPeakTime);
+ printf("Peak Reading : %d W\n\n", wattReading);
+
+ printf("Statistic : System Peak Amperage\n");
+ printf("Start Time : %s", maxPeakStartTime);
+ printf("Peak Time : %s", ampPeakTime);
+ printf("Peak Reading : %d.%d A\n", ampReading, ampReadingRemainder);
+ return 0;
+}
+/*
+ * Function Name: ipmi_powermgmt_clear
+ *
+ * Description: This function clears peakpower / cumulativepower value
+ * Input: intf - ipmi interface
+ * clearValue - peakpower / cumulativepower
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_powermgmt_clear(struct ipmi_intf * intf, uint8_t clearValue)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t clearType = 1;
+ uint8_t msg_data[3];
+ if (clearValue) {
+ clearType = 2;
+ }
+ /* clear powermanagement info*/
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = CLEAR_PWRMGMT_INFO_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+ memset(msg_data, 0, 3);
+ msg_data[0] = 0x07;
+ msg_data[1] = 0x01;
+ msg_data[2] = clearType;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error clearing power values.");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G)
+ && (rsp->ccode == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if (rsp->ccode == 0xc1) {
+ lprintf(LOG_ERR,
+ "Error clearing power values, command not supported on this system.");
+ return -1;
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Error clearing power values: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: watt_to_btuphr_conversion
+ *
+ * Description: This function converts the power value in watt to btuphr
+ * Input: powerinwatt - power in watt
+ *
+ * Output: power in btuphr
+ *
+ * Return:
+ */
+static uint64_t
+watt_to_btuphr_conversion(uint32_t powerinwatt)
+{
+ uint64_t powerinbtuphr;
+ powerinbtuphr=(3.413 * powerinwatt);
+ return(powerinbtuphr);
+}
+/*
+ * Function Name: btuphr_to_watt_conversion
+ *
+ * Description: This function converts the power value in btuphr to watt
+ * Input: powerinbtuphr - power in btuphr
+ *
+ * Output: power in watt
+ *
+ * Return:
+ */
+static uint32_t
+btuphr_to_watt_conversion(uint64_t powerinbtuphr)
+{
+ uint32_t powerinwatt;
+ /*returning the floor value*/
+ powerinwatt= (powerinbtuphr / 3.413);
+ return (powerinwatt);
+}
+/*
+ * Function Name: ipmi_get_power_headroom_command
+ *
+ * Description: This function prints the Power consumption information
+ * Input: intf - ipmi interface
+ * unit - watt / btuphr
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_get_power_headroom_command(struct ipmi_intf * intf,uint8_t unit)
+{
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint64_t peakpowerheadroombtuphr;
+ uint64_t instantpowerhearoom;
+
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_PWR_HEADROOM_CMD;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error getting power headroom status");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G)
+ && (rsp->ccode == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if ((rsp->ccode == 0xc1) || (rsp->ccode == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting power headroom status: "
+ "Command not supported on this system ");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error getting power headroom status: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 1) {
+ /* need to look into */
+ printf("power headroom Data : %x %x %x %x ", rsp->data[0],
+ rsp->data[1], rsp->data[2], rsp->data[3]);
+ }
+ powerheadroom= *(( POWER_HEADROOM *)rsp->data);
+# if WORDS_BIGENDIAN
+ powerheadroom.instheadroom = BSWAP_16(powerheadroom.instheadroom);
+ powerheadroom.peakheadroom = BSWAP_16(powerheadroom.peakheadroom);
+# endif
+ printf("Headroom\n");
+ printf("Statistic Reading\n");
+ if (unit == btuphr) {
+ peakpowerheadroombtuphr = watt_to_btuphr_conversion(powerheadroom.peakheadroom);
+ instantpowerhearoom = watt_to_btuphr_conversion(powerheadroom.instheadroom);
+ printf("System Instantaneous Headroom : %lld BTU/hr\n",
+ instantpowerhearoom);
+ printf("System Peak Headroom : %lld BTU/hr\n",
+ peakpowerheadroombtuphr);
+ } else {
+ printf("System Instantaneous Headroom : %d W\n",
+ powerheadroom.instheadroom);
+ printf("System Peak Headroom : %d W\n",
+ powerheadroom.peakheadroom);
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_get_power_consumption_data
+ *
+ * Description: This function updates the instant Power consumption information
+ * Input: intf - ipmi interface
+ * Output: power consumption current reading
+ * Assumption value will be in Watt.
+ *
+ * Return:
+ */
+static int
+ipmi_get_power_consumption_data(struct ipmi_intf * intf,uint8_t unit)
+{
+ SensorReadingType sensorReadingData;
+
+ struct ipmi_rs * rsp=NULL;
+ struct sdr_record_list *sdr;
+ int readingbtuphr = 0;
+ int warning_threshbtuphr = 0;
+ int failure_threshbtuphr = 0;
+ int status = 0;
+ int sensor_number = 0;
+ sdr = ipmi_sdr_find_sdr_byid(intf, "System Level");
+ if (sdr == NULL) {
+ lprintf(LOG_ERR,
+ "Error : Can not access the System Level sensor data");
+ return -1;
+ }
+ sensor_number = sdr->record.common->keys.sensor_num;
+ ipmi_get_sensor_reading(intf,sensor_number,&sensorReadingData);
+ rsp = ipmi_sdr_get_sensor_thresholds(intf,
+ sdr->record.common->keys.sensor_num,
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+ if (rsp == NULL || rsp->ccode != 0) {
+ lprintf(LOG_ERR,
+ "Error : Can not access the System Level sensor data");
+ return -1;
+ }
+ readingbtuphr = sdr_convert_sensor_reading(sdr->record.full,
+ sensorReadingData.sensorReading);
+ warning_threshbtuphr = sdr_convert_sensor_reading(sdr->record.full,
+ rsp->data[4]);
+ failure_threshbtuphr = sdr_convert_sensor_reading(sdr->record.full,
+ rsp->data[5]);
+
+ printf("System Board System Level\n");
+ if (unit == btuphr) {
+ readingbtuphr = watt_to_btuphr_conversion(readingbtuphr);
+ warning_threshbtuphr = watt_to_btuphr_conversion(warning_threshbtuphr);
+ failure_threshbtuphr = watt_to_btuphr_conversion( failure_threshbtuphr);
+
+ printf("Reading : %d BTU/hr\n", readingbtuphr);
+ printf("Warning threshold : %d BTU/hr\n", warning_threshbtuphr);
+ printf("Failure threshold : %d BTU/hr\n", failure_threshbtuphr);
+ } else {
+ printf("Reading : %d W \n",readingbtuphr);
+ printf("Warning threshold : %d W \n",(warning_threshbtuphr));
+ printf("Failure threshold : %d W \n",(failure_threshbtuphr));
+ }
+ return status;
+}
+/*
+ * Function Name: ipmi_get_instan_power_consmpt_data
+ *
+ * Description: This function updates the instant Power consumption information
+ * Input: intf - ipmi interface
+ * Output: instpowerconsumptiondata - instant Power consumption information
+ *
+ * Return:
+ */
+static int
+ipmi_get_instan_power_consmpt_data(struct ipmi_intf * intf,
+ IPMI_INST_POWER_CONSUMPTION_DATA * instpowerconsumptiondata)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req={0};
+ uint8_t msg_data[2];
+ /*get instantaneous power consumption command*/
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = GET_PWR_CONSUMPTION_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+ memset(msg_data, 0, 2);
+ msg_data[0] = 0x0A;
+ msg_data[1] = 0x00;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error getting instantaneous power consumption data .");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G)
+ && (rsp->ccode == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if ((rsp->ccode == 0xc1) || (rsp->ccode == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting instantaneous power consumption data: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Error getting instantaneous power consumption data: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ *instpowerconsumptiondata = *((IPMI_INST_POWER_CONSUMPTION_DATA *)(rsp->data));
+#if WORDS_BIGENDIAN
+ instpowerconsumptiondata->instanpowerconsumption = BSWAP_16(instpowerconsumptiondata->instanpowerconsumption);
+ instpowerconsumptiondata->instanApms = BSWAP_16(instpowerconsumptiondata->instanApms);
+ instpowerconsumptiondata->resv1 = BSWAP_16(instpowerconsumptiondata->resv1);
+#endif
+ return 0;
+}
+/*
+ * Function Name: ipmi_print_get_instan_power_Amps_data
+ *
+ * Description: This function prints the instant Power consumption information
+ * Input: instpowerconsumptiondata - instant Power consumption information
+ * Output:
+ *
+ * Return:
+ */
+static void
+ipmi_print_get_instan_power_Amps_data(IPMI_INST_POWER_CONSUMPTION_DATA instpowerconsumptiondata)
+{
+ uint16_t intampsval=0;
+ uint16_t decimalampsval=0;
+ if (instpowerconsumptiondata.instanApms > 0) {
+ decimalampsval = (instpowerconsumptiondata.instanApms % 10);
+ intampsval = instpowerconsumptiondata.instanApms / 10;
+ }
+ printf("\nAmperage value: %d.%d A \n", intampsval, decimalampsval);
+}
+/*
+ * Function Name: ipmi_print_get_power_consmpt_data
+ *
+ * Description: This function prints the Power consumption information
+ * Input: intf - ipmi interface
+ * unit - watt / btuphr
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_print_get_power_consmpt_data(struct ipmi_intf * intf, uint8_t unit)
+{
+ int rc = 0;
+ IPMI_INST_POWER_CONSUMPTION_DATA instpowerconsumptiondata = {0,0,0,0};
+ printf("\nPower consumption information\n");
+ rc = ipmi_get_power_consumption_data(intf, unit);
+ if (rc == (-1)) {
+ return rc;
+ }
+ rc = ipmi_get_instan_power_consmpt_data(intf, &instpowerconsumptiondata);
+ if (rc == (-1)) {
+ return rc;
+ }
+ ipmi_print_get_instan_power_Amps_data(instpowerconsumptiondata);
+ rc = ipmi_get_power_headroom_command(intf, unit);
+ if (rc == (-1)) {
+ return rc;
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_get_avgpower_consmpt_history
+ *
+ * Description: This function updates the average power consumption information
+ * Input: intf - ipmi interface
+ * Output: pavgpower- average power consumption information
+ *
+ * Return:
+ */
+static int
+ipmi_get_avgpower_consmpt_history(struct ipmi_intf * intf,
+ IPMI_AVGPOWER_CONSUMP_HISTORY * pavgpower)
+{
+ int rc;
+ uint8_t *rdata;
+ rc = ipmi_mc_getsysinfo(intf, 0xeb, 0, 0, sizeof(*pavgpower), pavgpower);
+ if (rc < 0) {
+ lprintf(LOG_ERR,
+ "Error getting average power consumption history data.");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G) && (rc == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting average power consumption history data: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rc != 0) {
+ lprintf(LOG_ERR,
+ "Error getting average power consumption history data: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 1) {
+ rdata = (void *)pavgpower;
+ printf("Average power consumption history data"
+ " :%x %x %x %x %x %x %x %x\n\n",
+ rdata[0], rdata[1], rdata[2], rdata[3],
+ rdata[4], rdata[5], rdata[6], rdata[7]);
+ }
+# if WORDS_BIGENDIAN
+ pavgpower->lastminutepower = BSWAP_16(pavgpower->lastminutepower);
+ pavgpower->lasthourpower = BSWAP_16(pavgpower->lasthourpower);
+ pavgpower->lastdaypower = BSWAP_16(pavgpower->lastdaypower);
+ pavgpower->lastweakpower = BSWAP_16(pavgpower->lastweakpower);
+# endif
+ return 0;
+}
+/*
+ * Function Name: ipmi_get_peakpower_consmpt_history
+ *
+ * Description: This function updates the peak power consumption information
+ * Input: intf - ipmi interface
+ * Output: pavgpower- peak power consumption information
+ *
+ * Return:
+ */
+static int
+ipmi_get_peakpower_consmpt_history(struct ipmi_intf * intf,
+ IPMI_POWER_CONSUMP_HISTORY * pstPeakpower)
+{
+ uint8_t *rdata;
+ int rc;
+ rc = ipmi_mc_getsysinfo(intf, 0xec, 0, 0, sizeof(*pstPeakpower),
+ pstPeakpower);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting peak power consumption history data.");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G) && (rc == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting peak power consumption history data: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rc != 0) {
+ lprintf(LOG_ERR, "Error getting peak power consumption history data: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 1) {
+ rdata = (void *)pstPeakpower;
+ printf("Peak power consmhistory Data : "
+ "%x %x %x %x %x %x %x %x %x %x\n "
+ "%x %x %x %x %x %x %x %x %x %x %x %x %x %x\n\n",
+ rdata[0], rdata[1], rdata[2], rdata[3],
+ rdata[4], rdata[5], rdata[6], rdata[7],
+ rdata[8], rdata[9], rdata[10], rdata[11],
+ rdata[12], rdata[13], rdata[14], rdata[15],
+ rdata[16], rdata[17], rdata[18], rdata[19],
+ rdata[20], rdata[21], rdata[22], rdata[23]);
+ }
+# if WORDS_BIGENDIAN
+ pstPeakpower->lastminutepower = BSWAP_16(pstPeakpower->lastminutepower);
+ pstPeakpower->lasthourpower = BSWAP_16(pstPeakpower->lasthourpower);
+ pstPeakpower->lastdaypower = BSWAP_16(pstPeakpower->lastdaypower);
+ pstPeakpower->lastweakpower = BSWAP_16(pstPeakpower->lastweakpower);
+ pstPeakpower->lastminutepowertime = BSWAP_32(pstPeakpower->lastminutepowertime);
+ pstPeakpower->lasthourpowertime = BSWAP_32(pstPeakpower->lasthourpowertime);
+ pstPeakpower->lastdaypowertime = BSWAP_32(pstPeakpower->lastdaypowertime);
+ pstPeakpower->lastweekpowertime = BSWAP_32(pstPeakpower->lastweekpowertime);
+#endif
+ return 0;
+}
+/*
+ * Function Name: ipmi_get_minpower_consmpt_history
+ *
+ * Description: This function updates the peak power consumption information
+ * Input: intf - ipmi interface
+ * Output: pavgpower- peak power consumption information
+ *
+ * Return:
+ */
+static int
+ipmi_get_minpower_consmpt_history(struct ipmi_intf * intf,
+ IPMI_POWER_CONSUMP_HISTORY * pstMinpower)
+{
+ uint8_t *rdata;
+ int rc;
+ rc = ipmi_mc_getsysinfo(intf, 0xed, 0, 0, sizeof(*pstMinpower),
+ pstMinpower);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting peak power consumption history data .");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G) && (rc == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting peak power consumption history data: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rc != 0) {
+ lprintf(LOG_ERR, "Error getting peak power consumption history data: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 1) {
+ rdata = (void *)pstMinpower;
+ printf("Peak power consmhistory Data : "
+ "%x %x %x %x %x %x %x %x %x %x\n "
+ "%x %x %x %x %x %x %x %x %x %x %x %x %x\n\n",
+ rdata[0], rdata[1], rdata[2], rdata[3],
+ rdata[4], rdata[5], rdata[6], rdata[7],
+ rdata[8], rdata[9], rdata[10], rdata[11],
+ rdata[12], rdata[13], rdata[14], rdata[15],
+ rdata[16], rdata[17], rdata[18], rdata[19],
+ rdata[20], rdata[21], rdata[22], rdata[23]);
+ }
+# if WORDS_BIGENDIAN
+ pstMinpower->lastminutepower = BSWAP_16(pstMinpower->lastminutepower);
+ pstMinpower->lasthourpower = BSWAP_16(pstMinpower->lasthourpower);
+ pstMinpower->lastdaypower = BSWAP_16(pstMinpower->lastdaypower);
+ pstMinpower->lastweakpower = BSWAP_16(pstMinpower->lastweakpower);
+ pstMinpower->lastminutepowertime = BSWAP_32(pstMinpower->lastminutepowertime);
+ pstMinpower->lasthourpowertime = BSWAP_32(pstMinpower->lasthourpowertime);
+ pstMinpower->lastdaypowertime = BSWAP_32(pstMinpower->lastdaypowertime);
+ pstMinpower->lastweekpowertime = BSWAP_32(pstMinpower->lastweekpowertime);
+# endif
+ return 0;
+}
+/*
+ * Function Name: ipmi_print_power_consmpt_history
+ *
+ * Description: This function print the average and peak power consumption information
+ * Input: intf - ipmi interface
+ * unit - watt / btuphr
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_print_power_consmpt_history(struct ipmi_intf * intf, int unit)
+{
+ char timestr[30];
+ uint32_t lastminutepeakpower;
+ uint32_t lasthourpeakpower;
+ uint32_t lastdaypeakpower;
+ uint32_t lastweekpeakpower;
+ uint64_t tempbtuphrconv;
+ int rc = 0;
+
+ IPMI_AVGPOWER_CONSUMP_HISTORY avgpower;
+ IPMI_POWER_CONSUMP_HISTORY stMinpower;
+ IPMI_POWER_CONSUMP_HISTORY stPeakpower;
+
+ rc = ipmi_get_avgpower_consmpt_history(intf, &avgpower);
+ if (rc == (-1)) {
+ return rc;
+ }
+
+ rc = ipmi_get_peakpower_consmpt_history(intf, &stPeakpower);
+ if (rc == (-1)) {
+ return rc;
+ }
+
+ rc = ipmi_get_minpower_consmpt_history(intf, &stMinpower);
+ if (rc == (-1)) {
+ return rc;
+ }
+ if (rc != 0) {
+ return rc;
+ }
+ printf("Power Consumption History\n\n");
+ /* The fields are alligned manually changing the spaces will alter
+ * the alignment*/
+ printf("Statistic Last Minute Last Hour "
+ "Last Day Last Week\n\n");
+ if (unit == btuphr) {
+ printf("Average Power Consumption ");
+ tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lastminutepower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lasthourpower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lastdaypower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(avgpower.lastweakpower);
+ printf("%4lld BTU/hr\n", tempbtuphrconv);
+
+ printf("Max Power Consumption ");
+ tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lastminutepower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lasthourpower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lastdaypower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(stPeakpower.lastweakpower);
+ printf("%4lld BTU/hr\n", tempbtuphrconv);
+
+ printf("Min Power Consumption ");
+ tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lastminutepower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lasthourpower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lastdaypower);
+ printf("%4lld BTU/hr ", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(stMinpower.lastweakpower);
+ printf("%4lld BTU/hr\n\n", tempbtuphrconv);
+ } else {
+ printf("Average Power Consumption ");
+ tempbtuphrconv = (avgpower.lastminutepower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (avgpower.lasthourpower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (avgpower.lastdaypower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv=(avgpower.lastweakpower);
+ printf("%4lld W \n", tempbtuphrconv);
+
+ printf("Max Power Consumption ");
+ tempbtuphrconv = (stPeakpower.lastminutepower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (stPeakpower.lasthourpower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (stPeakpower.lastdaypower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (stPeakpower.lastweakpower);
+ printf("%4lld W \n", tempbtuphrconv);
+
+ printf("Min Power Consumption ");
+ tempbtuphrconv = (stMinpower.lastminutepower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (stMinpower.lasthourpower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (stMinpower.lastdaypower);
+ printf("%4lld W ", tempbtuphrconv);
+ tempbtuphrconv = (stMinpower.lastweakpower);
+ printf("%4lld W \n\n", tempbtuphrconv);
+ }
+
+ lastminutepeakpower = stPeakpower.lastminutepowertime;
+ lasthourpeakpower = stPeakpower.lasthourpowertime;
+ lastdaypeakpower = stPeakpower.lastdaypowertime;
+ lastweekpeakpower = stPeakpower.lastweekpowertime;
+
+ printf("Max Power Time\n");
+ ipmi_time_to_str(lastminutepeakpower, timestr);
+ printf("Last Minute : %s",timestr);
+ ipmi_time_to_str(lasthourpeakpower, timestr);
+ printf("Last Hour : %s",timestr);
+ ipmi_time_to_str(lastdaypeakpower, timestr);
+ printf("Last Day : %s",timestr);
+ ipmi_time_to_str(lastweekpeakpower, timestr);
+ printf("Last Week : %s",timestr);
+
+ lastminutepeakpower=stMinpower.lastminutepowertime;
+ lasthourpeakpower=stMinpower.lasthourpowertime;
+ lastdaypeakpower=stMinpower.lastdaypowertime;
+ lastweekpeakpower=stMinpower.lastweekpowertime;
+
+ printf("Min Power Time\n");
+ ipmi_time_to_str(lastminutepeakpower, timestr);
+ printf("Last Minute : %s", timestr);
+ ipmi_time_to_str(lasthourpeakpower, timestr);
+ printf("Last Hour : %s", timestr);
+ ipmi_time_to_str(lastdaypeakpower, timestr);
+ printf("Last Day : %s", timestr);
+ ipmi_time_to_str(lastweekpeakpower, timestr);
+ printf("Last Week : %s", timestr);
+ return rc;
+}
+/*
+ * Function Name: ipmi_get_power_cap
+ *
+ * Description: This function updates the power cap information
+ * Input: intf - ipmi interface
+ * Output: ipmipowercap - power cap information
+ *
+ * Return:
+ */
+static int
+ipmi_get_power_cap(struct ipmi_intf * intf, IPMI_POWER_CAP * ipmipowercap)
+{
+ uint64_t tempbtuphrconv;
+ uint8_t *rdata;
+ int rc;
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_POWER_CAP, 0, 0,
+ sizeof(*ipmipowercap), ipmipowercap);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting power cap.");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G) && (rc == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if ((rc == 0xc1) || (rc == 0xcb)) {
+ lprintf(LOG_ERR, "Error getting power cap: "
+ "Command not supported on this system.");
+ return -1;
+ } else if (rc != 0) {
+ lprintf(LOG_ERR, "Error getting power cap: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 1) {
+ rdata = (void*)ipmipowercap;
+ printf("power cap Data :%x %x %x %x %x %x %x %x %x %x ",
+ rdata[1], rdata[2], rdata[3],
+ rdata[4], rdata[5], rdata[6], rdata[7],
+ rdata[8], rdata[9], rdata[10],rdata[11]);
+ }
+# if WORDS_BIGENDIAN
+ ipmipowercap->PowerCap = BSWAP_16(ipmipowercap->PowerCap);
+ ipmipowercap->MaximumPowerConsmp = BSWAP_16(ipmipowercap->MaximumPowerConsmp);
+ ipmipowercap->MinimumPowerConsmp = BSWAP_16(ipmipowercap->MinimumPowerConsmp);
+ ipmipowercap->totalnumpowersupp = BSWAP_16(ipmipowercap->totalnumpowersupp);
+ ipmipowercap->AvailablePower = BSWAP_16(ipmipowercap->AvailablePower);
+ ipmipowercap->SystemThrottling = BSWAP_16(ipmipowercap->SystemThrottling);
+ ipmipowercap->Resv = BSWAP_16(ipmipowercap->Resv);
+# endif
+ return 0;
+}
+/*
+ * Function Name: ipmi_print_power_cap
+ *
+ * Description: This function print the power cap information
+ * Input: intf - ipmi interface
+ * unit - watt / btuphr
+ * Output:
+ * Return:
+ */
+static int
+ipmi_print_power_cap(struct ipmi_intf * intf,uint8_t unit)
+{
+ uint64_t tempbtuphrconv;
+ int rc;
+ IPMI_POWER_CAP ipmipowercap;
+ memset(&ipmipowercap, 0, sizeof(ipmipowercap));
+ rc = ipmi_get_power_cap(intf, &ipmipowercap);
+ if (rc == 0) {
+ if (unit == btuphr) {
+ tempbtuphrconv = watt_to_btuphr_conversion(ipmipowercap.MaximumPowerConsmp);
+ printf("Maximum power: %lld BTU/hr\n", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(ipmipowercap.MinimumPowerConsmp);
+ printf("Minimum power: %lld BTU/hr\n", tempbtuphrconv);
+ tempbtuphrconv = watt_to_btuphr_conversion(ipmipowercap.PowerCap);
+ printf("Power cap : %lld BTU/hr\n", tempbtuphrconv);
+ } else {
+ printf("Maximum power: %d Watt\n", ipmipowercap.MaximumPowerConsmp);
+ printf("Minimum power: %d Watt\n", ipmipowercap.MinimumPowerConsmp);
+ printf("Power cap : %d Watt\n", ipmipowercap.PowerCap);
+ }
+ }
+ return rc;
+}
+/*
+ * Function Name: ipmi_set_power_cap
+ *
+ * Description: This function updates the power cap information
+ * Input: intf - ipmi interface
+ * unit - watt / btuphr
+ * val - new power cap value
+ * Output:
+ * Return:
+ */
+static int
+ipmi_set_power_cap(struct ipmi_intf * intf, int unit, int val)
+{
+ int rc;
+ uint8_t data[13], *rdata;
+ uint16_t powercapval;
+ uint64_t maxpowerbtuphr;
+ uint64_t maxpowerbtuphr1;
+ uint64_t minpowerbtuphr;
+ IPMI_POWER_CAP ipmipowercap;
+
+ if (ipmi_get_power_capstatus_command(intf) < 0) {
+ return -1; /* Adding the failed condition check */
+ }
+ if (PowercapSetable_flag != 1) {
+ lprintf(LOG_ERR, "Can not set powercap on this system");
+ return -1;
+ } else if (PowercapstatusFlag != 1) {
+ lprintf(LOG_ERR, "Power cap set feature is not enabled");
+ return -1;
+ }
+ rc = ipmi_mc_getsysinfo(intf, IPMI_DELL_POWER_CAP, 0, 0,
+ sizeof(ipmipowercap), &ipmipowercap);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error getting power cap.");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G) && (rc == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if (rc == 0xc1) {
+ lprintf(LOG_ERR, "Error getting power cap, command not supported on "
+ "this system.");
+ return -1;
+ } else if (rc != 0) {
+ lprintf(LOG_ERR, "Error getting power cap: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 1) {
+ rdata = (void *)&ipmipowercap;
+ printf("power cap Data :%x %x %x %x %x %x %x %x %x %x %x ",
+ rdata[1], rdata[2], rdata[3],
+ rdata[4], rdata[5], rdata[6], rdata[7],
+ rdata[8], rdata[9], rdata[10],rdata[11]);
+ }
+# if WORDS_BIGENDIAN
+ ipmipowercap.PowerCap = BSWAP_16(ipmipowercap.PowerCap);
+ ipmipowercap.MaximumPowerConsmp = BSWAP_16(ipmipowercap.MaximumPowerConsmp);
+ ipmipowercap.MinimumPowerConsmp = BSWAP_16(ipmipowercap.MinimumPowerConsmp);
+ ipmipowercap.AvailablePower = BSWAP_16(ipmipowercap.AvailablePower);
+ ipmipowercap.totalnumpowersupp = BSWAP_16(ipmipowercap.totalnumpowersupp);
+# endif
+ memset(data, 0, 13);
+ data[0] = IPMI_DELL_POWER_CAP;
+ powercapval = val;
+ data[1] = (powercapval & 0XFF);
+ data[2] = ((powercapval & 0XFF00) >> 8);
+ data[3] = unit;
+ data[4] = ((ipmipowercap.MaximumPowerConsmp & 0xFF));
+ data[5] = ((ipmipowercap.MaximumPowerConsmp & 0xFF00) >> 8);
+ data[6] = ((ipmipowercap.MinimumPowerConsmp & 0xFF));
+ data[7] = ((ipmipowercap.MinimumPowerConsmp & 0xFF00) >> 8);
+ data[8] = (ipmipowercap.totalnumpowersupp);
+ data[9] = ((ipmipowercap.AvailablePower & 0xFF));
+ data[10] = ((ipmipowercap.AvailablePower & 0xFF00) >> 8);
+ data[11] = (ipmipowercap.SystemThrottling);
+ data[12] = 0x00;
+
+ if (unit == btuphr) {
+ val = btuphr_to_watt_conversion(val);
+ } else if (unit == percent) {
+ if ((val < 0) || (val > 100)) {
+ lprintf(LOG_ERR, "Cap value is out of boundary conditon it "
+ "should be between 0 - 100");
+ return -1;
+ }
+ val = ((val*(ipmipowercap.MaximumPowerConsmp
+ - ipmipowercap.MinimumPowerConsmp)) / 100)
+ + ipmipowercap.MinimumPowerConsmp;
+ lprintf(LOG_ERR, "Cap value in percentage is %d ", val);
+ data[1] = (val & 0XFF);
+ data[2] = ((val & 0XFF00) >> 8);
+ data[3] = watt;
+ }
+ if (((val < ipmipowercap.MinimumPowerConsmp)
+ || (val > ipmipowercap.MaximumPowerConsmp)) && (unit == watt)) {
+ lprintf(LOG_ERR,
+ "Cap value is out of boundary conditon it should be between %d - %d",
+ ipmipowercap.MinimumPowerConsmp, ipmipowercap.MaximumPowerConsmp);
+ return -1;
+ } else if (((val < ipmipowercap.MinimumPowerConsmp)
+ || (val > ipmipowercap.MaximumPowerConsmp)) && (unit == btuphr)) {
+ minpowerbtuphr = watt_to_btuphr_conversion(ipmipowercap.MinimumPowerConsmp);
+ maxpowerbtuphr = watt_to_btuphr_conversion(ipmipowercap.MaximumPowerConsmp);
+ maxpowerbtuphr1 = watt_to_btuphr_conversion(ipmipowercap.MaximumPowerConsmp);
+ lprintf(LOG_ERR,
+ "Cap value is out of boundary conditon it should be between %d",
+ minpowerbtuphr);
+ lprintf(LOG_ERR, " -%d", maxpowerbtuphr1);
+ return -1;
+ }
+ rc = ipmi_mc_setsysinfo(intf, 13, data);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Error setting power cap");
+ return -1;
+ } else if ((iDRAC_FLAG == IDRAC_12G) && (rc == LICENSE_NOT_SUPPORTED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if (rc > 0) {
+ lprintf(LOG_ERR, "Error setting power cap: %s",
+ val2str(rc, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 1) {
+ printf("CC for setpowercap :%d ", rc);
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_powermonitor_usage
+ *
+ * Description: This function prints help message for powermonitor command
+ * Input:
+ * Output:
+ *
+ * Return:
+ */
+static void
+ipmi_powermonitor_usage(void)
+{
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor");
+ lprintf(LOG_NOTICE,
+" Shows power tracking statistics ");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor clear cumulativepower");
+ lprintf(LOG_NOTICE,
+" Reset cumulative power reading");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor clear peakpower");
+ lprintf(LOG_NOTICE,
+" Reset peak power reading");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor powerconsumption");
+ lprintf(LOG_NOTICE,
+" Displays power consumption in <watt|btuphr>");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor powerconsumptionhistory <watt|btuphr>");
+ lprintf(LOG_NOTICE,
+" Displays power consumption history ");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor getpowerbudget");
+ lprintf(LOG_NOTICE,
+" Displays power cap in <watt|btuphr>");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor setpowerbudget <val><watt|btuphr|percent>");
+ lprintf(LOG_NOTICE,
+" Allows user to set the power cap in <watt|BTU/hr|percentage>");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor enablepowercap ");
+ lprintf(LOG_NOTICE,
+" To enable set power cap");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" powermonitor disablepowercap ");
+ lprintf(LOG_NOTICE,
+" To disable set power cap");
+ lprintf(LOG_NOTICE,
+"");
+}
+/*
+ * Function Name: ipmi_delloem_vFlash_main
+ *
+ * Description: This function processes the delloem vFlash command
+ * Input: intf - ipmi interface
+ * argc - no of arguments
+ * argv - argument string array
+ * Output:
+ *
+ * Return: return code 0 - success
+ * -1 - failure
+ */
+static int
+ipmi_delloem_vFlash_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ current_arg++;
+ rc = ipmi_delloem_vFlash_process(intf, current_arg, argv);
+ return rc;
+}
+/*
+ * Function Name: get_vFlash_compcode_str
+ *
+ * Description: This function maps the vFlash completion code
+ * to a string
+ * Input : vFlash completion code and static array of codes vs strings
+ * Output: -
+ * Return: returns the mapped string
+ */
+const char *
+get_vFlash_compcode_str(uint8_t vflashcompcode, const struct vFlashstr *vs)
+{
+ static char un_str[32];
+ int i;
+ for (i = 0; vs[i].str != NULL; i++) {
+ if (vs[i].val == vflashcompcode)
+ return vs[i].str;
+ }
+ memset(un_str, 0, 32);
+ snprintf(un_str, 32, "Unknown (0x%02X)", vflashcompcode);
+ return un_str;
+}
+/*
+ * Function Name: ipmi_get_sd_card_info
+ *
+ * Description: This function prints the vFlash Extended SD card info
+ * Input : ipmi interface
+ * Output: prints the sd card extended info
+ * Return: 0 - success -1 - failure
+ */
+static int
+ipmi_get_sd_card_info(struct ipmi_intf * intf) {
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[2];
+ uint8_t input_length=0;
+ uint8_t cardstatus=0x00;
+ IPMI_DELL_SDCARD_INFO * sdcardinfoblock;
+
+ input_length = 2;
+ msg_data[0] = msg_data[1] = 0x00;
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_GET_EXT_SD_CARD_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = input_length;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in getting SD Card Extended Information");
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in getting SD Card Extended Information (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ sdcardinfoblock = (IPMI_DELL_SDCARD_INFO *) (void *) rsp->data;
+
+ if ((iDRAC_FLAG == IDRAC_12G)
+ && (sdcardinfoblock->vflashcompcode == VFL_NOT_LICENSED)) {
+ lprintf(LOG_ERR,
+ "FM001 : A required license is missing or expired");
+ return -1;
+ } else if (sdcardinfoblock->vflashcompcode != 0x00) {
+ lprintf(LOG_ERR, "Error in getting SD Card Extended Information (%s)",
+ get_vFlash_compcode_str(sdcardinfoblock->vflashcompcode,
+ vFlash_completion_code_vals));
+ return -1;
+ }
+
+ if (!(sdcardinfoblock->sdcardstatus & 0x04)) {
+ lprintf(LOG_ERR,
+ "vFlash SD card is unavailable, please insert the card of");
+ lprintf(LOG_ERR,
+ "size 256MB or greater");
+ return (-1);
+ }
+
+ printf("vFlash SD Card Properties\n");
+ printf("SD Card size : %8dMB\n", sdcardinfoblock->sdcardsize);
+ printf("Available size : %8dMB\n", sdcardinfoblock->sdcardavailsize);
+ printf("Initialized : %10s\n",
+ (sdcardinfoblock->sdcardstatus & 0x80) ? "Yes" : "No");
+ printf("Licensed : %10s\n",
+ (sdcardinfoblock->sdcardstatus & 0x40) ? "Yes" : "No");
+ printf("Attached : %10s\n",
+ (sdcardinfoblock->sdcardstatus & 0x20) ? "Yes" : "No");
+ printf("Enabled : %10s\n",
+ (sdcardinfoblock->sdcardstatus & 0x10) ? "Yes" : "No");
+ printf("Write Protected : %10s\n",
+ (sdcardinfoblock->sdcardstatus & 0x08) ? "Yes" : "No");
+ cardstatus = sdcardinfoblock->sdcardstatus & 0x03;
+ printf("Health : %10s\n",
+ ((0x00 == cardstatus) ? "OK" : (
+ (cardstatus == 0x03) ? "Undefined" : (
+ (cardstatus == 0x02) ? "Critical" : "Warning"))));
+ printf("Bootable partition : %10d\n", sdcardinfoblock->bootpartion);
+ return 0;
+}
+/*
+ * Function Name: ipmi_delloem_vFlash_process
+ *
+ * Description: This function processes the args for vFlash subcmd
+ * Input : intf - ipmi interface, arg index, argv array
+ * Output: prints help or error with help
+ * Return: 0 - Success -1 - failure
+ */
+static int
+ipmi_delloem_vFlash_process(struct ipmi_intf * intf, int current_arg, char ** argv)
+{
+ int rc;
+ if (strncmp(intf->name,"wmi\0",4) && strncmp(intf->name, "open\0",5)) {
+ lprintf(LOG_ERR,
+ "vFlash support is enabled only for wmi and open interface.");
+ lprintf(LOG_ERR, "Its not enabled for lan and lanplus interface.");
+ return -1;
+ }
+
+ if (argv[current_arg] == NULL || strcmp(argv[current_arg], "help") == 0) {
+ ipmi_vFlash_usage();
+ return 0;
+ }
+ ipmi_idracvalidator_command(intf);
+ if (!strncmp(argv[current_arg], "info\0", 5)) {
+ current_arg++;
+ if (argv[current_arg] == NULL) {
+ ipmi_vFlash_usage();
+ return -1;
+ } else if (strncmp(argv[current_arg], "Card\0", 5) == 0) {
+ current_arg++;
+ if (argv[current_arg] != NULL) {
+ ipmi_vFlash_usage();
+ return -1;
+ }
+ rc = ipmi_get_sd_card_info(intf);
+ return rc;
+ } else {
+ /* TBD: many sub commands are present */
+ ipmi_vFlash_usage();
+ return -1;
+ }
+ } else {
+ /* TBD other vFlash subcommands */
+ ipmi_vFlash_usage();
+ return -1;
+ }
+}
+/*
+ * Function Name: ipmi_vFlash_usage
+ *
+ * Description: This function displays the usage for using vFlash
+ * Input : void
+ * Output: prints help
+ * Return: void
+ */
+static void
+ipmi_vFlash_usage(void)
+{
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" vFlash info Card");
+ lprintf(LOG_NOTICE,
+" Shows Extended SD Card information");
+ lprintf(LOG_NOTICE,
+"");
+}
+/*
+ * Function Name: ipmi_setled_usage
+ *
+ * Description: This function prints help message for setled command
+ * Input:
+ * Output:
+ *
+ * Return:
+ */
+static void
+ipmi_setled_usage(void)
+{
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+" setled <b:d.f> <state..>");
+ lprintf(LOG_NOTICE,
+" Set backplane LED state");
+ lprintf(LOG_NOTICE,
+" b:d.f = PCI Bus:Device.Function of drive (lspci format)");
+ lprintf(LOG_NOTICE,
+" state = present|online|hotspare|identify|rebuilding|");
+ lprintf(LOG_NOTICE,
+" fault|predict|critical|failed");
+ lprintf(LOG_NOTICE,
+"");
+}
+
+static int
+IsSetLEDSupported(void)
+{
+ return SetLEDSupported;
+}
+
+static void
+CheckSetLEDSupport(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint8_t data[10];
+
+ SetLEDSupported = 0;
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = 0xD5; /* Storage */
+ req.msg.data_len = 10;
+ req.msg.data = data;
+
+ memset(data, 0, sizeof(data));
+ data[0] = 0x01; /* get */
+ data[1] = 0x00; /* subcmd:get firmware version */
+ data[2] = 0x08; /* length lsb */
+ data[3] = 0x00; /* length msb */
+ data[4] = 0x00; /* offset lsb */
+ data[5] = 0x00; /* offset msb */
+ data[6] = 0x00; /* bay id */
+ data[7] = 0x00;
+ data[8] = 0x00;
+ data[9] = 0x00;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL || rsp->ccode != 0) {
+ return;
+ }
+ SetLEDSupported = 1;
+}
+/*
+ * Function Name: ipmi_getdrivemap
+ *
+ * Description: This function returns mapping of BDF to Bay:Slot
+ * Input: intf - ipmi interface
+ * bdf - PCI Address of drive
+ * *bay - Returns bay ID
+ * *slot - Returns slot ID
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_getdrivemap(struct ipmi_intf * intf, int b, int d, int f, int *bay,
+ int *slot)
+{
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint8_t data[8];
+ /* Get mapping of BDF to bay:slot */
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = 0xD5;
+ req.msg.data_len = 8;
+ req.msg.data = data;
+
+ memset(data, 0, sizeof(data));
+ data[0] = 0x01; /* get */
+ data[1] = 0x07; /* storage map */
+ data[2] = 0x06; /* length lsb */
+ data[3] = 0x00; /* length msb */
+ data[4] = 0x00; /* offset lsb */
+ data[5] = 0x00; /* offset msb */
+ data[6] = b; /* bus */
+ data[7] = (d << 3) + f; /* devfn */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error issuing getdrivemap command.");
+ return -1;
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Error issuing getdrivemap command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ *bay = rsp->data[7];
+ *slot = rsp->data[8];
+ if (*bay == 0xFF || *slot == 0xFF) {
+ lprintf(LOG_ERR, "Error could not get drive bay:slot mapping");
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_setled_state
+ *
+ * Description: This function updates the LED on the backplane
+ * Input: intf - ipmi interface
+ * bdf - PCI Address of drive
+ * state - SES Flags state of drive
+ * Output:
+ *
+ * Return:
+ */
+static int
+ipmi_setled_state(struct ipmi_intf * intf, int bayId, int slotId, int state)
+{
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req = {0};
+ uint8_t data[20];
+ /* Issue Drive Status Update to bay:slot */
+ req.msg.netfn = DELL_OEM_NETFN;
+ req.msg.lun = 0;
+ req.msg.cmd = 0xD5;
+ req.msg.data_len = 20;
+ req.msg.data = data;
+
+ memset(data, 0, sizeof(data));
+ data[0] = 0x00; /* set */
+ data[1] = 0x04; /* set drive status */
+ data[2] = 0x0e; /* length lsb */
+ data[3] = 0x00; /* length msb */
+ data[4] = 0x00; /* offset lsb */
+ data[5] = 0x00; /* offset msb */
+ data[6] = 0x0e; /* length lsb */
+ data[7] = 0x00; /* length msb */
+ data[8] = bayId; /* bayid */
+ data[9] = slotId; /* slotid */
+ data[10] = state & 0xff; /* state LSB */
+ data[11] = state >> 8; /* state MSB; */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error issuing setled command.");
+ return -1;
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Error issuing setled command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ return 0;
+}
+/*
+ * Function Name: ipmi_getsesmask
+ *
+ * Description: This function calculates bits in SES drive update
+ * Return: Mask set with bits for SES backplane update
+ */
+static int
+ipmi_getsesmask(int argc, char **argv)
+{
+ int mask = 0;
+ while (current_arg < argc) {
+ if (!strcmp(argv[current_arg], "present"))
+ mask |= (1L << 0);
+ if (!strcmp(argv[current_arg], "online"))
+ mask |= (1L << 1);
+ if (!strcmp(argv[current_arg], "hotspare"))
+ mask |= (1L << 2);
+ if (!strcmp(argv[current_arg], "identify"))
+ mask |= (1L << 3);
+ if (!strcmp(argv[current_arg], "rebuilding"))
+ mask |= (1L << 4);
+ if (!strcmp(argv[current_arg], "fault"))
+ mask |= (1L << 5);
+ if (!strcmp(argv[current_arg], "predict"))
+ mask |= (1L << 6);
+ if (!strcmp(argv[current_arg], "critical"))
+ mask |= (1L << 9);
+ if (!strcmp(argv[current_arg], "failed"))
+ mask |= (1L << 10);
+ current_arg++;
+ }
+ return mask;
+}
+/*
+ * Function Name: ipmi_delloem_setled_main
+ *
+ * Description: This function processes the delloem setled command
+ * Input: intf - ipmi interface
+ * argc - no of arguments
+ * argv - argument string array
+ * Output:
+ *
+ * Return: return code 0 - success
+ * -1 - failure
+ */
+static int
+ipmi_delloem_setled_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int b,d,f, mask;
+ int bayId, slotId;
+ bayId = 0xFF;
+ slotId = 0xFF;
+ current_arg++;
+ if (argc < current_arg) {
+ usage();
+ return -1;
+ }
+ /* ipmitool delloem setled info*/
+ if (argc == 1 || strcmp(argv[current_arg], "help") == 0) {
+ ipmi_setled_usage();
+ return 0;
+ }
+ CheckSetLEDSupport(intf);
+ if (!IsSetLEDSupported()) {
+ lprintf(LOG_ERR, "'setled' is not supported on this system.");
+ return -1;
+ } else if (sscanf(argv[current_arg], "%*x:%x:%x.%x", &b,&d,&f) == 3) {
+ /* We have bus/dev/function of drive */
+ current_arg++;
+ ipmi_getdrivemap (intf, b, d, f, &bayId, &slotId);
+ } else if (sscanf(argv[current_arg], "%x:%x.%x", &b,&d,&f) == 3) {
+ /* We have bus/dev/function of drive */
+ current_arg++;
+ } else {
+ ipmi_setled_usage();
+ return -1;
+ }
+ /* Get mask of SES flags */
+ mask = ipmi_getsesmask(argc, argv);
+ /* Get drive mapping */
+ if (ipmi_getdrivemap (intf, b, d, f, &bayId, &slotId)) {
+ return -1;
+ }
+ /* Set drive LEDs */
+ return ipmi_setled_state (intf, bayId, slotId, mask);
+}
diff --git a/lib/ipmi_ekanalyzer.c b/lib/ipmi_ekanalyzer.c
new file mode 100644
index 0000000..2ac1012
--- /dev/null
+++ b/lib/ipmi_ekanalyzer.c
@@ -0,0 +1,4195 @@
+/*
+ * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved.
+ *
+ * Base on code from
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <ipmitool/ipmi_ekanalyzer.h>
+#include <ipmitool/log.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_strings.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define NO_MORE_INFO_FIELD 0xc1
+#define TYPE_CODE 0xc0 /*Language code*/
+
+/*****************************************************************
+* CONSTANT
+*****************************************************************/
+const int ERROR_STATUS = -1;
+const int OK_STATUS = 0;
+
+const char * STAR_LINE_LIMITER =
+ "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*";
+const char * EQUAL_LINE_LIMITER =
+ "=================================================================";
+const int SIZE_OF_FILE_TYPE = 3;
+const unsigned char AMC_MODULE = 0x80;
+const int PICMG_ID_OFFSET = 3;
+const unsigned int COMPARE_CANDIDATE = 2;
+/*In AMC.0 or PICMG 3.0 specification offset start from 0 with 3 bytes of
+* Mfg.ID, 1 byte of Picmg record Id, and
+* 1 byte of format version, so the data offset start from 5
+*/
+const int START_DATA_OFFSET = 5;
+const int LOWER_OEM_TYPE = 0xf0;
+const int UPPER_OEM_TYPE = 0xfe;
+const unsigned char DISABLE_PORT = 0x1f;
+
+const struct valstr ipmi_ekanalyzer_module_type[] = {
+ { ON_CARRIER_FRU_FILE, "On-Carrier Device" },
+ { A1_AMC_FRU_FILE, "AMC slot A1" },
+ { A2_AMC_FRU_FILE, "AMC slot A2" },
+ { A3_AMC_FRU_FILE, "AMC slot A3" },
+ { A4_AMC_FRU_FILE, "AMC slot A4" },
+ { B1_AMC_FRU_FILE, "AMC slot B1" },
+ { B2_AMC_FRU_FILE, "AMC slot B2" },
+ { B3_AMC_FRU_FILE, "AMC slot B3" },
+ { B4_AMC_FRU_FILE, "AMC slot B4" },
+ { RTM_FRU_FILE, "RTM" }, /*This is OEM specific module*/
+ { CONFIG_FILE, "Configuration file" },
+ { SHELF_MANAGER_FRU_FILE, "Shelf Manager" },
+ { 0xffff , NULL },
+};
+
+const struct valstr ipmi_ekanalyzer_IPMBL_addr[] = {
+ { 0x72, "AMC slot A1" },
+ { 0x74, "AMC slot A2" },
+ { 0x76, "AMC slot A3" },
+ { 0x78, "AMC slot A4" },
+ { 0x7a, "AMC slot B1" },
+ { 0x7c, "AMC slot B2" },
+ { 0x7e, "AMC slot B3" },
+ { 0x80, "AMC slot B4" },
+ { 0x90, "RTM"}, /*This is OEM specific module*/
+ { 0xffff , NULL },
+};
+
+const struct valstr ipmi_ekanalyzer_link_type[] = {
+ { 0x00, "Reserved" },
+ { 0x01, "Reserved" },
+ { 0x02, "AMC.1 PCI Express" },
+ { 0x03, "AMC.1 PCI Express Advanced Switching" },
+ { 0x04, "AMC.1 PCI Express Advanced Switching" },
+ { 0x05, "AMC.2 Ethernet" },
+ { 0x06, "AMC.4 Serial RapidIO" },
+ { 0x07, "AMC.3 Storage" },
+ /*This is OEM specific module*/
+ { 0xf0, "OEM Type 0"},
+ { 0xf1, "OEM Type 1"},
+ { 0xf2, "OEM Type 2"},
+ { 0xf3, "OEM Type 3"},
+ { 0xf4, "OEM Type 4"},
+ { 0xf5, "OEM Type 5"},
+ { 0xf6, "OEM Type 6"},
+ { 0xf7, "OEM Type 7"},
+ { 0xf8, "OEM Type 8"},
+ { 0xf9, "OEM Type 9"},
+ { 0xfa, "OEM Type 10"},
+ { 0xfb, "OEM Type 11"},
+ { 0xfc, "OEM Type 12"},
+ { 0xfd, "OEM Type 13"},
+ { 0xfe, "OEM Type 14"},
+ { 0xff , "Reserved" },
+};
+
+/*Reference: AMC.1 specification*/
+const struct valstr ipmi_ekanalyzer_extension_PCIE[] = {
+ { 0x00, "Gen 1 capable - non SSC" },
+ { 0x01, "Gen 1 capable - SSC" },
+ { 0x02, "Gen 2 capable - non SSC" },
+ { 0x03, "Gen 3 capable - SSC" },
+ { 0x0f, "Reserved"},
+};
+/*Reference: AMC.2 specification*/
+const struct valstr ipmi_ekanalyzer_extension_ETHERNET[] = {
+ { 0x00, "1000BASE-BX (SerDES Gigabit) Ethernet link" },
+ { 0x01, "10GBASE-BX4 10 Gigabit Ethernet link" },
+};
+/*Reference: AMC.3 specification*/
+const struct valstr ipmi_ekanalyzer_extension_STORAGE[] = {
+ { 0x00, "Fibre Channel (FC)" },
+ { 0x01, "Serial ATA (SATA)" },
+ { 0x02, "Serial Attached SCSI (SAS/SATA)" },
+};
+
+const struct valstr ipmi_ekanalyzer_asym_PCIE[] = {
+ { 0x00, "exact match"},
+ { 0x01, "provides a Primary PCI Express Port" },
+ { 0x02, "provides a Secondary PCI Express Port" },
+};
+
+const struct valstr ipmi_ekanalyzer_asym_STORAGE[] = {
+ { 0x00, "FC or SAS interface {exact match}" },
+ { 0x01, "SATA Server interface" },
+ { 0x02, "SATA Client interface" },
+ { 0x03, "Reserved" },
+};
+
+const struct valstr ipmi_ekanalyzer_picmg_record_id[] = {
+ { 0x04, "Backplane Point to Point Connectivity Record" },
+ { 0x10, "Address Table Record" },
+ { 0x11, "Shelf Power Distribution Record" },
+ { 0x12, "Shelf Activation and Power Management Record" },
+ { 0x13, "Shelf Manager IP Connection Record" },
+ { 0x14, "Board Point to Point Connectivity Record" },
+ { 0x15, "Radial IPMB-0 Link Mapping Record" },
+ { 0x16, "Module Current Requirements Record" },
+ { 0x17, "Carrier Activation and Power Management Record" },
+ { 0x18, "Carrier Point-to-Point Connectivity Record" },
+ { 0x19, "AdvancedMC Point-to-Point Connectivity Record" },
+ { 0x1a, "Carrier Information Table" },
+ { 0x1b, "Shelf Fan Geography Record" },
+ { 0x2c, "Carrier Clock Point-to-Point Connectivity Record" },
+ { 0x2d, "Clock Configuration Record" },
+};
+
+extern int verbose;
+
+struct ipmi_ek_multi_header {
+ struct fru_multirec_header header;
+ unsigned char * data;
+ struct ipmi_ek_multi_header * prev;
+ struct ipmi_ek_multi_header * next;
+};
+
+struct ipmi_ek_amc_p2p_connectivity_record{
+ unsigned char guid_count;
+ struct fru_picmgext_guid * oem_guid;
+ unsigned char rsc_id;
+ unsigned char ch_count;
+ struct fru_picmgext_amc_channel_desc_record * ch_desc;
+ unsigned char link_desc_count;
+ struct fru_picmgext_amc_link_desc_record * link_desc;
+ int * matching_result; /*For link descriptor comparision*/
+};
+
+/*****************************************************************************
+* Function prototype
+******************************************************************************/
+/****************************************************************************
+* command Functions
+*****************************************************************************/
+static int ipmi_ekanalyzer_print( int argc, char * opt,
+ char ** filename, int * file_type );
+
+static tboolean ipmi_ekanalyzer_ekeying_match( int argc, char * opt,
+ char ** filename, int * file_type );
+
+/****************************************************************************
+* Linked list Functions
+*****************************************************************************/
+static void ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_last );
+
+static void ipmi_ek_display_record( struct ipmi_ek_multi_header * record,
+ struct ipmi_ek_multi_header * list_head,
+ struct ipmi_ek_multi_header * list_last );
+
+static void ipmi_ek_remove_record_from_list(
+ struct ipmi_ek_multi_header * record,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_last );
+
+static int ipmi_ekanalyzer_fru_file2structure( char * filename,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_record,
+ struct ipmi_ek_multi_header ** list_last );
+
+/****************************************************************************
+* Ekeying match Functions
+*****************************************************************************/
+static int ipmi_ek_matching_process( int * file_type, int index1, int index2,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_last, char * opt,
+ struct ipmi_ek_multi_header * pphysical );
+
+static int ipmi_ek_get_resource_descriptor( int port_count, int index,
+ struct fru_picmgext_carrier_p2p_descriptor * port_desc,
+ struct ipmi_ek_multi_header * record );
+
+static int ipmi_ek_create_amc_p2p_record( struct ipmi_ek_multi_header * record,
+ struct ipmi_ek_amc_p2p_connectivity_record * amc_record );
+
+static int ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record,
+ struct ipmi_ek_amc_p2p_connectivity_record record1,
+ struct ipmi_ek_amc_p2p_connectivity_record record2,
+ char * opt, int file_type1, int file_type2 );
+
+static tboolean ipmi_ek_compare_channel_descriptor(
+ struct fru_picmgext_amc_channel_desc_record ch_desc1,
+ struct fru_picmgext_amc_channel_desc_record ch_desc2,
+ struct fru_picmgext_carrier_p2p_descriptor * port_desc,
+ int index_port, unsigned char rsc_id );
+
+static int ipmi_ek_compare_link_descriptor(
+ struct ipmi_ek_amc_p2p_connectivity_record record1, int index1,
+ struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 );
+
+static int ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] );
+
+static int ipmi_ek_compare_number_of_enable_port(
+ struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] );
+
+static int ipmi_ek_check_physical_connectivity(
+ struct ipmi_ek_amc_p2p_connectivity_record record1, int index1,
+ struct ipmi_ek_amc_p2p_connectivity_record record2, int index2,
+ struct ipmi_ek_multi_header * record,
+ int filetype1, int filetype2, char * option );
+
+/****************************************************************************
+* Display Functions
+*****************************************************************************/
+static int ipmi_ek_display_fru_header( char * filename );
+
+static int ipmi_ek_display_fru_header_detail(char * filename);
+
+static int ipmi_ek_display_chassis_info_area(FILE * input_file, long offset);
+
+static size_t ipmi_ek_display_board_info_area( FILE * input_file,
+ char * board_type, unsigned int * board_length );
+
+static int ipmi_ek_display_product_info_area(FILE * input_file, long offset);
+
+static tboolean ipmi_ek_display_link_descriptor( int file_type,
+ unsigned char rsc_id, char * str,
+ struct fru_picmgext_amc_link_desc_record link_desc );
+
+static void ipmi_ek_display_oem_guid(
+ struct ipmi_ek_amc_p2p_connectivity_record amc_record1 );
+
+static int ipmi_ek_display_carrier_connectivity(
+ struct ipmi_ek_multi_header * record );
+
+static int ipmi_ek_display_power( int argc, char * opt,
+ char ** filename, int * file_type );
+
+static void ipmi_ek_display_current_descriptor(
+ struct fru_picmgext_carrier_activation_record car,
+ struct fru_picmgext_activation_record * cur_desc, char * filename );
+
+static void ipmi_ek_display_backplane_p2p_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_address_table_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_shelf_power_distribution_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_shelf_activation_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_shelf_ip_connection_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_shelf_fan_geography_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_board_p2p_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_radial_ipmb0_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_amc_current_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_amc_activation_record (
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_amc_p2p_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_amc_carrier_info_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_clock_carrier_p2p_record(
+ struct ipmi_ek_multi_header * record );
+
+static void ipmi_ek_display_clock_config_record(
+ struct ipmi_ek_multi_header * record );
+
+/**************************************************************************
+*
+* Function name: ipmi_ekanalyzer_usage
+*
+* Description : Print the usage (help menu) of ekeying analyzer tool
+*
+* Restriction : None
+*
+* Input : None
+*
+* Output : None
+*
+* Global : None
+*
+* Return : None
+*
+***************************************************************************/
+static void
+ipmi_ekanalyzer_usage( void )
+{
+ lprintf(LOG_NOTICE, "Ekeying analyzer tool version 1.00");
+ lprintf(LOG_NOTICE, "ekanalyzer Commands:");
+ lprintf(LOG_NOTICE,
+ " print [carrier | power | all] <oc=filename1> <b1=filename2>...");
+ lprintf(LOG_NOTICE,
+ " frushow <b2=filename>");
+ lprintf(LOG_NOTICE,
+ " summary [match | unmatch | all] <oc=filename1> <b1=filename2>...");
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_get_file_type
+*
+* Description: this function takes an argument, then xtract the file type and
+* convert into module type (on carrier, AMC,...) value.
+*
+*
+* Restriction: None
+*
+* Input: argument: strings contain the type and the name of the file
+* together
+*
+* Output: None
+*
+* Global: None
+*
+* Return: Return value of module type: On carrier FRU file, A1 FRUM file...
+* if the file type is invalid, it return -1. See structure
+* ipmi_ekanalyzer_module_type for a list of valid type.
+***************************************************************************/
+static int
+ipmi_ek_get_file_type( char * argument )
+{
+ int index_name=0;
+ int filetype = ERROR_STATUS;
+
+ if( strlen (argument) > MIN_ARGUMENT ){
+ if( strncmp( argument, "oc=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = ON_CARRIER_FRU_FILE;
+ }
+ else if( strncmp( argument, "a1=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = A1_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "a2=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = A2_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "a3=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = A3_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "a4=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = A4_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "b1=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = B1_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "b2=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = B2_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "b3=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = B3_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "b4=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = B4_AMC_FRU_FILE;
+ }
+ else if( strncmp( argument, "rt=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = RTM_FRU_FILE;
+ }
+ else if( strncmp( argument, "rc=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = CONFIG_FILE;
+ }
+ else if( strncmp( argument, "sm=", SIZE_OF_FILE_TYPE ) == 0 ) {
+ filetype = SHELF_MANAGER_FRU_FILE;
+ }
+ else{
+ filetype = ERROR_STATUS;
+ }
+ }
+ return filetype;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ekanalyzer_main
+*
+* Description: Main program of ekeying analyzer. It calls the appropriate
+* function according to the command received.
+*
+* Restriction: None
+*
+* Input: ipmi_intf * intf: ?
+* int argc : number of argument received
+* int ** argv: argument strings
+*
+* Output: None
+*
+* Global: None
+*
+* Return: OK_STATUS as succes or ERROR_STATUS as error
+*
+***************************************************************************/
+int
+ipmi_ekanalyzer_main( struct ipmi_intf * intf, int argc, char ** argv )
+{
+ int rc = ERROR_STATUS;
+ int file_type[MAX_FILE_NUMBER];
+ int tmp_ret = 0;
+ char * filename[MAX_FILE_NUMBER];
+ unsigned int argument_offset = 0;
+ unsigned int type_offset = 0;
+ /*list des multi record*/
+ struct ipmi_ek_multi_header * list_head = NULL;
+ struct ipmi_ek_multi_header * list_record = NULL;
+ struct ipmi_ek_multi_header * list_last = NULL;
+
+ if ( (argc == 0) || ( (argc - 1) > MAX_FILE_NUMBER ) ){
+ lprintf(LOG_ERR, "Too few or too many arguments!");
+ ipmi_ekanalyzer_usage();
+ rc = ERROR_STATUS;
+ }
+ else if ( strcmp(argv[argument_offset], "help") == 0) {
+ ipmi_ekanalyzer_usage();
+ rc = 0;
+ }
+ else if ( (strcmp(argv[argument_offset], "frushow") == 0)
+ && (argc > (MIN_ARGUMENT-1) )
+ ){
+ for ( type_offset = 0; type_offset < (argc-1); type_offset++ ){
+ argument_offset++;
+ file_type[type_offset] = ipmi_ek_get_file_type (argv[argument_offset]);
+ if ( file_type[type_offset] != ERROR_STATUS ){
+ if ( file_type[type_offset] != CONFIG_FILE ){
+ /* because of strlen doesn't count '\0', we need to add 1 byte for
+ * this character to filename size
+ */
+ filename[type_offset] = malloc( strlen(argv[argument_offset]) + 1
+ - SIZE_OF_FILE_TYPE
+ );
+ if( filename[type_offset] != NULL ){
+ strcpy(filename[type_offset],
+ &argv[argument_offset][SIZE_OF_FILE_TYPE]);
+ printf("Start converting file '%s'...\n", filename[type_offset]);
+ /* Display FRU header offset */
+ rc = ipmi_ek_display_fru_header (filename[type_offset]);
+
+ if ( rc != ERROR_STATUS ){
+ /* Display FRU header info in detail record */
+ tmp_ret = ipmi_ek_display_fru_header_detail(filename[type_offset]);
+ /* Convert from binary data into multi record structure */
+ rc = ipmi_ekanalyzer_fru_file2structure ( filename[type_offset],
+ &list_head, &list_record, &list_last );
+
+ ipmi_ek_display_record ( list_record, list_head, list_last );
+ /* Remove record of list */
+ while ( list_head != NULL ){
+ ipmi_ek_remove_record_from_list( list_head,
+ &list_head,&list_last );
+ if (verbose > 1)
+ printf("record has been removed!\n");
+ }
+ }
+ free(filename[type_offset]);
+ filename[type_offset] = NULL;
+ }
+ }
+ }
+ else{
+ lprintf(LOG_ERR, "Invalid file type!");
+ lprintf(LOG_ERR, " ekanalyzer frushow <xx=frufile> ...");
+ }
+ }
+ }
+ else if ( (strcmp(argv[argument_offset], "print") == 0)
+ || (strcmp(argv[argument_offset], "summary") == 0)
+ ){
+ /*Display help of the correspond command if there is not enought argument
+ * passing in command line
+ */
+ if ( argc < MIN_ARGUMENT ){
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ if ( strcmp(argv[argument_offset], "print") == 0 ){
+ lprintf(LOG_ERR, " ekanalyzer print [carrier/power/all]"
+ " <xx=frufile> <xx=frufile> [xx=frufile]"
+ );
+ }
+ else{
+ lprintf(LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]"
+ " <xx=frufile> <xx=frufile> [xx=frufile]"
+ );
+ }
+ }
+ else{
+ char * option;
+ /*index=1 indicates start position of first file name in command line*/
+ int index = 1;
+ int filename_size=0;
+
+ argument_offset++;
+ if ( (strcmp(argv[argument_offset], "carrier") == 0)
+ || (strcmp(argv[argument_offset], "power") == 0)
+ || (strcmp(argv[argument_offset], "all") == 0)
+ ){
+ option = argv[argument_offset];
+ index ++;
+ argc--;
+ }
+ else if ( ( strcmp(argv[argument_offset], "match") == 0 )
+ || ( strcmp(argv[argument_offset], "unmatch") == 0 )
+ ){
+ option = argv[argument_offset];
+ index ++;
+ argc--;
+ }
+ /*since the command line must receive xx=filename, so the position of
+ * "=" sign is 2
+ */
+ else if ( strncmp(&argv[argument_offset][2], "=", 1) == 0 ){
+ option = "default";
+ /* Since there is no option from user, the first argument
+ * becomes first file type */
+ index = 1; /* index of argument */
+ }
+ else{
+ option = "invalid";
+ printf("Invalid option '%s'\n", argv[argument_offset]);
+ argument_offset--;
+ if (strcmp(argv[0], "print") == 0){
+ lprintf (LOG_ERR, " ekanalyzer print [carrier/power/all]"
+ " <xx=frufile> <xx=frufile> [xx=frufile]"
+ );
+ }
+ else{
+ lprintf (LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]"
+ " <xx=frufile> <xx=frufile> [xx=frufile]"
+ );
+ }
+ rc = ERROR_STATUS;
+ }
+ if ( strcmp(option, "invalid") != 0 ){
+ int i=0;
+
+ for ( i = 0; i < (argc-1); i++){
+ file_type[i] = ipmi_ek_get_file_type (argv[index]);
+ if ( file_type[i] == ERROR_STATUS ){
+ /* display the first 2 charactors (file type) of argument */
+ lprintf(LOG_ERR, "Invalid file type: %c%c\n", argv[index][0],
+ argv[index][1]);
+ ipmi_ekanalyzer_usage();
+ rc = ERROR_STATUS;
+ break;
+ }
+ /*size is equal to string size minus 3 bytes of file type plus
+ * 1 byte of '\0' since the strlen doesn't count the '\0'
+ */
+ filename_size = strlen( argv[index] ) - SIZE_OF_FILE_TYPE + 1;
+ if ( filename_size > 0 ){
+ filename[i] = malloc( filename_size );
+ if (filename[i] != NULL)
+ strcpy( filename[i], &argv[index][SIZE_OF_FILE_TYPE] );
+ }
+ rc = OK_STATUS;
+ index++;
+ }
+ if ( rc != ERROR_STATUS ){
+ if (verbose > 0){
+ for (i = 0; i < (argc-1); i++){
+ printf ("Type: %s, ",
+ val2str(file_type[i], ipmi_ekanalyzer_module_type));
+ printf("file name: %s\n", filename[i]);
+ }
+ }
+ if (strcmp(argv[0], "print") == 0){
+ rc = ipmi_ekanalyzer_print(
+ (argc-1), option, filename, file_type);
+ }
+ else{
+ rc = ipmi_ekanalyzer_ekeying_match(
+ (argc-1), option, filename, file_type);
+ }
+ for (i = 0; i < (argc-1); i++){
+ if (filename[i] != NULL){
+ free(filename[i]);
+ filename[i] = NULL;
+ }
+ }
+ } /* End of ERROR_STATUS */
+ } /* End of comparison of invalid option */
+ } /* End of else MIN_ARGUMENT */
+ } /* End of print or summary option */
+ else{
+ lprintf(LOG_ERR, "Invalid ekanalyzer command: %s", argv[0]);
+ ipmi_ekanalyzer_usage();
+ rc = ERROR_STATUS;
+ }
+
+ return rc;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ekanalyzer_print
+*
+* Description: this function will display the topology, power or both
+* information together according to the option that it received.
+*
+* Restriction: None
+*
+* Input: int argc: number of the argument received
+* char* opt: option string that will tell what to display
+* char** filename: strings that contained filename of FRU data binary file
+* int* file_type: a pointer that contain file type (on carrier file,
+* a1 file, b1 file...). See structure
+* ipmi_ekanalyzer_module_type for a list of valid type
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return 0 as success and -1 as error.
+*
+***************************************************************************/
+static int
+ipmi_ekanalyzer_print( int argc, char * opt, char ** filename, int * file_type )
+{
+ int return_value = OK_STATUS;
+
+ /*Display carrier topology*/
+ if ( (strcmp(opt, "carrier") == 0) || (strcmp(opt, "default") == 0) ){
+ tboolean found_flag = FALSE;
+ int index = 0;
+ int index_name[argc];
+ int list = 0;
+ /*list of multi record*/
+ struct ipmi_ek_multi_header * list_head[argc];
+ struct ipmi_ek_multi_header * list_record[argc];
+ struct ipmi_ek_multi_header * list_last[argc];
+
+ for ( list=0; list < argc; list++ ){
+ list_head[list] = NULL;
+ list_record[list] = NULL;
+ list_last[list] = NULL;
+ }
+
+ list=0; /* reset list count */
+ for ( index = 0; index < argc; index++ ){
+ if ( file_type[index] == ON_CARRIER_FRU_FILE ){
+ index_name[list] = index;
+ return_value = ipmi_ekanalyzer_fru_file2structure( filename[index],
+ &list_head[list], &list_record[list], &list_last[list] );
+ list++;
+ found_flag = TRUE;
+ }
+ }
+ if ( !found_flag ){
+ printf("No carrier file has been found\n");
+ return_value = ERROR_STATUS;
+ }
+ else{
+ int i = 0;
+ for ( i = 0; i < argc; i++ ){
+ /*this is a flag to advoid displaying the same data multiple time*/
+ tboolean first_data = TRUE;
+ for ( list_record[i] = list_head[i];
+ list_record[i] != NULL;
+ list_record[i] = list_record[i]->next ){
+ if ( list_record[i]->data[PICMG_ID_OFFSET]
+ ==
+ FRU_AMC_CARRIER_P2P ){
+ if ( first_data ){
+ printf("%s\n", STAR_LINE_LIMITER);
+ printf("From Carrier file: %s\n", filename[index_name[i]]);
+ first_data = FALSE;
+ }
+ return_value = ipmi_ek_display_carrier_connectivity(
+ list_record[i] );
+ }
+ else if ( list_record[i]->data[PICMG_ID_OFFSET]
+ ==
+ FRU_AMC_CARRIER_INFO ){
+ /*See AMC.0 specification Table3-3 for mor detail*/
+ #define COUNT_OFFSET 6
+ if ( first_data ){
+ printf("From Carrier file: %s\n", filename[index_name[i]]);
+ first_data = FALSE;
+ }
+ printf(" Number of AMC bays supported by Carrier: %d\n",
+ list_record[i]->data[COUNT_OFFSET] );
+ }
+ }
+ }
+ /*Destroy the list of record*/
+ for ( i = 0; i < argc; i++ ){
+ while ( list_head[i] != NULL ){
+ ipmi_ek_remove_record_from_list( list_head[i],
+ &list_head[i], &list_last[i] );
+ }
+ /* display deleted result when we reach the last record */
+ if ( ( i == (list-1) ) && verbose )
+ printf("Record list has been removed successfully\n");
+ }
+ }
+ }
+ else if ( (strcmp(opt, "power") == 0) ){
+ printf("Print power information\n");
+ return_value = ipmi_ek_display_power(argc, opt, filename, file_type);
+ }
+ else if ( strcmp(opt, "all") == 0 ){
+ printf("Print all information\n");
+ return_value = ipmi_ek_display_power(argc, opt, filename, file_type);
+ }
+ else{
+ lprintf(LOG_ERR, "Invalid option %s", opt);
+ return_value = ERROR_STATUS;
+ }
+ return return_value;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_carrier_connectivity
+*
+* Description: Display the topology between a Carrier and all AMC modules by
+* using carrier p2p connectivity record
+*
+* Restriction: Ref: AMC.0 Specification: Table 3-13 and Table 3-14
+*
+* Input: struct ipmi_ek_multi_header* record: a pointer to the carrier p2p
+* connectivity record.
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return 0 on success and -1 if the record doesn't exist.
+*
+***************************************************************************/
+static int
+ipmi_ek_display_carrier_connectivity( struct ipmi_ek_multi_header * record )
+{
+ int return_value = ERROR_STATUS;
+ struct fru_picmgext_carrier_p2p_record rsc_desc;
+ struct fru_picmgext_carrier_p2p_descriptor *port_desc;
+
+ if ( record == NULL ){
+ lprintf(LOG_ERR, "P2P connectivity record is invalid\n");
+ return_value = ERROR_STATUS;
+ }
+ else{
+ int offset = START_DATA_OFFSET;
+ if ( verbose > 1 ){
+ int k = 0;
+ printf("Binary data of Carrier p2p connectivity"\
+ " record starting from mfg id\n");
+ for ( k = 0; k < ( record->header.len ); k++ ){
+ printf("%02x ", record->data[k]);
+ }
+ printf("\n");
+ }
+ while ( offset <= (record->header.len - START_DATA_OFFSET) ){
+ rsc_desc.resource_id = record->data[offset++];
+ rsc_desc.p2p_count = record->data[offset++];
+ if ( verbose > 0 ){
+ printf("resource id= %02x port count= %d\n",
+ rsc_desc.resource_id,rsc_desc.p2p_count);
+ }
+ /*check if it is an AMC Module*/
+ if ( ( (rsc_desc.resource_id & AMC_MODULE) ) == AMC_MODULE ) {
+ /*check if it is an RTM module*/
+ if ((rsc_desc.resource_id == AMC_MODULE)){
+ printf(" %s topology:\n", val2str( RTM_IPMB_L,
+ ipmi_ekanalyzer_IPMBL_addr));
+ }
+ else{
+ /*The last four bits of resource ID represent site number
+ * (mask = 0x0f)
+ */
+ printf(" %s topology:\n",
+ val2str( (rsc_desc.resource_id & 0x0f),
+ ipmi_ekanalyzer_module_type));
+ }
+ }
+ else{
+ printf(" On Carrier Device ID %d topology: \n",
+ (rsc_desc.resource_id & 0x0f));
+ }
+ while ( rsc_desc.p2p_count > 0 ){
+ unsigned char data[3];
+#ifndef WORDS_BIGENDIAN
+ data[0] = record->data[offset+0];
+ data[1] = record->data[offset+1];
+ data[2] = record->data[offset+2];
+#else
+ data[0] = record->data[offset+2];
+ data[1] = record->data[offset+1];
+ data[2] = record->data[offset+0];
+#endif
+ port_desc = (struct fru_picmgext_carrier_p2p_descriptor*)data;
+ offset += sizeof (struct fru_picmgext_carrier_p2p_descriptor);
+ if ((port_desc->remote_resource_id & AMC_MODULE) == AMC_MODULE) {
+ printf("\tPort %d =====> %s, Port %d\n",
+ port_desc->local_port,
+ val2str( (port_desc->remote_resource_id & 0x0f),
+ ipmi_ekanalyzer_module_type),
+ port_desc->remote_port);
+ }
+ else {
+ printf("\tPort %d =====> On Carrier Device ID %d, Port %d\n",
+ port_desc->local_port,
+ (port_desc->remote_resource_id & 0x0f),
+ port_desc->remote_port);
+ }
+ rsc_desc.p2p_count--;
+ }
+ }
+ return_value = OK_STATUS;
+ }
+ return return_value;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_power
+*
+* Description: Display the power management of the Carrier and AMC module by
+* using current management record. If the display option equal to all,
+* it will display power and carrier topology together.
+*
+* Restriction: Reference: AMC.0 Specification, Table 3-11
+*
+* Input: int argc: number of the argument received
+* char* opt: option string that will tell what to display
+* char** filename: strings that contained filename of FRU data binary file
+* int* file_type: a pointer that contain file type (on carrier file,
+* a1 file, b1 file...)
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return 0 on success and -1 if the record doesn't exist.
+*
+***************************************************************************/
+static int
+ipmi_ek_display_power( int argc, char * opt, char ** filename, int * file_type )
+{
+ int num_file=0;
+ int return_value = ERROR_STATUS;
+ int index = 0;
+
+ /*list des multi record*/
+ struct ipmi_ek_multi_header * list_head[argc];
+ struct ipmi_ek_multi_header * list_record[argc];
+ struct ipmi_ek_multi_header * list_last[argc];
+
+ for ( num_file = 0; num_file < argc; num_file++ ){
+ list_head[num_file] = NULL;
+ list_record[num_file] = NULL;
+ list_last[num_file] = NULL;
+ }
+
+ for ( num_file = 0; num_file < argc; num_file++ ){
+ tboolean is_first_data = TRUE;
+ if ( file_type[num_file] == CONFIG_FILE ){
+ num_file++;
+ }
+
+ if ( is_first_data ){
+ printf("%s\n", STAR_LINE_LIMITER);
+ printf("\nFrom %s file '%s'\n",
+ val2str( file_type[num_file], ipmi_ekanalyzer_module_type),
+ filename[num_file]);
+ is_first_data = FALSE;
+ }
+
+ return_value = ipmi_ekanalyzer_fru_file2structure( filename[num_file],
+ &list_head[num_file], &list_record[num_file], &list_last[num_file]);
+
+ if ( list_head[num_file] != NULL ){
+ for ( list_record[num_file] = list_head[num_file];
+ list_record[num_file] != NULL;
+ list_record[num_file] = list_record[num_file]->next
+ ){
+ if ( ( strcmp(opt, "all") == 0 )
+ && ( file_type[num_file] == ON_CARRIER_FRU_FILE )
+ ){
+ if ( list_record[num_file]->data[PICMG_ID_OFFSET]
+ ==
+ FRU_AMC_CARRIER_P2P
+ ){
+ return_value = ipmi_ek_display_carrier_connectivity(
+ list_record[num_file] );
+ }
+ else if ( list_record[num_file]->data[PICMG_ID_OFFSET]
+ ==
+ FRU_AMC_CARRIER_INFO
+ ){
+ /*Ref: See AMC.0 Specification Table 3-3: Carrier Information
+ * Table about offset value
+ */
+ printf( " Number of AMC bays supported by Carrier: %d\n",
+ list_record[num_file]->data[START_DATA_OFFSET+1] );
+ }
+ }
+ /*Ref: AMC.0 Specification: Table 3-11
+ * Carrier Activation and Current Management Record
+ */
+ if ( list_record[num_file]->data[PICMG_ID_OFFSET]
+ ==
+ FRU_AMC_ACTIVATION
+ ){
+ int index_data = START_DATA_OFFSET;
+ struct fru_picmgext_carrier_activation_record car;
+ struct fru_picmgext_activation_record * cur_desc;
+
+ memcpy ( &car, &list_record[num_file]->data[index_data],
+ sizeof (struct fru_picmgext_carrier_activation_record) );
+ index_data +=
+ sizeof (struct fru_picmgext_carrier_activation_record);
+ cur_desc = malloc (car.module_activation_record_count * \
+ sizeof (struct fru_picmgext_activation_record) );
+ for(index=0; index<car.module_activation_record_count; index++){
+ memcpy( &cur_desc[index],
+ &list_record[num_file]->data[index_data],
+ sizeof (struct fru_picmgext_activation_record) );
+
+ index_data += sizeof (struct fru_picmgext_activation_record);
+ }
+ /*Display the current*/
+ ipmi_ek_display_current_descriptor( car,
+ cur_desc, filename[num_file] );
+ free(cur_desc);
+ cur_desc = NULL;
+ }
+ /*Ref: AMC.0 specification, Table 3-10: Module Current Requirement*/
+ else if ( list_record[num_file]->data[PICMG_ID_OFFSET]
+ == FRU_AMC_CURRENT
+ ){
+ float power_in_watt = 0;
+ float current_in_amp = 0;
+
+ printf(" %s power required (Current Draw): ",
+ val2str ( file_type[num_file], ipmi_ekanalyzer_module_type) );
+ current_in_amp =
+ list_record[num_file]->data[START_DATA_OFFSET]*0.1;
+ power_in_watt = current_in_amp * AMC_VOLTAGE;
+ printf("%.2f Watts (%.2f Amps)\n",power_in_watt, current_in_amp);
+ }
+ }
+ return_value = OK_STATUS;
+ /*Destroy the list of record*/
+ for ( index = 0; index < argc; index++ ){
+ while ( list_head[index] != NULL ){
+ ipmi_ek_remove_record_from_list ( list_head[index],
+ &list_head[index],&list_last[index] );
+ }
+ if ( verbose > 1 )
+ printf("Record list has been removed successfully\n");
+ }
+ }
+ }
+ printf("%s\n", STAR_LINE_LIMITER);
+ return return_value;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_current_descriptor
+*
+* Description: Display the current descriptor under format xx Watts (xx Amps)
+*
+* Restriction: None
+*
+* Input: struct fru_picmgext_carrier_activation_record car: contain binary data
+* of carrier activation record
+* struct fru_picmgext_activation_record * cur_desc: contain current
+* descriptor
+* char* filename: strings that contained filename of FRU data binary file
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_current_descriptor(
+ struct fru_picmgext_carrier_activation_record car,
+ struct fru_picmgext_activation_record * cur_desc, char * filename )
+{
+ int index = 0;
+ float power_in_watt = 0.0;
+ float current_in_amp = 0.0;
+
+ for ( index = 0; index < car.module_activation_record_count; index++ ){
+ /*See AMC.0 specification, Table 3-12 for detail about calculation*/
+ current_in_amp = (float) cur_desc[index].max_module_curr * 0.1;
+ power_in_watt = (float) current_in_amp * AMC_VOLTAGE;
+
+ printf(" Carrier AMC power available on %s:\n",
+ val2str( cur_desc[index].ibmb_addr, ipmi_ekanalyzer_IPMBL_addr ) );
+ printf("\t- Local IPMB Address \t: %02x\n", cur_desc[index].ibmb_addr);
+ printf("\t- Maximum module Current\t: %.2f Watts (%.2f Amps)\n",
+ power_in_watt, current_in_amp );
+ }
+ /*Display total power on Carrier*/
+ current_in_amp = (float) car.max_internal_curr * 0.1;
+ power_in_watt = (float) current_in_amp * AMC_VOLTAGE;
+ printf(" Carrier AMC total power available for all bays from file '%s':",
+ filename);
+ printf(" %.2f Watts (%.2f Amps)\n", power_in_watt, current_in_amp );
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ekanalyzer_ekeying_match
+*
+* Description: Check for possible Ekeying match between two FRU files
+*
+* Restriction: None
+*
+* Input: argc: number of the argument received
+* opt: string that contains display option received from user.
+* filename: strings that contained filename of FRU data binary file
+* file_type: a pointer that contain file type (on carrier file,
+* a1 file, b1 file...)
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return TRUE on success and FALSE if the record doesn't exist.
+*
+***************************************************************************/
+static tboolean
+ipmi_ekanalyzer_ekeying_match( int argc, char * opt,
+ char ** filename, int * file_type )
+{
+ tboolean return_value = FALSE;
+
+ if ( (strcmp(opt, "carrier") == 0 ) || (strcmp(opt, "power") == 0) ){
+ lprintf(LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]"\
+ " <xx=frufile> <xx=frufile> [xx=frufile]");
+ return_value = ERROR_STATUS;
+ }
+ else{
+ int num_file=0;
+ tboolean amc_file = FALSE; /*used to indicate the present of AMC file*/
+ tboolean oc_file = FALSE; /*used to indicate the present of Carrier file*/
+
+ /*Check for possible ekeying match between files*/
+ for ( num_file=0; num_file < argc; num_file++ ){
+ if ( ( file_type[num_file] == ON_CARRIER_FRU_FILE )
+ || ( file_type[num_file] == CONFIG_FILE )
+ || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE )
+ ){
+ amc_file = FALSE;
+ }
+ else { /*there is an amc file*/
+ amc_file = TRUE;
+ break;
+ }
+ }
+ if ( amc_file == FALSE ){
+ printf("\nNo AMC FRU file is provided --->" \
+ " No possible ekeying match!\n");
+ return_value = ERROR_STATUS;
+ }
+ else{
+ /*If no carrier file is provided, return error*/
+ for ( num_file=0; num_file < argc; num_file++ ){
+ if ( (file_type[num_file] == ON_CARRIER_FRU_FILE )
+ || ( file_type[num_file] == CONFIG_FILE )
+ || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE )
+ ){
+ oc_file = TRUE;
+ break;
+ }
+ }
+ if ( !oc_file ){
+ printf("\nNo Carrier FRU file is provided" \
+ " ---> No possible ekeying match!\n");
+ return_value = ERROR_STATUS;
+ }
+ else{
+ /*list des multi record*/
+ struct ipmi_ek_multi_header * list_head[argc];
+ struct ipmi_ek_multi_header * list_record[argc];
+ struct ipmi_ek_multi_header * list_last[argc];
+ struct ipmi_ek_multi_header * pcarrier_p2p;
+ int list = 0;
+ int match_pair = 0;
+
+ /*Create an empty list*/
+ for ( list=0; list<argc; list++ ){
+ list_head[list] = NULL;
+ list_record[list] = NULL;
+ list_last[list] = NULL;
+ }
+ list=0;
+
+ for ( num_file=0; num_file < argc; num_file++ ){
+ if (file_type[num_file] != CONFIG_FILE){
+ return_value = ipmi_ekanalyzer_fru_file2structure(
+ filename[num_file], &list_head[num_file],
+ &list_record[num_file], &list_last[num_file]);
+ }
+ }
+ /*Get Carrier p2p connectivity record for physical check*/
+ for (num_file=0; num_file < argc; num_file++){
+ if (file_type[num_file] == ON_CARRIER_FRU_FILE ){
+ for ( pcarrier_p2p=list_head[num_file];
+ pcarrier_p2p != NULL ;
+ pcarrier_p2p = pcarrier_p2p->next
+ ){
+ if ( pcarrier_p2p->data[PICMG_ID_OFFSET]
+ == FRU_AMC_CARRIER_P2P
+ ){
+ break;
+ }
+ }
+ break;
+ }
+ }
+ /*Determine the match making pair*/
+ while ( match_pair < argc ){
+ for ( num_file = (match_pair+1); num_file<argc; num_file++ ){
+ if ( ( file_type[match_pair] != CONFIG_FILE )
+ && ( file_type[num_file] != CONFIG_FILE )
+ ){
+ if ( ( file_type[match_pair] != ON_CARRIER_FRU_FILE )
+ || ( file_type[num_file] != ON_CARRIER_FRU_FILE )
+ ){
+ printf("%s vs %s\n",
+ val2str(file_type[match_pair],
+ ipmi_ekanalyzer_module_type),
+ val2str(file_type[num_file],
+ ipmi_ekanalyzer_module_type));
+ /*Ekeying match between 2 files*/
+ if (verbose>0){
+ printf("Start matching process\n");
+ }
+ return_value = ipmi_ek_matching_process( file_type,
+ match_pair, num_file, list_head,
+ list_last, opt, pcarrier_p2p);
+ }
+ }
+ }
+ match_pair ++;
+ }
+ for( num_file=0; num_file < argc; num_file++ ){
+ if (list_head[num_file] != NULL ){
+ ipmi_ek_remove_record_from_list( list_head[num_file],
+ &list_record[num_file], &list_last[num_file]);
+ }
+ if ( ( num_file == argc-1 ) && verbose )
+ printf("Record list has been removed successfully\n");
+ }
+ return_value = OK_STATUS;
+ }
+ }
+ }
+ return return_value;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_matching_process
+*
+* Description: This function process the OEM check, Physical Connectivity check,
+* and Link Descriptor comparison to do Ekeying match
+*
+* Restriction: None
+*
+* Input: file_type: a pointer that contain file type (on carrier file,
+* a1 file, b1 file...)
+* index1: position of the first record in the list of the record
+* index2: position of the second record in the list of the record
+* ipmi_ek_multi_header ** list_head: pointer to the header of a
+* linked list that contain FRU multi record
+* ipmi_ek_multi_header ** list_last: pointer to the tale of a
+* linked list that contain FRU multi record
+* opt: string that contain display option such as "match", "unmatch", or
+* "all".
+* pphysical: a pointer that contain a carrier p2p connectivity record
+* to perform physical check
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return OK_STATUS on success and ERROR_STATUS if the record doesn't
+* exist.
+*
+***************************************************************************/
+static int ipmi_ek_matching_process( int * file_type, int index1, int index2,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_last, char * opt,
+ struct ipmi_ek_multi_header * pphysical )
+{
+ int result = ERROR_STATUS;
+ struct ipmi_ek_multi_header * record;
+ int num_amc_record1 = 0;/*Number of AMC records in the first module*/
+ int num_amc_record2 = 0;/*Number of AMC records in the second module*/
+
+ /* Comparison between an On-Carrier and an AMC*/
+ if ( file_type[index2] == ON_CARRIER_FRU_FILE ){
+ int index_temp = 0;
+ index_temp = index1;
+ index1 = index2; /*index1 indicate on carrier*/
+ index2 = index_temp; /*index2 indcate an AMC*/
+ }
+ /*Calculate record size for Carrier file*/
+ for ( record=list_head[index1]; record != NULL;record = record->next ){
+ if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){
+ num_amc_record2++;
+ }
+ }
+ /*Calculate record size for amc file*/
+ for ( record=list_head[index2]; record != NULL;record = record->next){
+ if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){
+ num_amc_record1++;
+ }
+ }
+ if ( (num_amc_record1 > 0) && (num_amc_record2 > 0) ){
+ int index_record1 = 0;
+ int index_record2 = 0;
+ /* Multi records of AMC module */
+ struct ipmi_ek_amc_p2p_connectivity_record * amc_record1 = NULL;
+ /* Multi records of Carrier or an AMC module */
+ struct ipmi_ek_amc_p2p_connectivity_record * amc_record2 = NULL;
+
+ amc_record1 = malloc ( num_amc_record1 * \
+ sizeof(struct ipmi_ek_amc_p2p_connectivity_record));
+ amc_record2 = malloc ( num_amc_record2 * \
+ sizeof(struct ipmi_ek_amc_p2p_connectivity_record));
+
+ for (record=list_head[index2]; record != NULL;record = record->next){
+ if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){
+ result = ipmi_ek_create_amc_p2p_record( record,
+ &amc_record1[index_record1] );
+ if (result != ERROR_STATUS){
+ struct ipmi_ek_multi_header * current_record = NULL;
+
+ for ( current_record=list_head[index1];
+ current_record != NULL ;
+ current_record = current_record->next
+ ){
+ if ( current_record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){
+ result = ipmi_ek_create_amc_p2p_record( current_record,
+ &amc_record2[index_record2] );
+ if ( result != ERROR_STATUS ){
+ if ( result == OK_STATUS ){
+ /*Compare Link descriptor*/
+ result = ipmi_ek_compare_link ( pphysical,
+ amc_record1[index_record1],
+ amc_record2[index_record2],
+ opt, file_type[index1], file_type[index2]);
+ }
+ index_record2++;
+ }
+ } /*end of FRU_AMC_P2P */
+ } /* end of for loop */
+ index_record1++;
+ }
+ }
+ }
+ free(amc_record1) ;
+ amc_record1 = NULL;
+ free(amc_record2) ;
+ amc_record2 = NULL;
+ }
+ else{
+ printf("No amc record is found!\n");
+ }
+
+ return result;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_check_physical_connectivity
+*
+* Description: This function check for point to point connectivity between
+* two modules by comparing each enable port in link descriptor
+* with local and remote ports of port descriptor in
+* carrier point-to-point connectivity record according to the
+* corresponding file type ( a1, b1, b2...).
+*
+* Restriction: In order to perform physical check connectivity, it needs to
+* compare between 2 AMC Modules, so the use of index ( 1 and 2 )
+* can facilitate the comparison in this case.
+*
+* Input: record1: is an AMC p2p record for an AMC module
+* record2 is an AMC p2p record for an On-Carrier record or an AMC module
+* char* opt: option string that will tell if a matching result, unmatched
+* result or all the results will be displayed.
+* file_type1: indicates type of the first module
+* file_type2: indicates type of the second module
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return OK_STATUS if both link are matched, otherwise
+* return ERROR_STATUS
+*
+***************************************************************************/
+static int
+ipmi_ek_check_physical_connectivity(
+ struct ipmi_ek_amc_p2p_connectivity_record record1, int index1,
+ struct ipmi_ek_amc_p2p_connectivity_record record2, int index2,
+ struct ipmi_ek_multi_header * record,
+ int filetype1, int filetype2, char * option )
+{
+ int return_status = OK_STATUS;
+
+ if ( record == NULL ){
+ printf("NO Carrier p2p connectivity !\n");
+ return_status = ERROR_STATUS;
+ }
+ else{
+ #define INVALID_AMC_SITE_NUMBER -1
+ int index = START_DATA_OFFSET;
+ int amc_site = INVALID_AMC_SITE_NUMBER;
+ struct fru_picmgext_carrier_p2p_record rsc_desc;
+ struct fru_picmgext_carrier_p2p_descriptor * port_desc = NULL;
+
+ /* Get the physical connectivity record */
+ while ( index < record->header.len ) {
+ rsc_desc.resource_id = record->data[index++];
+ rsc_desc.p2p_count = record->data[index++];
+ /* carrier p2p record starts with on-carrier device */
+ if ( (rsc_desc.resource_id == record1.rsc_id)
+ ||
+ (rsc_desc.resource_id == record2.rsc_id)
+ ){
+ if (rsc_desc.p2p_count <= 0){
+ printf("No p2p count\n");
+ return_status = ERROR_STATUS;
+ }
+ else{
+ port_desc = malloc ( rsc_desc.p2p_count *
+ sizeof(struct fru_picmgext_carrier_p2p_descriptor) );
+ index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count,
+ index, port_desc, record );
+ amc_site = INVALID_AMC_SITE_NUMBER;
+ break;
+ }
+ }
+ else{ /* carrier p2p record starts with AMC module */
+ if (rsc_desc.resource_id == AMC_MODULE){
+ if (filetype1 != ON_CARRIER_FRU_FILE){
+ amc_site = filetype1;
+ }
+ else{
+ amc_site = filetype2;
+ }
+ }
+ else{
+ amc_site = rsc_desc.resource_id & 0x0f;
+ }
+ if ( amc_site > 0 ){
+ if ( (amc_site == filetype1) || (amc_site == filetype2) ){
+ port_desc = malloc ( rsc_desc.p2p_count *
+ sizeof(struct fru_picmgext_carrier_p2p_descriptor) );
+ index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count,
+ index, port_desc, record );
+ break;
+ }
+ }
+ else{
+ return_status = ERROR_STATUS;
+ }
+ }
+ /*If the record doesn't contain the same AMC site number in command
+ * line, go to the next record
+ */
+ index += ( sizeof(struct fru_picmgext_carrier_p2p_descriptor) *
+ rsc_desc.p2p_count );
+ }
+
+ if ( (port_desc != NULL) && (return_status != ERROR_STATUS) ){
+ int j=0;
+
+ for ( j = 0; j < rsc_desc.p2p_count; j++ ){
+ /* Compare only enable channel descriptor */
+ if ( record1.ch_desc[index1].lane0port != DISABLE_PORT ){
+ /* matching result from channel descriptor comparison */
+ tboolean match_lane = FALSE;
+
+ match_lane = ipmi_ek_compare_channel_descriptor (
+ record1.ch_desc[index1], record2.ch_desc[index2],
+ port_desc, j, rsc_desc.resource_id );
+
+ if ( match_lane ){
+ if ( filetype1 != ON_CARRIER_FRU_FILE ){
+ if ( (
+ (filetype1 == (rsc_desc.resource_id & 0x0f))
+ &&
+ (filetype2 ==(port_desc[j].remote_resource_id &0x0f))
+ )
+ ||
+ (
+ (filetype2 == (rsc_desc.resource_id & 0x0f))
+ &&
+ (filetype1 ==(port_desc[j].remote_resource_id &0x0f))
+ )
+ ){
+ if ( ! (strcmp(option, "unmatch") == 0) ){
+ printf("%s port %d ==> %s port %d\n",
+ val2str(filetype2, ipmi_ekanalyzer_module_type),
+ record1.ch_desc[index1].lane0port,
+ val2str(filetype1, ipmi_ekanalyzer_module_type),
+ record2.ch_desc[index2].lane0port);
+ }
+ return_status = OK_STATUS;
+
+ break;
+ }
+ else{
+ if (verbose == LOG_DEBUG){
+ printf("No point 2 point connectivity\n");
+ }
+ return_status = ERROR_STATUS;
+ }
+ }
+ else{
+ if ( (record2.rsc_id == (rsc_desc.resource_id) )
+ &&
+ (filetype2 == (port_desc[j].remote_resource_id & 0x0f))
+ ){
+ if ( ! (strcmp(option, "unmatch") == 0) ){
+ printf("%s port %d ==> %s port %d\n",
+ val2str(filetype2, ipmi_ekanalyzer_module_type),
+ record1.ch_desc[index1].lane0port,
+ val2str(filetype1, ipmi_ekanalyzer_module_type),
+ record2.ch_desc[index2].lane0port);
+ }
+ return_status = OK_STATUS;
+ break;
+ }
+ else if ( (filetype2 == (rsc_desc.resource_id & 0x0f) )
+ &&
+ (record2.rsc_id == (port_desc[j].remote_resource_id))
+ ){
+ if ( ! (strcmp(option, "unmatch") == 0) ){
+ printf("%s port %d ==> %s %x port %d\n",
+ val2str(filetype2, ipmi_ekanalyzer_module_type),
+ record1.ch_desc[index1].lane0port,
+ val2str(filetype1, ipmi_ekanalyzer_module_type),
+ record2.rsc_id,record2.ch_desc[index2].lane0port);
+ }
+ return_status = OK_STATUS;
+ break;
+ }
+ else{
+ if (verbose == LOG_DEBUG){
+ printf("No point 2 point connectivity\n");
+ }
+ return_status = ERROR_STATUS;
+ }
+ }
+ }
+ else{
+ if (verbose == LOG_DEBUG){
+ printf("No point 2 point connectivity\n");
+ }
+ return_status = ERROR_STATUS;
+ }
+ }
+ else{ /*If the link is disable, the result is always true*/
+ return_status = OK_STATUS;
+ }
+ }
+ }
+ else{
+ if (verbose == LOG_WARN){
+ printf("Invalid Carrier p2p connectivity record\n");
+ }
+ return_status = ERROR_STATUS;
+ }
+ if (port_desc != NULL){
+ free(port_desc);
+ port_desc = NULL;
+ }
+ }
+ return return_status;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_compare_link
+*
+* Description: This function compares link grouping id of each
+* amc p2p connectiviy record
+*
+* Restriction: None
+*
+* Input: record1: is an AMC p2p record for an AMC module
+* record2 is an AMC p2p record for an On-Carrier record or an AMC module
+* char* opt: option string that will tell if a matching result, unmatched
+* result or all the results will be displayed.
+* file_type1: indicates type of the first module
+* file_type2: indicates type of the second module
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return 0 if both link are matched, otherwise return -1
+*
+***************************************************************************/
+static int
+ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record,
+ struct ipmi_ek_amc_p2p_connectivity_record record1,
+ struct ipmi_ek_amc_p2p_connectivity_record record2, char * opt,
+ int file_type1, int file_type2 )
+{
+ int result = ERROR_STATUS;
+ int index1 = 0; /*index for AMC module*/
+ int index2 = 0; /*index for On-carrier type*/
+
+ record1.matching_result = malloc ( record1.link_desc_count * sizeof(int) );
+ record2.matching_result = malloc ( record2.link_desc_count * sizeof(int) );
+ /*Initialize all the matching_result to false*/
+ for( index2 = 0; index2 < record2.link_desc_count; index2++ ){
+ record2.matching_result[index2] = FALSE;
+ }
+ for( index1 = 0; index1 < record1.link_desc_count; index1++ ){
+ for( index2 = 0; index2 < record2.link_desc_count; index2++ ){
+ if( record1.link_desc[index1].group_id == 0 ){
+ if( record2.link_desc[index2].group_id == 0 ){
+ result = ipmi_ek_compare_link_descriptor(
+ record1, index1, record2, index2 );
+ if ( result == OK_STATUS ){
+ /*Calculate the index for Channel descriptor in function of
+ * link designator channel ID
+ */
+ /*first channel_id in the AMC Link descriptor of record1*/
+ static int flag_first_link1;
+ int index_ch_desc1; /*index of channel descriptor */
+ /*first channel_id in the AMC Link descriptor of record2*/
+ static int flag_first_link2;
+ int index_ch_desc2; /*index of channel descriptor*/
+
+ if (index1==0){ /*this indicate the first link is encounter*/
+ flag_first_link1 = record1.link_desc[index1].channel_id;
+ }
+ index_ch_desc1 = record1.link_desc[index1].channel_id -
+ flag_first_link1;
+ if (index2==0){
+ flag_first_link2 = record2.link_desc[index2].channel_id;
+ }
+ index_ch_desc2 = record2.link_desc[index2].channel_id -
+ flag_first_link2;
+ /*Check for physical connectivity for each link*/
+ result = ipmi_ek_check_physical_connectivity ( record1,
+ index_ch_desc1, record2, index_ch_desc2,
+ physic_record, file_type1, file_type2, opt );
+ if ( result == OK_STATUS ){
+ /*Display the result if option = match or all*/
+ if ( (strcmp( opt, "match" ) == 0)
+ || (strcmp( opt, "all" ) == 0)
+ || (strcmp( opt, "default" ) == 0)
+ ){
+ tboolean isOEMtype = FALSE;
+ printf(" Matching Result\n");
+ isOEMtype = ipmi_ek_display_link_descriptor( file_type1,
+ record2.rsc_id,
+ "From", record2.link_desc[index2]);
+ if (isOEMtype){
+ ipmi_ek_display_oem_guid (record2);
+ }
+ isOEMtype = ipmi_ek_display_link_descriptor( file_type2,
+ record1.rsc_id,
+ "To", record1.link_desc[index1] );
+ if (isOEMtype){
+ ipmi_ek_display_oem_guid (record1);
+ }
+ printf(" %s\n", STAR_LINE_LIMITER);
+ }
+ record2.matching_result[index2] = TRUE;
+ record1.matching_result[index1] = TRUE;
+ /*quit the fist loop since the match is found*/
+ index2 = record2.link_desc_count;
+ }
+ }
+ }
+ }
+ else { /*Link Grouping ID is non zero, Compare all link descriptor
+ * that has non-zero link grouping id together
+ */
+ if (record2.link_desc[index2].group_id != 0 ){
+ result = ipmi_ek_compare_link_descriptor(
+ record1, index1, record2, index2 );
+ if ( result == OK_STATUS ){
+ /*Calculate the index for Channel descriptor in function of
+ * link designator channel ID
+ */
+ /*first channel_id in the AMC Link descriptor of record1*/
+ static int flag_first_link1;
+ int index_ch_desc1; /*index of channel descriptor */
+ /*first channel_id in the AMC Link descriptor of record2*/
+ static int flag_first_link2;
+ int index_ch_desc2; /*index of channel descriptor*/
+
+ if (index1==0){ /*this indicate the first link is encounter*/
+ flag_first_link1 = record1.link_desc[index1].channel_id;
+ }
+ index_ch_desc1 = record1.link_desc[index1].channel_id -
+ flag_first_link1;
+ if (index2==0){
+ flag_first_link2 = record2.link_desc[index2].channel_id;
+ }
+ index_ch_desc2 = record2.link_desc[index2].channel_id -
+ flag_first_link2;
+ /*Check for physical connectivity for each link*/
+ result = ipmi_ek_check_physical_connectivity (
+ record1, index_ch_desc1, record2, index_ch_desc2,
+ physic_record, file_type1, file_type2, opt );
+ if ( result == OK_STATUS ){
+ if ( (strcmp( opt, "match" ) == 0)
+ || (strcmp( opt, "all" ) == 0)
+ || (strcmp( opt, "default" ) == 0)
+ ){
+ tboolean isOEMtype = FALSE;
+ printf(" Matching Result\n");
+ isOEMtype = ipmi_ek_display_link_descriptor( file_type1,
+ record2.rsc_id,
+ "From", record2.link_desc[index2] );
+ if ( isOEMtype ){
+ ipmi_ek_display_oem_guid (record2);
+ }
+ isOEMtype = ipmi_ek_display_link_descriptor( file_type2,
+ record1.rsc_id,
+ "To", record1.link_desc[index1] );
+ if (isOEMtype){
+ ipmi_ek_display_oem_guid (record1);
+ }
+ printf(" %s\n", STAR_LINE_LIMITER);
+ }
+ record2.matching_result[index2] = TRUE;
+ record1.matching_result[index1] = TRUE;
+ /*leave the fist loop since the match is found*/
+ index2 = record2.link_desc_count;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( (strcmp(opt, "unmatch") == 0) || (strcmp(opt, "all") == 0) ){
+ int isOEMtype = FALSE;
+ printf(" Unmatching result\n");
+ for (index1 = 0; index1 < record1.link_desc_count; index1++){
+ isOEMtype = ipmi_ek_display_link_descriptor( file_type2,
+ record1.rsc_id, "", record1.link_desc[index1] );
+ if ( isOEMtype ){
+ ipmi_ek_display_oem_guid (record1);
+ }
+ printf(" %s\n", STAR_LINE_LIMITER);
+ }
+ for ( index2 = 0; index2 < record2.link_desc_count; index2++){
+ if ( !record2.matching_result[index2] ){
+ isOEMtype = ipmi_ek_display_link_descriptor( file_type1,
+ record2.rsc_id, "", record2.link_desc[index2] );
+ if ( isOEMtype ){
+ ipmi_ek_display_oem_guid (record2);
+ }
+ printf(" %s\n", STAR_LINE_LIMITER);
+ }
+ }
+ }
+
+ free(record1.matching_result);
+ record1.matching_result = NULL;
+ free(record2.matching_result);
+ record2.matching_result = NULL;
+
+ return result;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_compare_channel_descriptor
+*
+* Description: This function compares 2 channel descriptors of 2 AMC
+* point-to-point connectivity records with port descriptor of
+* carrier point-to-point connectivity record. The comparison is
+* made between each enable port only.
+*
+* Restriction: Reference: AMC.0 specification:
+* - Table 3-14 for port descriptor
+* - Table 3-17 for channel descriptor
+*
+* Input: ch_desc1: first channel descriptor
+* ch_desc2: second channel descriptor
+* port_desc: a pointer that contain a list of port descriptor
+* index_port: index of the port descriptor
+* rsc_id: resource id that represents as local resource id in the
+* resource descriptor table.
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return TRUE if both channel descriptor are matched,
+* or FALSE otherwise
+*
+***************************************************************************/
+static tboolean
+ipmi_ek_compare_channel_descriptor(
+ struct fru_picmgext_amc_channel_desc_record ch_desc1,
+ struct fru_picmgext_amc_channel_desc_record ch_desc2,
+ struct fru_picmgext_carrier_p2p_descriptor * port_desc,
+ int index_port, unsigned char rsc_id )
+{
+ tboolean match_lane = FALSE;
+
+ /* carrier p2p record start with AMC_MODULE as local port */
+ if ( (rsc_id & AMC_MODULE) == AMC_MODULE ){
+ if ( (ch_desc1.lane0port == port_desc[index_port].local_port)
+ &&
+ (ch_desc2.lane0port == port_desc[index_port].remote_port)
+ ){
+ /*check if the port is enable*/
+ if (ch_desc1.lane1port != DISABLE_PORT){
+ index_port ++;
+ if ( (ch_desc1.lane1port == port_desc[index_port].local_port)
+ &&
+ (ch_desc2.lane1port == port_desc[index_port].remote_port)
+ ){
+ if (ch_desc1.lane2port != DISABLE_PORT){
+ index_port++;
+ if ( (ch_desc1.lane2port == port_desc[index_port].local_port)
+ &&
+ (ch_desc2.lane2port == port_desc[index_port].remote_port)
+ ){
+ if (ch_desc1.lane3port != DISABLE_PORT){
+ index_port++;
+ if ( (ch_desc1.lane3port ==
+ port_desc[index_port].local_port)
+ &&
+ (ch_desc2.lane3port ==
+ port_desc[index_port].remote_port)
+ ){
+ match_lane = TRUE;
+ }
+ }
+ else{
+ match_lane = TRUE;
+ }
+ } /* end of if lane2port */
+ }
+ else{
+ match_lane = TRUE;
+ }
+ } /* end of if lane1port */
+ }
+ else{ /*if the port is disable, the compare result is always true*/
+ match_lane = TRUE;
+ }
+ }/* end of if lane0port */
+ }
+ /* carrier p2p record start with Carrier as local port */
+ else{
+ if ( (ch_desc1.lane0port == port_desc[index_port].remote_port)
+ &&
+ (ch_desc2.lane0port == port_desc[index_port].local_port)
+ ){
+ if (ch_desc1.lane1port != DISABLE_PORT){
+ index_port ++;
+ if ( (ch_desc1.lane1port == port_desc[index_port].remote_port)
+ &&
+ (ch_desc2.lane1port == port_desc[index_port].local_port)
+ ){
+ if (ch_desc1.lane2port != DISABLE_PORT){
+ index_port++;
+ if ( (ch_desc1.lane2port == port_desc[index_port].remote_port)
+ &&
+ (ch_desc2.lane2port == port_desc[index_port].local_port)
+ ){
+ if (ch_desc1.lane3port != DISABLE_PORT){
+ index_port++;
+ if ( (ch_desc1.lane3port ==
+ port_desc[index_port].remote_port)
+ &&
+ (ch_desc2.lane3port ==
+ port_desc[index_port].local_port)
+ ){
+ match_lane = TRUE;
+ }
+ }
+ else{
+ match_lane = TRUE;
+ }
+ } /* end of if lane2port */
+ }
+ else{
+ match_lane = TRUE;
+ }
+ } /* end of if lane1port */
+ }
+ else{
+ match_lane = TRUE;
+ }
+ } /* end of if lane0port */
+ }
+
+ return match_lane;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_compare_link_descriptor
+*
+* Description: This function compares 2 link descriptors of 2
+* amc p2p connectiviy record
+*
+* Restriction: None
+*
+* Input: record1: AMC p2p connectivity record of the 1rst AMC or Carrier Module
+* index1: index of AMC link descriptor in 1rst record
+* record2: AMC p2p connectivity record of the 2nd AMC or Carrier Module
+* index1: index of AMC link descriptor in 2nd record
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return OK_STATUS if both link are matched,
+* otherwise return ERROR_STATUS
+*
+***************************************************************************/
+static int
+ipmi_ek_compare_link_descriptor(
+ struct ipmi_ek_amc_p2p_connectivity_record record1, int index1,
+ struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 )
+{
+ int result = ERROR_STATUS;
+
+ if (record1.link_desc[index1].type == record2.link_desc[index2].type){
+ /*if it is an OEM type, we compare the OEM GUID*/
+ if ( (record1.link_desc[index1].type >= LOWER_OEM_TYPE)
+ && (record1.link_desc[index1].type <= UPPER_OEM_TYPE)
+ ){
+ if ( (record1.guid_count == 0) && (record2.guid_count == 0) ){
+ /*there is no GUID for comparison, so the result is always OK*/
+ result = OK_STATUS;
+ }
+ else{
+ int i=0;
+ int j=0;
+
+ for( i=0; i<record1.guid_count; i++){
+ for( j=0; j < record2.guid_count; j++){
+ if( memcmp (&record1.oem_guid[i], &record2.oem_guid[j],
+ SIZE_OF_GUID )
+ == 0
+ ){
+ result = OK_STATUS;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else{
+ result = OK_STATUS;
+ }
+ if (result == OK_STATUS){
+ if (record1.link_desc[index1].type_ext
+ == record2.link_desc[index2].type_ext
+ ){
+ unsigned char asym[COMPARE_CANDIDATE];
+ int offset = 0;
+
+ asym[offset++] = record1.link_desc[index1].asym_match;
+ asym[offset] = record2.link_desc[index2].asym_match;
+ result = ipmi_ek_compare_asym ( asym );
+ if (result == OK_STATUS){
+ struct fru_picmgext_amc_link_desc_record link[COMPARE_CANDIDATE];
+ int index = 0;
+
+ link[index++] = record1.link_desc[index1];
+ link[index] = record2.link_desc[index2];
+ result = ipmi_ek_compare_number_of_enable_port( link );
+ }
+ else{
+ result = ERROR_STATUS;
+ }
+ }
+ else{
+ result = ERROR_STATUS;
+ }
+ }
+ }
+ else{
+ result = ERROR_STATUS;
+ }
+
+ return result;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_compare_asym
+*
+* Description: This function compares 2 asymetric match of 2
+* amc link descriptors
+*
+* Restriction: None
+*
+* Input: asym[COMPARE_CANDIDATE]: Contain 2 asymetric match for comparison
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return 0 if both asym. match are matched, otherwise return -1
+*
+***************************************************************************/
+
+static int
+ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] )
+{
+ int return_value = ERROR_STATUS;
+ int first_index = 0;
+ int second_index = 1;
+
+ if ( (asym[first_index] == 0) && (asym[second_index] == 0) ){
+ return_value = OK_STATUS;
+ }
+ else if ( (asym[first_index] & asym[second_index]) == 0 ){
+ return_value = OK_STATUS;
+ }
+ else{
+ return_value = ERROR_STATUS;
+ }
+ return return_value;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_compare_link_descriptor
+*
+* Description: This function compare number of enble port of Link designator
+*
+* Restriction: None
+*
+* Input: link_designator1: first link designator
+* link_designator2: second link designator
+*
+* Output: None
+*
+* Global: None
+*
+* Return: return 0 if both link are matched, otherwise return -1
+*
+***************************************************************************/
+static int
+ipmi_ek_compare_number_of_enable_port(
+ struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] )
+{
+ int amc_port_count = 0;
+ int carrier_port_count = 0;
+ int return_value = ERROR_STATUS;
+ int index = 0;
+
+ if (link_desc[index].port_flag_0){ /*bit 0 indicates port 0*/
+ amc_port_count++;
+ }
+ if (link_desc[index].port_flag_1){ /*bit 1 indicates port 1*/
+ amc_port_count++;
+ }
+ if (link_desc[index].port_flag_2){ /*bit 2 indicates port 2*/
+ amc_port_count++;
+ }
+ if (link_desc[index++].port_flag_3){ /*bit 3 indicates port 3*/
+ amc_port_count++;
+ }
+
+ /*2nd link designator*/
+ if (link_desc[index].port_flag_0){ /*bit 0 indicates port 0*/
+ carrier_port_count++;
+ }
+ if (link_desc[index].port_flag_1){ /*bit 1 indicates port 1*/
+ carrier_port_count++;
+ }
+ if (link_desc[index].port_flag_2){ /*bit 2 indicates port 2*/
+ carrier_port_count++;
+ }
+ if (link_desc[index].port_flag_3){ /*bit 3 indicates port 3*/
+ carrier_port_count++;
+ }
+
+ if(carrier_port_count == amc_port_count){
+
+ return_value = OK_STATUS;
+ }
+ else{
+ return_value = ERROR_STATUS;
+ }
+
+ return return_value;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_link_descriptor
+*
+* Description: Display the link descriptor of an AMC p2p connectivity record
+*
+* Restriction: See AMC.0 or PICMG 3.0 specification for detail about bit masks
+*
+* Input: file_type: module type.
+* rsc_id: resource id
+* char* str: indicates if it is a source (its value= "From") or a
+* destination (its value = "To"). ( it is set to "" if it is not
+* a source nor destination
+* link_desc: AMC link descriptor
+* asym: asymetric match
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static tboolean
+ipmi_ek_display_link_descriptor( int file_type, unsigned char rsc_id,
+ char * str, struct fru_picmgext_amc_link_desc_record link_desc )
+{
+ tboolean isOEMtype = FALSE;
+
+ if (file_type == ON_CARRIER_FRU_FILE){
+ printf(" - %s On-Carrier Device ID %d\n", str, (rsc_id & 0x0f) );
+ }
+ else{
+ printf(" - %s %s\n", str,
+ val2str(file_type,ipmi_ekanalyzer_module_type));
+ }
+
+ printf(" - Channel ID %d || ", link_desc.channel_id );
+ printf("%s", link_desc.port_flag_0 ? "Lane 0: enable" : "");
+ printf("%s", link_desc.port_flag_1 ? ", Lane 1: enable" : "");
+ printf("%s", link_desc.port_flag_2 ? ", Lane 2: enable" : "");
+ printf("%s", link_desc.port_flag_3 ? ", Lane 3: enable" : "");
+
+ printf("\n");
+ printf(" - Link Type: %s \n",
+ val2str (link_desc.type, ipmi_ekanalyzer_link_type) );
+ switch ( link_desc.type ){
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE:
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1:
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2:
+ printf(" - Link Type extension: %s\n",
+ val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_PCIE) );
+ printf(" - Link Group ID: %d || ", link_desc.group_id );
+ printf("Link Asym. Match: %d - %s\n",
+ link_desc.asym_match,
+ val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_PCIE) );
+ break;
+ case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET:
+ printf(" - Link Type extension: %s\n",
+ val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_ETHERNET) );
+ printf(" - Link Group ID: %d || ", link_desc.group_id );
+ printf("Link Asym. Match: %d - %s\n",
+ link_desc.asym_match,
+ val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_PCIE) );
+ break;
+ case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE:
+ printf(" - Link Type extension: %s\n",
+ val2str (link_desc.type_ext, ipmi_ekanalyzer_extension_STORAGE) );
+ printf(" - Link Group ID: %d || ", link_desc.group_id );
+ printf("Link Asym. Match: %d - %s\n",
+ link_desc.asym_match,
+ val2str (link_desc.asym_match, ipmi_ekanalyzer_asym_STORAGE) );
+ break;
+ default:
+ printf(" - Link Type extension: %i\n", link_desc.type_ext );
+ printf(" - Link Group ID: %d || ", link_desc.group_id );
+ printf("Link Asym. Match: %i\n", link_desc.asym_match);
+ break;
+ }
+ /*return as OEM type if link type indicates OEM*/
+ if ( (link_desc.type >= LOWER_OEM_TYPE)
+ &&
+ (link_desc.type <= UPPER_OEM_TYPE)
+ ){
+ isOEMtype = TRUE;
+ }
+
+ return isOEMtype;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_oem_guid
+*
+* Description: Display the oem guid of an AMC p2p connectivity record
+*
+* Restriction: None
+*
+* Input: amc_record: AMC p2p connectivity record
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_oem_guid(
+ struct ipmi_ek_amc_p2p_connectivity_record amc_record )
+{
+ int index_oem = 0;
+ int index = 0;
+
+ if ( amc_record.guid_count == 0 ){
+ printf("\tThere is no OEM GUID for this module\n");
+ }
+ for (index_oem = 0; index_oem < amc_record.guid_count; index_oem++){
+ printf(" - GUID: ");
+ for(index = 0; index < SIZE_OF_GUID; index++){
+ printf("%02x", amc_record.oem_guid[index_oem].guid[index]);
+ /*For a better look: putting a "-" after displaying four bytes of GUID*/
+ if (!(index % 4)){
+ printf("-");
+ }
+ }
+ printf("\n");
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_create_amc_p2p_record
+*
+* Description: this function create an AMC point 2 point connectivity record
+* that contain link descriptor, channel descriptor, oem guid
+*
+* Restriction: Reference: AMC.0 Specification Table 3-16
+*
+* Input: record: a pointer to FRU multi record
+*
+* Output: amc_record: a pointer to the created AMC p2p record
+*
+* Global: None
+*
+* Return: Return OK_STATUS on success, or ERROR_STATUS if no record has been
+* created.
+*
+***************************************************************************/
+static int
+ipmi_ek_create_amc_p2p_record(struct ipmi_ek_multi_header * record,
+ struct ipmi_ek_amc_p2p_connectivity_record * amc_record)
+{
+ int index_data = START_DATA_OFFSET;
+ int return_status = OK_STATUS;
+
+ amc_record->guid_count = record->data[index_data++];
+ if (amc_record->guid_count > 0) {
+ int index_oem = 0;
+ amc_record->oem_guid = malloc(amc_record->guid_count * \
+ sizeof(struct fru_picmgext_guid));
+ for (index_oem = 0; index_oem < amc_record->guid_count;
+ index_oem++) {
+ memcpy(&amc_record->oem_guid[index_oem].guid,
+ &record->data[index_data],
+ SIZE_OF_GUID);
+ index_data += (int)SIZE_OF_GUID;
+ }
+ amc_record->rsc_id = record->data[index_data++];
+ amc_record->ch_count = record->data[index_data++];
+ /* Calculate link descriptor count */
+ amc_record->link_desc_count = ((record->header.len) - 8 -
+ (SIZE_OF_GUID*amc_record->guid_count) -
+ (FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE *
+ amc_record->ch_count)) / 5 ;
+ } else {
+ amc_record->rsc_id = record->data[index_data++];
+ amc_record->ch_count = record->data[index_data++];
+ /* Calculate link descriptor count see spec AMC.0 for detail */
+ amc_record->link_desc_count = ((record->header.len) - 8 -
+ (FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE *
+ amc_record->ch_count)) / 5;
+ }
+
+ if (amc_record->ch_count > 0) {
+ int ch_index = 0;
+ amc_record->ch_desc = malloc((amc_record->ch_count) * \
+ sizeof(struct fru_picmgext_amc_channel_desc_record));
+ for (ch_index = 0; ch_index < amc_record->ch_count;
+ ch_index++) {
+ unsigned int data;
+ struct fru_picmgext_amc_channel_desc_record *src, *dst;
+ data = record->data[index_data] |
+ (record->data[index_data + 1] << 8) |
+ (record->data[index_data + 2] << 16);
+
+ src = (struct fru_picmgext_amc_channel_desc_record *)&data;
+ dst = (struct fru_picmgext_amc_channel_desc_record *)
+ &amc_record->ch_desc[ch_index];
+
+ dst->lane0port = src->lane0port;
+ dst->lane1port = src->lane1port;
+ dst->lane2port = src->lane2port;
+ dst->lane3port = src->lane3port;
+ index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE;
+ }
+ }
+ if (amc_record->link_desc_count > 0) {
+ int i=0;
+ amc_record->link_desc = malloc(amc_record->link_desc_count * \
+ sizeof(struct fru_picmgext_amc_link_desc_record));
+ for (i = 0; i< amc_record->link_desc_count; i++) {
+ unsigned int data[2];
+ struct fru_picmgext_amc_link_desc_record *src, *dst;
+ data[0] = record->data[index_data] |
+ (record->data[index_data + 1] << 8) |
+ (record->data[index_data + 2] << 16) |
+ (record->data[index_data + 3] << 24);
+
+ data[1] = record->data[index_data + 4];
+ src = (struct fru_picmgext_amc_link_desc_record*)&data;
+ dst = (struct fru_picmgext_amc_link_desc_record*)
+ &amc_record->link_desc[i];
+
+ dst->channel_id = src->channel_id;
+ dst->port_flag_0 = src->port_flag_0;
+ dst->port_flag_1 = src->port_flag_1;
+ dst->port_flag_2 = src->port_flag_2;
+ dst->port_flag_3 = src->port_flag_3;
+ dst->type = src->type;
+ dst->type_ext = src->type_ext;
+ dst->group_id = src->group_id;
+ dst->asym_match = src->asym_match;
+ index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE;
+ }
+ } else {
+ return_status = ERROR_STATUS;
+ }
+ return return_status;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_get_resource_descriptor
+*
+* Description: this function create the resource descriptor of Carrier p2p
+* connectivity record.
+*
+* Restriction: None
+*
+* Input: port_count: number of port count
+* index: index to the position of data start offset
+* record: a pointer to FRU multi record
+*
+* Output: port_desc: a pointer to the created resource descriptor
+*
+* Global: None
+*
+* Return: Return index that indicates the current position of data in record.
+*
+***************************************************************************/
+static int
+ipmi_ek_get_resource_descriptor( int port_count, int index,
+ struct fru_picmgext_carrier_p2p_descriptor * port_desc,
+ struct ipmi_ek_multi_header * record )
+{
+ int num_port = 0;
+
+ while ( num_port < port_count ){
+ memcpy ( &port_desc[num_port], &record->data[index],
+ sizeof (struct fru_picmgext_carrier_p2p_descriptor) );
+ index += sizeof (struct fru_picmgext_carrier_p2p_descriptor);
+ num_port++;
+ }
+
+ return index;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_fru_header
+*
+* Description: this function display FRU header offset from a FRU binary file
+*
+* Restriction: Reference: IPMI Platform Management FRU Information Storage
+* Definition V1.0, Section 8
+*
+* Input: filename: name of FRU binary file
+*
+* Output: None
+*
+* Global: None
+*
+* Return: Return OK_STATUS on sucess, ERROR_STATUS on error
+*
+***************************************************************************/
+static int
+ipmi_ek_display_fru_header(char * filename)
+{
+ FILE * input_file;
+ struct fru_header header;
+ int ret = 0;
+
+ input_file = fopen(filename, "r");
+ if (input_file == NULL) {
+ lprintf(LOG_ERR, "File '%s' not found.", filename);
+ return (ERROR_STATUS);
+ }
+ ret = fread(&header, sizeof (struct fru_header), 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Failed to read FRU header!");
+ fclose(input_file);
+ return (ERROR_STATUS);
+ }
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ printf("FRU Header Info\n");
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ printf("Format Version :0x%02x %s\n",
+ (header.version & 0x0f),
+ ((header.version & 0x0f) == 1) ? "" : "{unsupported}");
+ printf("Internal Use Offset :0x%02x\n", header.offset.internal);
+ printf("Chassis Info Offset :0x%02x\n", header.offset.chassis);
+ printf("Board Info Offset :0x%02x\n", header.offset.board);
+ printf("Product Info Offset :0x%02x\n", header.offset.product);
+ printf("MultiRecord Offset :0x%02x\n", header.offset.multi);
+ printf("Common header Checksum :0x%02x\n", header.checksum);
+
+ fclose(input_file);
+ return OK_STATUS;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_fru_header_detail
+*
+* Description: this function display detail FRU header information
+* from a FRU binary file.
+
+*
+* Restriction: Reference: IPMI Platform Management FRU Information Storage
+* Definition V1.0, Section 8
+*
+* Input: filename: name of FRU binary file
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static int
+ipmi_ek_display_fru_header_detail(char * filename)
+{
+# define FACTOR_OFFSET 8
+# define SIZE_MFG_DATE 3
+ FILE * input_file;
+ size_t file_offset = 0;
+ struct fru_header header;
+ time_t tval;
+ int ret = 0;
+ unsigned char data = 0;
+ unsigned char lan_code = 0;
+ unsigned char mfg_date[SIZE_MFG_DATE];
+ unsigned int board_length = 0;
+
+ input_file = fopen(filename, "r");
+ if (input_file == NULL) {
+ lprintf(LOG_ERR, "File '%s' not found.", filename);
+ return (-1);
+ }
+ /* The offset in each fru is in multiple of 8 bytes
+ * See IPMI Platform Management FRU Information Storage Definition
+ * for detail
+ */
+ ret = fread(&header, sizeof(struct fru_header), 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Failed to read FRU header!");
+ fclose(input_file);
+ return (-1);
+ }
+ /*** Display FRU Internal Use Info ***/
+ if (!feof(input_file)) {
+ unsigned char format_version;
+ unsigned long len = 0;
+
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ printf("FRU Internal Use Info\n");
+ printf("%s\n", EQUAL_LINE_LIMITER);
+
+ ret = fread(&format_version, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid format version!");
+ fclose(input_file);
+ return (-1);
+ }
+ printf("Format Version: %d\n", (format_version & 0x0f));
+
+ if (header.offset.chassis > 0) {
+ len = (header.offset.chassis * FACTOR_OFFSET)
+ - (header.offset.internal * FACTOR_OFFSET);
+ } else {
+ len = (header.offset.board * FACTOR_OFFSET)
+ - (header.offset.internal * FACTOR_OFFSET);
+ }
+ printf("Length: %ld\n", len);
+ printf("Data dump:\n");
+ while ((len > 0) && (!feof(input_file))) {
+ unsigned char data;
+ ret = fread(&data, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid data!");
+ fclose(input_file);
+ return (-1);
+ }
+ printf("0x%02x ", data);
+ len--;
+ }
+ printf("\n");
+ }
+ /*** Chassis Info Area ***/
+ if (header.offset.chassis != 0) {
+ long offset = 0;
+ offset = header.offset.chassis * FACTOR_OFFSET;
+ ret = ipmi_ek_display_chassis_info_area(input_file, offset);
+ }
+ /*** Display FRU Board Info Area ***/
+ while (1) {
+ if (header.offset.board == 0) {
+ break;
+ }
+ ret = fseek(input_file,
+ (header.offset.board * FACTOR_OFFSET),
+ SEEK_SET);
+ if (feof(input_file)) {
+ break;
+ }
+ file_offset = ftell(input_file);
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ printf("FRU Board Info Area\n");
+ printf("%s\n", EQUAL_LINE_LIMITER);
+
+ ret = fread(&data, 1, 1, input_file); /* Format version */
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid FRU Format Version!");
+ fclose(input_file);
+ return (-1);
+ }
+ printf("Format Version: %d\n", (data & 0x0f));
+ if (feof(input_file)) {
+ break;
+ }
+ ret = fread(&data, 1, 1, input_file); /* Board Area Length */
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Board Area Length!");
+ fclose(input_file);
+ return (-1);
+ }
+ board_length = (data * FACTOR_OFFSET);
+ printf("Area Length: %d\n", board_length);
+ /* Decrease the length of board area by 1 byte of format version
+ * and 1 byte for area length itself. the rest of this length will
+ * be used to check for additional custom mfg. byte
+ */
+ board_length -= 2;
+ if (feof(input_file)) {
+ break;
+ }
+ ret = fread(&lan_code, 1, 1, input_file); /* Language Code */
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Language Code in input");
+ fclose(input_file);
+ return (-1);
+ }
+ printf("Language Code: %d\n", lan_code);
+ board_length--;
+ /* Board Mfg Date */
+ if (feof(input_file)) {
+ break;
+ }
+
+ ret = fread(mfg_date, SIZE_MFG_DATE, 1, input_file);
+ if (ret != 1) {
+ lprintf(LOG_ERR, "Invalid Board Data.");
+ fclose(input_file);
+ return (-1);
+ }
+ tval = ((mfg_date[2] << 16) + (mfg_date[1] << 8)
+ + (mfg_date[0]));
+ tval = tval * 60;
+ tval = tval + secs_from_1970_1996;
+ printf("Board Mfg Date: %ld, %s", tval,
+ asctime(localtime(&tval)));
+ board_length -= SIZE_MFG_DATE;
+ /* Board Mfg */
+ file_offset = ipmi_ek_display_board_info_area(
+ input_file, "Board Manufacture Data", &board_length);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Board Product */
+ file_offset = ipmi_ek_display_board_info_area(
+ input_file, "Board Product Name", &board_length);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Board Serial */
+ file_offset = ipmi_ek_display_board_info_area(
+ input_file, "Board Serial Number", &board_length);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Board Part */
+ file_offset = ipmi_ek_display_board_info_area(
+ input_file, "Board Part Number", &board_length);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* FRU file ID */
+ file_offset = ipmi_ek_display_board_info_area(
+ input_file, "FRU File ID", &board_length);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Additional Custom Mfg. */
+ file_offset = ipmi_ek_display_board_info_area(
+ input_file, "Custom", &board_length);
+ break;
+ }
+ /* Product Info Area */
+ if (header.offset.product && (!feof(input_file))) {
+ long offset = 0;
+ offset = header.offset.product * FACTOR_OFFSET;
+ ret = ipmi_ek_display_product_info_area(input_file,
+ offset);
+ }
+ fclose(input_file);
+ return 0;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_chassis_info_area
+*
+* Description: this function displays detail format of product info area record
+* into humain readable text format
+*
+* Restriction: Reference: IPMI Platform Management FRU Information Storage
+* Definition V1.0, Section 10
+*
+* Input: input_file: pointer to file stream
+* offset: start offset of chassis info area
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static int
+ipmi_ek_display_chassis_info_area(FILE * input_file, long offset)
+{
+ size_t file_offset;
+ int ret = 0;
+ unsigned char data = 0;
+ unsigned char ch_len = 0;
+ unsigned char ch_type = 0;
+ unsigned int len;
+
+ if (input_file == NULL) {
+ lprintf(LOG_ERR, "No file stream to read.");
+ return (-1);
+ }
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ printf("Chassis Info Area\n");
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ ret = fseek(input_file, offset, SEEK_SET);
+ if (feof(input_file)) {
+ lprintf(LOG_ERR, "Invalid Chassis Info Area!");
+ return (-1);
+ }
+ ret = fread(&data, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Version Number!");
+ return (-1);
+ }
+ printf("Format Version Number: %d\n", (data & 0x0f));
+ ret = fread(&ch_len, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid length!");
+ return (-1);
+ }
+ /* len is in factor of 8 bytes */
+ len = ch_len * 8;
+ printf("Area Length: %d\n", len);
+ len -= 2;
+ if (feof(input_file)) {
+ return (-1);
+ }
+ /* Chassis Type*/
+ ret = fread(&ch_type, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Chassis Type!");
+ return (-1);
+ }
+ printf("Chassis Type: %d\n", ch_type);
+ len--;
+ /* Chassis Part Number*/
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Chassis Part Number", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Chassis Serial */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Chassis Serial Number", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Custom product info area */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Custom", &len);
+ return 0;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_board_info_area
+*
+* Description: this function displays board info area depending on board type
+* that pass in argument. Board type can be:
+* Manufacturer, Serial, Product or Part...
+*
+* Restriction: IPMI Platform Management FRU Information Storage
+* Definition V1.0, Section 11
+*
+* Input: input_file: pointer to file stream
+* board_type: a string that contain board type
+* board_length: length of info area
+*
+* Output: None
+*
+* Global: None
+*
+* Return: the current position of input_file
+*
+***************************************************************************/
+static size_t
+ipmi_ek_display_board_info_area(FILE * input_file, char * board_type,
+ unsigned int * board_length)
+{
+ size_t file_offset;
+ int ret = 0;
+ unsigned char len = 0;
+ unsigned int size_board = 0;
+ if (input_file == NULL || board_type == NULL
+ || board_length == NULL) {
+ return (size_t)(-1);
+ }
+ file_offset = ftell(input_file);
+
+ /* Board length*/
+ ret = fread(&len, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Length!");
+ goto out;
+ }
+ (*board_length)--;
+
+ /* Bit 5:0 of Board Mfg type represent legnth */
+ size_board = (len & 0x3f);
+ if (size_board == 0) {
+ printf("%s: None\n", board_type);
+ goto out;
+ }
+ if (strncmp(board_type, "Custom", 6 ) != 0) {
+ unsigned char *data;
+ unsigned int i = 0;
+ data = malloc(size_board);
+ if (data == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return (size_t)(-1);
+ }
+ ret = fread(data, size_board, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid board type size!");
+ free(data);
+ data = NULL;
+ goto out;
+ }
+ printf("%s type: 0x%02x\n", board_type, len);
+ printf("%s: ", board_type);
+ for (i = 0; i < size_board; i++) {
+ if ((len & TYPE_CODE) == TYPE_CODE) {
+ printf("%c", data[i]);
+ } else {
+ /* other than language code (binary, BCD,
+ * ASCII 6 bit...) is not supported
+ */
+ printf("%02x", data[i]);
+ }
+ }
+ printf("\n");
+ free(data);
+ data = NULL;
+ (*board_length) -= size_board;
+ goto out;
+ }
+ while (!feof(input_file)) {
+ if (len == NO_MORE_INFO_FIELD) {
+ unsigned char padding;
+ unsigned char checksum = 0;
+ /* take the rest of data in the area minus 1 byte of
+ * checksum
+ */
+ printf("Additional Custom Mfg. length: 0x%02x\n", len);
+ padding = (*board_length) - 1;
+ if ((padding > 0) && (!feof(input_file))) {
+ printf("Unused space: %d (bytes)\n", padding);
+ fseek(input_file, padding, SEEK_CUR);
+ }
+ ret = fread(&checksum, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Checksum!");
+ goto out;
+ }
+ printf("Checksum: 0x%02x\n", checksum);
+ goto out;
+ }
+ printf("Additional Custom Mfg. length: 0x%02x\n", len);
+ if ((size_board > 0) && (size_board < (*board_length))) {
+ unsigned char * additional_data = NULL;
+ unsigned int i = 0;
+ additional_data = malloc(size_board);
+ if (additional_data == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return (size_t)(-1);
+ }
+
+ ret = fread(additional_data, size_board, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Additional Data!");
+ goto out;
+ }
+ printf("Additional Custom Mfg. Data: %02x",
+ additional_data[0]);
+ for (i = 1; i < size_board; i++) {
+ printf("-%02x", additional_data[i]);
+ }
+ printf("\n");
+ free(additional_data);
+ additional_data = NULL;
+ (*board_length) -= size_board;
+ }
+ else {
+ printf("No Additional Custom Mfg. %d\n", *board_length);
+ goto out;
+ }
+ }
+
+out:
+ file_offset = ftell(input_file);
+ return file_offset;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_product_info_area
+*
+* Description: this function displays detail format of product info area record
+* into humain readable text format
+*
+* Restriction: Reference: IPMI Platform Management FRU Information Storage
+* Definition V1.0, Section 12
+*
+* Input: input_file: pointer to file stream
+* offset: start offset of product info area
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static int
+ipmi_ek_display_product_info_area(FILE * input_file, long offset)
+{
+ size_t file_offset;
+ int ret = 0;
+ unsigned char ch_len = 0;
+ unsigned char data = 0;
+ unsigned int len = 0;
+
+ if (input_file == NULL) {
+ lprintf(LOG_ERR, "No file stream to read.");
+ return (-1);
+ }
+ file_offset = ftell(input_file);
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ printf("Product Info Area\n");
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ ret = fseek(input_file, offset, SEEK_SET);
+ if (feof(input_file)) {
+ lprintf(LOG_ERR, "Invalid Product Info Area!");
+ return (-1);
+ }
+ ret = fread(&data, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Data!");
+ return (-1);
+ }
+ printf("Format Version Number: %d\n", (data & 0x0f));
+ if (feof(input_file)) {
+ return (-1);
+ }
+ /* Have to read this into a char or else
+ * it ends up byte swapped on big endian machines */
+ ret = fread(&ch_len, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Length!");
+ return (-1);
+ }
+ /* length is in factor of 8 bytes */
+ len = ch_len * 8;
+ printf("Area Length: %d\n", len);
+ len -= 2; /* -1 byte of format version and -1 byte itself */
+
+ ret = fread(&data, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Length!");
+ return (-1);
+ }
+
+ fread(&data, 1, 1, input_file);
+ printf("Language Code: %d\n", data);
+ len--;
+ /* Product Mfg */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Product Manufacture Data", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Product Name */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Product Name", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Product Part */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Product Part/Model Number", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Product Version */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Product Version", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Product Serial */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Product Serial Number", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Product Asset Tag */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Asset Tag", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* FRU file ID */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "FRU File ID", &len);
+ ret = fseek(input_file, file_offset, SEEK_SET);
+ /* Custom product info area */
+ file_offset = ipmi_ek_display_board_info_area(input_file,
+ "Custom", &len);
+ return 0;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_record
+*
+* Description: this function displays FRU multi record information.
+*
+* Restriction: None
+*
+* Input: record: a pointer to current record
+* list_head: a pointer to header of the list
+* list_last: a pointer to tale of the list
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_record( struct ipmi_ek_multi_header * record,
+ struct ipmi_ek_multi_header * list_head,
+ struct ipmi_ek_multi_header * list_last )
+{
+ if ( list_head == NULL ){
+ printf("***empty list***\n");
+ }
+ else{
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ printf("FRU Multi Info area\n");
+ printf("%s\n", EQUAL_LINE_LIMITER);
+ for ( record = list_head; record != NULL; record = record->next ){
+ printf("Record Type ID: 0x%02x\n", record->header.type);
+ printf("Record Format version: 0x%02x\n", record->header.format);
+ if (record->header.len > PICMG_ID_OFFSET){
+ /* In picmg3.0 specification, picmg record id lower than 4 or
+ * greater than 0x2d is not supported
+ */
+ #define PICMG_ID_LOWER_LIMIT 0x04
+ #define PICMG_ID_UPPER_LIMIT 0x2d
+ unsigned char picmg_id;
+
+ picmg_id = record->data[PICMG_ID_OFFSET];
+ printf("Manufacturer ID: %02x%02x%02x h\n", record->data[2],
+ record->data[1], record->data[0] );
+ if( ( picmg_id < PICMG_ID_LOWER_LIMIT )
+ ||
+ ( picmg_id > PICMG_ID_UPPER_LIMIT ) ){
+ printf("Picmg record ID: Unsupported {0x%02x}\n", picmg_id );
+ }
+ else{
+ printf("Picmg record ID: %s {0x%02x}\n",
+ val2str(picmg_id, ipmi_ekanalyzer_picmg_record_id),
+ picmg_id );
+ }
+ switch (picmg_id){
+ case FRU_PICMG_BACKPLANE_P2P: /*0x04*/
+ ipmi_ek_display_backplane_p2p_record (record);
+ break;
+ case FRU_PICMG_ADDRESS_TABLE: /*0x10*/
+ ipmi_ek_display_address_table_record (record);
+ break;
+ case FRU_PICMG_SHELF_POWER_DIST: /*0x11*/
+ ipmi_ek_display_shelf_power_distribution_record (record);
+ break;
+ case FRU_PICMG_SHELF_ACTIVATION: /*/0x12*/
+ ipmi_ek_display_shelf_activation_record (record);
+ break;
+ case FRU_PICMG_SHMC_IP_CONN: /*0x13*/
+ ipmi_ek_display_shelf_ip_connection_record (record);
+ break;
+ case FRU_PICMG_BOARD_P2P: /*0x14*/
+ ipmi_ek_display_board_p2p_record (record);
+ break;
+ case FRU_RADIAL_IPMB0_LINK_MAPPING: /*0x15*/
+ ipmi_ek_display_radial_ipmb0_record (record);
+ break;
+ case FRU_AMC_CURRENT: /*0x16*/
+ ipmi_ek_display_amc_current_record (record);
+ break;
+ case FRU_AMC_ACTIVATION: /*0x17*/
+ ipmi_ek_display_amc_activation_record (record);
+ break;
+ case FRU_AMC_CARRIER_P2P: /*0x18*/
+ ipmi_ek_display_carrier_connectivity (record);
+ break;
+ case FRU_AMC_P2P: /*0x19*/
+ ipmi_ek_display_amc_p2p_record (record);
+ break;
+ case FRU_AMC_CARRIER_INFO: /*0x1a*/
+ ipmi_ek_display_amc_carrier_info_record (record);
+ break;
+ case FRU_PICMG_CLK_CARRIER_P2P: /*0x2c*/
+ ipmi_ek_display_clock_carrier_p2p_record (record);
+ break;
+ case FRU_PICMG_CLK_CONFIG: /*0x2d*/
+ ipmi_ek_display_clock_config_record (record);
+ break;
+ default:
+ if (verbose > 0){
+ int i;
+ printf("%02x %02x %02x %02x %02x ", record->header.type,
+ record->header.format, record->header.len,
+ record->header.record_checksum,
+ record->header.header_checksum );
+ for ( i = 0; i < record->header.len; i++ ){
+ printf("%02x ", record->data[i]);
+ }
+ printf("\n");
+ }
+ break;
+ }
+ printf("%s\n", STAR_LINE_LIMITER);
+ }
+ }
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_backplane_p2p_record
+*
+* Description: this function displays backplane p2p record.
+*
+* Restriction: Reference: PICMG 3.0 Specification Table 3-40
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_backplane_p2p_record( struct ipmi_ek_multi_header * record )
+{
+ uint8_t index;
+ int offset = START_DATA_OFFSET;
+ struct fru_picmgext_slot_desc * slot_d
+ = (struct fru_picmgext_slot_desc*) &record->data[offset];
+
+ offset += sizeof(struct fru_picmgext_slot_desc);
+
+ while ( offset <= record->header.len ) {
+ printf(" Channel Type: ");
+ switch ( slot_d -> chan_type )
+ {
+ case 0x00:
+ case 0x07:
+ printf("PICMG 2.9\n");
+ break;
+ case 0x08:
+ printf("Single Port Fabric IF\n");
+ break;
+ case 0x09:
+ printf("Double Port Fabric IF\n");
+ break;
+ case 0x0a:
+ printf("Full Channel Fabric IF\n");
+ break;
+ case 0x0b:
+ printf("Base IF\n");
+ break;
+ case 0x0c:
+ printf("Update Channel IF\n");
+ break;
+ default:
+ printf("Unknown IF\n");
+ break;
+ }
+ printf(" Slot Address: %02x\n", slot_d -> slot_addr);
+ printf(" Channel Count: %i\n", slot_d -> chn_count);
+
+ for ( index = 0; index < (slot_d -> chn_count); index++ ) {
+ struct fru_picmgext_chn_desc * d
+ = (struct fru_picmgext_chn_desc *) &record->data[offset];
+
+ if ( verbose ){
+ printf( "\t"
+ "Chn: %02x --> "
+ "Chn: %02x in "
+ "Slot: %02x\n",
+ d->local_chn, d->remote_chn, d->remote_slot
+ );
+ }
+ offset += sizeof(struct fru_picmgext_chn_desc);
+ }
+ slot_d = (struct fru_picmgext_slot_desc*) &record->data[offset];
+ offset += sizeof(struct fru_picmgext_slot_desc);
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_address_table_record
+*
+* Description: this function displays address table record.
+*
+* Restriction: Reference: PICMG 3.0 Specification Table 3-6
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_address_table_record( struct ipmi_ek_multi_header * record )
+{
+ unsigned char entries = 0;
+ unsigned char i;
+ int offset = START_DATA_OFFSET;
+ #define SIZE_SHELF_ADDRESS_BYTE 20
+
+ printf(" Type/Len: 0x%02x\n", record->data[offset++]);
+ printf(" Shelf Addr: ");
+ for ( i = 0; i < SIZE_SHELF_ADDRESS_BYTE; i++ ){
+ printf("0x%02x ", record->data[offset++]);
+ }
+ printf("\n");
+
+ entries = record->data[offset++];
+ printf(" Addr Table Entries count: 0x%02x\n", entries);
+
+ for ( i = 0; i < entries; i++ ){
+ printf("\tHWAddr: 0x%02x - SiteNum: 0x%02x - SiteType: 0x%02x \n",
+ record->data[offset+0],
+ record->data[offset+1],
+ record->data[offset+2]);
+ offset += 3;
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_shelf_power_distribution_record
+*
+* Description: this function displays shelf power distribution record.
+*
+* Restriction: Reference: PICMG 3.0 Specification Table 3-70
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_shelf_power_distribution_record(
+ struct ipmi_ek_multi_header * record )
+{
+ int offset = START_DATA_OFFSET;
+ unsigned char i,j;
+ unsigned char feeds = 0;
+
+ feeds = record->data[offset++];
+ printf(" Number of Power Feeds: 0x%02x\n", feeds);
+
+ for (i=0; i<feeds; i++) {
+ unsigned char entries;
+ unsigned long max_ext = 0;
+ unsigned long max_int = 0;
+ max_ext = record->data[offset+0] | (record->data[offset+1]<<8);
+ printf(" Max External Available Current: %ld Amps\n", (max_ext*10) );
+
+ offset += 2;
+
+ max_int = record->data[offset+0] | (record->data[offset+1]<<8);
+ printf(" Max Internal Current:\t %ld Amps\n", (max_int*10));
+ offset += 2;
+ printf(" Min Expected Operating Voltage: %d Volts\n",
+ (record->data[offset++]/2));
+ entries = record->data[offset++];
+ printf(" Feed to FRU count: 0x%02x\n", entries);
+ for (j=0; j<entries; j++) {
+ printf("\tHW: 0x%02x", record->data[offset++]);
+ printf("\tFRU ID: 0x%02x\n", record->data[offset++]);
+ }
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_shelf_activation_record
+*
+* Description: this function displays shelf activation record.
+*
+* Restriction: Reference: PICMG 3.0 Specification Table 3-73
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_shelf_activation_record(
+ struct ipmi_ek_multi_header * record )
+{
+ unsigned char count = 0;
+ int offset = START_DATA_OFFSET;
+
+ printf(" Allowance for FRU Act Readiness: 0x%02x\n",
+ record->data[offset++]);
+ count = record->data[offset++];
+ printf(" FRU activation and Power Desc Cnt: 0x%02x\n", count);
+
+ while ( count > 0 ) {
+ printf(" FRU activation and Power descriptor:\n");
+ printf("\tHardware Address:\t\t0x%02x\n", record->data[offset++]);
+ printf("\tFRU Device ID:\t\t\t0x%02x\n", record->data[offset++]);
+ printf("\tMax FRU Power Capability:\t0x%04x Watts\n",
+ ( record->data[offset+0] | (record->data[offset+1]<<8) ));
+ offset += 2;
+ printf("\tConfiguration parameter:\t0x%02x\n", record->data[offset++]);
+ count --;
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_shelf_ip_connection_record
+*
+* Description: this function displays shelf ip connection record.
+*
+* Restriction: Fix me: Don't test yet
+* Reference: PICMG 3.0 Specification Table 3-31
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_shelf_ip_connection_record(
+ struct ipmi_ek_multi_header * record )
+{
+ int ioffset = START_DATA_OFFSET;
+ if (ioffset > record->header.len) {
+ printf(" Shelf Manager IP Address: %d.%d.%d.%d\n",
+ record->data[ioffset+0], record->data[ioffset+1],
+ record->data[ioffset+2], record->data[ioffset+3]);
+ ioffset += 4;
+ }
+ if (ioffset > record->header.len) {
+ printf(" Default Gateway Address: %d.%d.%d.%d\n",
+ record->data[ioffset+0], record->data[ioffset+1],
+ record->data[ioffset+2], record->data[ioffset+3]);
+ ioffset += 4;
+ }
+ if (ioffset > record->header.len) {
+ printf(" Subnet Mask: %d.%d.%d.%d\n",
+ record->data[ioffset+0], record->data[ioffset+1],
+ record->data[ioffset+2], record->data[ioffset+3]);
+ ioffset += 4;
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_shelf_fan_geography_record
+*
+* Description: this function displays shelf fan geography record.
+*
+* Restriction: Fix me: Don't test yet
+* Reference: PICMG 3.0 Specification Table 3-75
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_shelf_fan_geography_record(
+ struct ipmi_ek_multi_header * record )
+{
+ int ioffset = START_DATA_OFFSET;
+ unsigned char fan_count = 0;
+
+ fan_count = record->data[ioffset];
+ ioffset++;
+ printf(" Fan-to-FRU Entry Count: 0x%02x\n", fan_count);
+
+ while ( (fan_count > 0) && (ioffset <= record->header.len) ) {
+ printf(" Fan-to-FRU Mapping Entry: {%2x%2x%2x%2x}\n",
+ record->data[ioffset], record->data[ioffset+1],
+ record->data[ioffset+2], record->data[ioffset+3]
+ );
+ printf(" Hardware Address: 0x%02x\n", record->data[ioffset++]);
+ printf(" FRU device ID: 0x%02x\n", record->data[ioffset++]);
+ printf(" Site Number: 0x%02x\n", record->data[ioffset++]);
+ printf(" Site Type: 0x%02x\n", record->data[ioffset++]);
+ fan_count --;
+ }
+
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_board_p2p_record
+*
+* Description: this function displays board pont-to-point record.
+*
+* Restriction: Reference: PICMG 3.0 Specification Table 3-44
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_board_p2p_record( struct ipmi_ek_multi_header * record )
+{
+ unsigned char guid_count;
+ int offset = START_DATA_OFFSET;
+ int i = 0;
+
+ guid_count = record->data[offset++];
+ printf(" GUID count: %2d\n", guid_count);
+
+ for (i = 0 ; i < guid_count; i++ ) {
+ int j;
+ printf("\tGUID: ");
+ for (j=0; j < sizeof(struct fru_picmgext_guid); j++) {
+ printf("%02x", record->data[offset+j]);
+ }
+ printf("\n");
+ offset += sizeof(struct fru_picmgext_guid);
+ }
+
+ for ( offset;
+ offset < record->header.len;
+ offset += sizeof(struct fru_picmgext_link_desc)
+ ) {
+ /* to solve little endian /big endian problem */
+ unsigned long data;
+ struct fru_picmgext_link_desc * d;
+
+ data = (record->data[offset+0]) | (record->data[offset+1] << 8)\
+ | (record->data[offset+2] << 16)\
+ | (record->data[offset+3] << 24);
+
+ d = (struct fru_picmgext_link_desc *) &data;
+
+ printf(" Link Descriptor\n");
+ printf("\tLink Grouping ID:\t0x%02x\n", d->grouping);
+ printf("\tLink Type Extension:\t0x%02x - ", d->ext);
+
+ if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE){
+ switch (d->ext){
+ case 0:
+ printf("10/100/1000BASE-T Link (four-pair)\n");
+ break;
+ case 1:
+ printf("ShMC Cross-connect (two-pair)\n");
+ break;
+ default:
+ printf("Unknwon\n");
+ break;
+ }
+ }
+ else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET){
+ switch (d->ext){
+ case 0:
+ printf("Fixed 1000Base-BX\n");
+ break;
+ case 1:
+ printf("Fixed 10GBASE-BX4 [XAUI]\n");
+ break;
+ case 2:
+ printf("FC-PI\n");
+ break;
+ default:
+ printf("Unknwon\n");
+ break;
+ }
+ }
+ else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND){
+ printf("Unknwon\n");
+ }
+ else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR){
+ printf("Unknwon\n");
+ }
+ else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE){
+ printf("Unknwon\n");
+ }
+ else{
+ printf("Unknwon\n");
+ }
+
+ printf("\tLink Type:\t\t0x%02x - ",d->type);
+ if (d->type == 0 || d->type == 0xff){
+ printf("Reserved\n");
+ }
+ else if (d->type >= 0x06 && d->type <= 0xef) {
+ printf("Reserved\n");
+ }
+ else if (d->type >= LOWER_OEM_TYPE && d->type <= UPPER_OEM_TYPE) {
+ printf("OEM GUID Definition\n");
+ }
+ else {
+ switch (d->type){
+ case FRU_PICMGEXT_LINK_TYPE_BASE:
+ printf("PICMG 3.0 Base Interface 10/100/1000\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET:
+ printf("PICMG 3.1 Ethernet Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND:
+ printf("PICMG 3.2 Infiniband Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR:
+ printf("PICMG 3.3 Star Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_PCIE:
+ printf("PICMG 3.4 PCI Express Fabric Interface\n");
+ break;
+ default:
+ printf("Invalid\n");
+ break;
+ }
+ }
+ printf("\tLink Designator: \n");
+ printf("\t Port 0 Flag: %s\n",
+ (d->desig_port & 0x01) ? "enable" : "disable");
+ printf("\t Port 1 Flag: %s\n",
+ (d->desig_port & 0x02) ? "enable" : "disable");
+ printf("\t Port 2 Flag: %s\n",
+ (d->desig_port & 0x04) ? "enable" : "disable");
+ printf("\t Port 3 Flag: %s\n",
+ (d->desig_port & 0x08) ? "enable" : "disable");
+
+ printf("\t Interface: 0x%02x - ", d->desig_if);
+ switch (d->desig_if){
+ case FRU_PICMGEXT_DESIGN_IF_BASE:
+ printf("Base Interface\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_FABRIC:
+ printf("Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL:
+ printf("Update Channel\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_RESERVED:
+ printf("Reserved\n");
+ break;
+ default:
+ printf("Invalid");
+ break;
+ }
+ printf("\t Channel Number: 0x%02x\n", d->desig_channel);
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_radial_ipmb0_record
+*
+* Description: this function displays radial IPMB-0 record.
+*
+* Restriction: Fix me: Don't test yet
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_radial_ipmb0_record( struct ipmi_ek_multi_header * record )
+{
+ int offset = START_DATA_OFFSET;
+ #define SIZE_OF_CONNECTOR_DEFINER 3; /*bytes*/
+
+ /*Ref: PICMG 3.0 Specification Revision 2.0, Table 3-59*/
+ printf(" IPMB-0 Connector Definer: ");
+ #ifndef WORDS_BIGENDIAN
+ printf("%02x %02x %02x h\n", record->data[offset],
+ record->data[offset+1], record->data[offset+2]);
+ #else
+ printf("%02x %02x %02x h\n", record->data[offset+2],
+ record->data[offset+1], record->data[offset]);
+ #endif
+ /*3 bytes of connector definer was used*/
+ offset += SIZE_OF_CONNECTOR_DEFINER;
+
+ printf (" IPMB-0 Connector version ID: ");
+ #ifndef WORDS_BIGENDIAN
+ printf("%02x %02x h\n", record->data[offset], record->data[offset+1]);
+ #else
+ printf("%02x %02x h\n", record->data[offset+1], record->data[offset]);
+ #endif
+ offset += 2;
+
+ printf(" IPMB-0 Hub Descriptor Count: 0x%02x", record->data[offset++]);
+ if (record->data[offset] > 0){
+ for (offset; offset < record->header.len;){
+ unsigned char entry_count = 0;
+ printf(" IPMB-0 Hub Descriptor\n");
+ printf("\tHardware Address: 0x%02x\n", record->data[offset++]);
+ printf("\tHub Info {0x%02x}: ", record->data[offset]);
+ /* Bit mask specified in Table 3-59 of PICMG 3.0 Specification */
+ if ( (record->data[offset] & 0x01) == 0x01 ){
+ printf("IPMB-A only\n");
+ }
+ else if ( (record->data[offset] & 0x02) == 0x02 ){
+ printf("IPMB-B only\n");
+ }
+ else if ( (record->data[offset] & 0x03) == 0x03 ){
+ printf("IPMB-A and IPMB-B\n");
+ }
+ else{
+ printf("Reserved.\n");
+ }
+ offset ++;
+
+ entry_count = record->data[offset++];
+ printf("\tAddress Entry count: 0x%02x", entry_count);
+ while (entry_count > 0){
+ printf("\t Hardware Address: 0x%02x\n", record->data[offset++]);
+ printf("\t IPMB-0 Link Entry: 0x%02x\n",record->data[offset++]);
+ entry_count --;
+ }
+ }
+ }
+
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_amc_current_record
+*
+* Description: this function displays AMC current record.
+*
+* Restriction: None
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_amc_current_record( struct ipmi_ek_multi_header * record )
+{
+ unsigned char current;
+ current = record->data[START_DATA_OFFSET];
+ printf(" Current draw: %.1f A @ 12V => %.2f Watt\n",
+ (float) current/10.0, ((float)current/10.0)*12.0 );
+ printf("\n");
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_amc_activation_record
+*
+* Description: this function displays carrier activation and current management
+* record.
+*
+* Restriction: Reference: AMC.0 Specification Table 3-11 and Table 3-12
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_amc_activation_record( struct ipmi_ek_multi_header * record )
+{
+ uint16_t max_current;
+ int offset = START_DATA_OFFSET;
+
+ max_current = record->data[offset];
+ max_current |= record->data[++offset] << 8;
+ printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n",
+ (float) max_current / 10,
+ (float) max_current / 10 * 12);
+ printf(" Module Activation Readiness: %i sec.\n",
+ record->data[++offset]);
+
+ printf(" Descriptor Count: %i\n", record->data[++offset]);
+ for(++offset; (offset < record->header.len); offset += 3 )
+ {
+ struct fru_picmgext_activation_record * a =
+ (struct fru_picmgext_activation_record *) &record->data[offset];
+
+ printf("\tIPMB-Address:\t\t0x%x\n", a->ibmb_addr);
+ printf("\tMax. Module Current:\t%.2f A\n", (float)a->max_module_curr/10);
+ printf("\n");
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_amc_p2p_record
+*
+* Description: this function display amc p2p connectivity record in humain
+* readable text format
+*
+* Restriction: Reference: AMC.0 Specification Table 3-16
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_amc_p2p_record( struct ipmi_ek_multi_header * record )
+{
+ int index_data = START_DATA_OFFSET;
+ int oem_count = 0;
+ int ch_count = 0;
+ int index=0;
+
+ oem_count = record->data[index_data++];
+ printf("OEM GUID count: %02x\n", oem_count);
+
+ if ( oem_count > 0 ){
+ while ( oem_count > 0 ){
+ printf("OEM GUID: ");
+ for ( index = 1; index <= SIZE_OF_GUID; index++ ){
+ printf("%02x", record->data[index_data++]);
+ /* For a better look, display a "-" character after each 5 bytes
+ * of OEM GUID */
+ if ( !(index % 5) ){
+ printf("-");
+ }
+ }
+ printf("\n");
+ oem_count--;
+ }
+ }
+ if ( ( record->data[index_data] & AMC_MODULE ) == AMC_MODULE ){
+ printf("AMC module connection\n");
+ }
+ else{
+ printf("On-Carrier Device %02x h\n", ( record->data[index_data] & 0x0f ));
+ }
+ index_data ++;
+ ch_count = record->data[index_data++];
+ printf("AMC Channel Descriptor count: %02x h\n", ch_count);
+
+ if ( ch_count > 0 ){
+ for ( index = 0; index < ch_count; index++ ){
+ unsigned int data;
+ struct fru_picmgext_amc_channel_desc_record * ch_desc;
+ printf(" AMC Channel Descriptor {%02x%02x%02x}\n",
+ record->data[index_data+2], record->data[index_data+1],
+ record->data[index_data]
+ );
+ data = record->data[index_data] |
+ (record->data[index_data + 1] << 8) |
+ (record->data[index_data + 2] << 16);
+ ch_desc = ( struct fru_picmgext_amc_channel_desc_record * ) &data;
+ printf(" Lane 0 Port: %d\n", ch_desc->lane0port);
+ printf(" Lane 1 Port: %d\n", ch_desc->lane1port);
+ printf(" Lane 2 Port: %d\n", ch_desc->lane2port);
+ printf(" Lane 3 Port: %d\n\n", ch_desc->lane3port);
+ index_data += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE;
+ }
+ }
+ while ( index_data < record->header.len ){
+ /*Warning: For gcc version between 4.0 and 4.3 this code doesnt work*/
+ unsigned int data[2];
+ struct fru_picmgext_amc_link_desc_record *link_desc;
+ data[0] = record->data[index_data] |
+ (record->data[index_data + 1] << 8) |
+ (record->data[index_data + 2] << 16) |
+ (record->data[index_data + 3] << 24);
+ data[1] = record->data[index_data + 4];
+
+ link_desc = (struct fru_picmgext_amc_link_desc_record *) &data[0];
+
+ printf(" AMC Link Descriptor:\n" );
+
+ printf("\t- Link Type: %s \n",
+ val2str (link_desc->type, ipmi_ekanalyzer_link_type));
+ switch ( link_desc->type ) {
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE:
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1:
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2:
+ printf("\t- Link Type extension: %s\n",
+ val2str (link_desc->type_ext, ipmi_ekanalyzer_extension_PCIE));
+ printf("\t- Link Group ID: %d\n ", link_desc->group_id );
+ printf("\t- Link Asym. Match: %d - %s\n",
+ link_desc->asym_match,
+ val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE));
+ break;
+ case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET:
+ printf("\t- Link Type extension: %s\n",
+ val2str (link_desc->type_ext,
+ ipmi_ekanalyzer_extension_ETHERNET));
+ printf("\t- Link Group ID: %d \n", link_desc->group_id );
+ printf("\t- Link Asym. Match: %d - %s\n",
+ link_desc->asym_match,
+ val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE));
+ break;
+ case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE:
+ printf("\t- Link Type extension: %s\n",
+ val2str (link_desc->type_ext,
+ ipmi_ekanalyzer_extension_STORAGE));
+ printf("\t- Link Group ID: %d \n", link_desc->group_id );
+ printf("\t- Link Asym. Match: %d - %s\n",
+ link_desc->asym_match,
+ val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_STORAGE));
+ break;
+ default:
+ printf("\t- Link Type extension: %i (Unknown)\n", link_desc->type_ext );
+ printf("\t- Link Group ID: %d \n", link_desc->group_id );
+ printf("\t- Link Asym. Match: %i\n", link_desc->asym_match);
+ break;
+ }
+ printf("\t- AMC Link Designator:\n");
+ printf("\t Channel ID: %i\n", link_desc->channel_id);
+ printf("\t\t Lane 0: %s\n", (link_desc->port_flag_0)?"enable":"disable");
+ printf("\t\t Lane 1: %s\n", (link_desc->port_flag_1)?"enable":"disable");
+ printf("\t\t Lane 2: %s\n", (link_desc->port_flag_2)?"enable":"disable");
+ printf("\t\t Lane 3: %s\n", (link_desc->port_flag_3)?"enable":"disable");
+ index_data += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE;
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_amc_carrier_info_record
+*
+* Description: this function displays Carrier information table.
+*
+* Restriction: Reference: AMC.0 Specification Table 3-3
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: START_DATA_OFFSET
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_amc_carrier_info_record( struct ipmi_ek_multi_header * record )
+{
+ unsigned char extVersion;
+ unsigned char siteCount;
+ int offset = START_DATA_OFFSET;
+
+ extVersion = record->data[offset++];
+ siteCount = record->data[offset++];
+
+ printf(" AMC.0 extension version: R%d.%d\n", (extVersion >> 0)& 0x0F,
+ (extVersion >> 4)& 0x0F );
+ printf(" Carrier Sie Number Count: %d\n", siteCount);
+
+ while (siteCount > 0){
+ printf("\tSite ID (%d): %s \n", record->data[offset],
+ val2str(record->data[offset], ipmi_ekanalyzer_module_type) );
+ offset++;
+ siteCount--;
+ }
+ printf("\n");
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_clock_carrier_p2p_record
+*
+* Description: this function displays Carrier clock point-to-pont
+* connectivity record.
+*
+* Restriction: the following code is copy from ipmi_fru.c with modification in
+* reference to AMC.0 Specification Table 3-29
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_display_clock_carrier_p2p_record(
+ struct ipmi_ek_multi_header * record )
+{
+ unsigned char desc_count;
+ int i,j;
+ int offset = START_DATA_OFFSET;
+
+ desc_count = record->data[offset++];
+
+ for(i=0; i<desc_count; i++){
+ unsigned char resource_id;
+ unsigned char channel_count;
+
+ resource_id = record->data[offset++];
+ channel_count = record->data[offset++];
+
+ printf(" Clock Resource ID: 0x%02x\n", resource_id);
+ printf(" Type: ");
+ if((resource_id & 0xC0)>>6 == 0) {
+ printf("On-Carrier-Device\n");
+ }
+ else if((resource_id & 0xC0)>>6 == 1) {
+ printf("AMC slot\n");
+ }
+ else if((resource_id & 0xC0)>>6 == 2) {
+ printf("Backplane\n");
+ }
+ else{
+ printf("reserved\n");
+ }
+ printf(" Channel Count: 0x%02x\n", channel_count);
+
+ for(j=0; j<channel_count; j++){
+ unsigned char loc_channel, rem_channel, rem_resource;
+
+ loc_channel = record->data[offset++];
+ rem_channel = record->data[offset++];
+ rem_resource = record->data[offset++];
+
+ printf("\tCLK-ID: 0x%02x ---> ", loc_channel);
+ printf(" remote CLKID: 0x%02x ", rem_channel);
+ if((rem_resource & 0xC0)>>6 == 0) {
+ printf("[ Carrier-Dev");
+ }
+ else if((rem_resource & 0xC0)>>6 == 1) {
+ printf("[ AMC slot ");
+ }
+ else if((rem_resource & 0xC0)>>6 == 2) {
+ printf("[ Backplane ");
+ }
+ else{
+ printf("reserved ");
+ }
+ printf(" 0x%02x ]\n", rem_resource&0xF);
+ }
+ }
+ printf("\n");
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_display_clock_config_record
+*
+* Description: this function displays clock configuration record.
+*
+* Restriction: the following codes are copy from ipmi_fru.c with modification
+* in reference to AMC.0 Specification Table 3-35 and Table 3-36
+*
+* Input: record: a pointer to current record to be displayed
+*
+* Output: None
+*
+* Global: START_DATA_OFFSET
+*
+* Return: None
+*
+***************************************************************************/
+void
+ipmi_ek_display_clock_config_record( struct ipmi_ek_multi_header * record )
+{
+ unsigned char resource_id, descr_count;
+ int i;
+ int offset = START_DATA_OFFSET;
+
+ resource_id = record->data[offset++];
+ descr_count = record->data[offset++];
+ printf(" Clock Resource ID: 0x%02x\n", resource_id);
+ printf(" Clock Configuration Descriptor Count: 0x%02x\n", descr_count);
+
+ for(i=0; i<descr_count; i++){
+ unsigned char channel_id, control;
+ unsigned char indirect_cnt, direct_cnt;
+ int j=0;
+
+ channel_id = record->data[offset++];
+ control = record->data[offset++];
+ printf("\tCLK-ID: 0x%02x - ", channel_id);
+ printf("CTRL 0x%02x [ %12s ]\n", control,
+ ((control&0x1)==0)?"Carrier IPMC":"Application");
+
+ indirect_cnt = record->data[offset++];
+ direct_cnt = record->data[offset++];
+ printf("\t Count: Indirect 0x%02x / Direct 0x%02x\n", indirect_cnt,
+ direct_cnt );
+
+ /* indirect desc */
+ for(j=0; j<indirect_cnt; j++){
+ unsigned char feature;
+ unsigned char dep_chn_id;
+
+ feature = record->data[offset++];
+ dep_chn_id = record->data[offset++];
+ printf("\t\tFeature: 0x%02x [%8s] - ", feature,
+ (feature&0x1)==1?"Source":"Receiver");
+ printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id);
+ }
+
+ /* direct desc */
+ for(j=0; j<direct_cnt; j++){
+ unsigned char feature, family, accuracy;
+ unsigned long freq, min_freq, max_freq;
+
+ feature = record->data[offset++];
+ family = record->data[offset++];
+ accuracy = record->data[offset++];
+ freq = (record->data[offset+0] << 0 )
+ | (record->data[offset+1] << 8 )
+ | (record->data[offset+2] << 16)
+ | (record->data[offset+3] << 24);
+ offset += 4;
+ min_freq = (record->data[offset+0] << 0 )
+ | (record->data[offset+1] << 8 )
+ | (record->data[offset+2] << 16)
+ | (record->data[offset+3] << 24);
+ offset += 4;
+ max_freq = (record->data[offset+0] << 0 )
+ | (record->data[offset+1] << 8 )
+ | (record->data[offset+2] << 16)
+ | (record->data[offset+3] << 24);
+ offset += 4;
+
+ printf("\t- Feature: 0x%02x - PLL: %x / Asym: %s\n",
+ feature,
+ (feature > 1) & 1,
+ (feature&1)?"Source":"Receiver");
+ printf("\tFamily: 0x%02x - AccLVL: 0x%02x\n", family, accuracy);
+ printf("\tFRQ: %-9ld - min: %-9ld - max: %-9ld\n",
+ freq, min_freq, max_freq);
+ }
+ printf("\n");
+ }
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ekanalyzer_fru_file2structure
+*
+* Description: this function convert a FRU binary file into a linked list of
+* FRU multi record
+*
+* Restriction: None
+*
+* Input/Ouput: filename1: name of the file that contain FRU binary data
+* record: a pointer to current record
+* list_head: a pointer to header of the list
+* list_last: a pointer to tale of the list
+*
+* Global: None
+*
+* Return: return -1 as Error status, and 0 as Ok status
+*
+***************************************************************************/
+static int
+ipmi_ekanalyzer_fru_file2structure(char * filename,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_record,
+ struct ipmi_ek_multi_header ** list_last)
+{
+ FILE * input_file;
+ unsigned char data;
+ unsigned char last_record = 0;
+ unsigned int multi_offset = 0;
+ int record_count = 0;
+ int ret = 0;
+
+ input_file = fopen(filename, "r");
+ if (input_file == NULL) {
+ lprintf(LOG_ERR, "File: '%s' is not found", filename);
+ return ERROR_STATUS;
+ }
+
+ fseek(input_file, START_DATA_OFFSET, SEEK_SET);
+ data = 0;
+ ret = fread(&data, 1, 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Offset!");
+ fclose(input_file);
+ return ERROR_STATUS;
+ }
+ if (data == 0) {
+ lprintf(LOG_ERR, "There is no multi record in the file '%s'",
+ filename);
+ fclose(input_file);
+ return ERROR_STATUS;
+ }
+ /* the offset value is in multiple of 8 bytes. */
+ multi_offset = data * 8;
+ lprintf(LOG_DEBUG, "start multi offset = 0x%02x",
+ multi_offset );
+
+ fseek(input_file, multi_offset, SEEK_SET);
+ while (!feof(input_file)) {
+ *list_record = malloc(sizeof(struct ipmi_ek_multi_header));
+ ret = fread(&(*list_record)->header, START_DATA_OFFSET, 1,
+ input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Header!");
+ fclose(input_file);
+ return ERROR_STATUS;
+ }
+ if ((*list_record)->header.len == 0) {
+ record_count++;
+ continue;
+ }
+ (*list_record)->data = malloc((*list_record)->header.len);
+ if ((*list_record)->data == NULL) {
+ lprintf(LOG_ERR, "Failed to allocation memory size %d\n",
+ (*list_record)->header.len);
+ record_count++;
+ continue;
+ }
+
+ ret = fread((*list_record)->data, ((*list_record)->header.len),
+ 1, input_file);
+ if ((ret != 1) || ferror(input_file)) {
+ lprintf(LOG_ERR, "Invalid Record Data!");
+ fclose(input_file);
+ return ERROR_STATUS;
+ }
+ if (verbose > 0)
+ printf("Record %d has length = %02x\n", record_count,
+ (*list_record)->header.len);
+ if (verbose > 1) {
+ int i;
+ printf("Type: %02x", (*list_record)->header.type);
+ for (i = 0; i < ((*list_record)->header.len); i++) {
+ if (!(i % 8)) {
+ printf("\n0x%02x: ", i);
+ }
+ printf("%02x ",
+ (*list_record)->data[i]);
+ }
+ printf("\n\n");
+ }
+ ipmi_ek_add_record2list(list_record, list_head, list_last);
+ /* mask the 8th bits to see if it is the last record */
+ last_record = ((*list_record)->header.format) & 0x80;
+ if (last_record) {
+ break;
+ }
+ record_count++;
+ }
+ fclose(input_file);
+ return OK_STATUS;
+}
+
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_add_record2list
+*
+* Description: this function adds a sigle FRU multi record to a linked list of
+* FRU multi record.
+*
+* Restriction: None
+*
+* Input/Output: record: a pointer to current record
+* list_head: a pointer to header of the list
+* list_last: a pointer to tale of the list
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_last )
+{
+ if (*list_head == NULL) {
+ *list_head = *record;
+ (*record)->prev = NULL;
+ if (verbose > 2)
+ printf("Adding first record to list\n");
+ }
+ else {
+ (*list_last)->next = *record;
+ (*record)->prev = *list_last;
+ if (verbose > 2)
+ printf("Add 1 record to list\n");
+ }
+ *list_last = *record;
+ (*record)->next = NULL;
+}
+
+/**************************************************************************
+*
+* Function name: ipmi_ek_remove_record_from_list
+*
+* Description: this function removes a sigle FRU multi record from a linked
+* list of FRU multi record.
+*
+* Restriction: None
+*
+* Input/Output: record: a pointer to record to be deleted
+* list_head: a pointer to header of the list
+* list_last: a pointer to tale of the list
+*
+* Global: None
+*
+* Return: None
+*
+***************************************************************************/
+static void
+ipmi_ek_remove_record_from_list( struct ipmi_ek_multi_header * record,
+ struct ipmi_ek_multi_header ** list_head,
+ struct ipmi_ek_multi_header ** list_last )
+{
+ if (record->prev == NULL)
+ *list_head = record->next;
+ else
+ record->prev->next = record->next;
+ if ( record->next == NULL )
+ (*list_last) = record->prev;
+ else
+ record->next->prev = record->prev;
+ free(record);
+ record = NULL;
+}
+
+
+
+
diff --git a/lib/ipmi_event.c b/lib/ipmi_event.c
new file mode 100644
index 0000000..2f1032e
--- /dev/null
+++ b/lib/ipmi_event.c
@@ -0,0 +1,642 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_channel.h>
+#include <ipmitool/ipmi_event.h>
+#include <ipmitool/ipmi_sdr.h>
+
+
+static void
+ipmi_event_msg_print(struct ipmi_intf * intf, struct platform_event_msg * pmsg)
+{
+ struct sel_event_record sel_event;
+
+ memset(&sel_event, 0, sizeof(struct sel_event_record));
+
+ sel_event.record_id = 0;
+ sel_event.sel_type.standard_type.gen_id = 2;
+
+ sel_event.sel_type.standard_type.evm_rev = pmsg->evm_rev;
+ sel_event.sel_type.standard_type.sensor_type = pmsg->sensor_type;
+ sel_event.sel_type.standard_type.sensor_num = pmsg->sensor_num;
+ sel_event.sel_type.standard_type.event_type = pmsg->event_type;
+ sel_event.sel_type.standard_type.event_dir = pmsg->event_dir;
+ sel_event.sel_type.standard_type.event_data[0] = pmsg->event_data[0];
+ sel_event.sel_type.standard_type.event_data[1] = pmsg->event_data[1];
+ sel_event.sel_type.standard_type.event_data[2] = pmsg->event_data[2];
+
+ if (verbose)
+ ipmi_sel_print_extended_entry_verbose(intf, &sel_event);
+ else
+ ipmi_sel_print_extended_entry(intf, &sel_event);
+}
+
+static int
+ipmi_send_platform_event(struct ipmi_intf * intf, struct platform_event_msg * emsg)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[8];
+ uint8_t chmed;
+
+ memset(&req, 0, sizeof(req));
+ memset(rqdata, 0, 8);
+
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = 0x02;
+ req.msg.data = rqdata;
+
+ chmed = ipmi_current_channel_medium(intf);
+ if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) {
+ /* system interface, need extra generator ID */
+ req.msg.data_len = 8;
+ rqdata[0] = 0x41; // As per Fig. 29-2 and Table 5-4
+ memcpy(rqdata+1, emsg, sizeof(struct platform_event_msg));
+ }
+ else {
+ req.msg.data_len = 7;
+ memcpy(rqdata, emsg, sizeof(struct platform_event_msg));
+ }
+
+ ipmi_event_msg_print(intf, emsg);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Platform Event Message command failed");
+ return -1;
+ }
+ else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Platform Event Message command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+#define EVENT_THRESH_STATE_LNC_LO 0
+#define EVENT_THRESH_STATE_LNC_HI 1
+#define EVENT_THRESH_STATE_LCR_LO 2
+#define EVENT_THRESH_STATE_LCR_HI 3
+#define EVENT_THRESH_STATE_LNR_LO 4
+#define EVENT_THRESH_STATE_LNR_HI 5
+#define EVENT_THRESH_STATE_UNC_LO 6
+#define EVENT_THRESH_STATE_UNC_HI 7
+#define EVENT_THRESH_STATE_UCR_LO 8
+#define EVENT_THRESH_STATE_UCR_HI 9
+#define EVENT_THRESH_STATE_UNR_LO 10
+#define EVENT_THRESH_STATE_UNR_HI 11
+
+static const struct valstr ipmi_event_thresh_lo[] = {
+ { EVENT_THRESH_STATE_LNC_LO, "lnc" },
+ { EVENT_THRESH_STATE_LCR_LO, "lcr" },
+ { EVENT_THRESH_STATE_LNR_LO, "lnr" },
+ { EVENT_THRESH_STATE_UNC_LO, "unc" },
+ { EVENT_THRESH_STATE_UCR_LO, "ucr" },
+ { EVENT_THRESH_STATE_UNR_LO, "unr" },
+ { 0, NULL },
+};
+static const struct valstr ipmi_event_thresh_hi[] = {
+ { EVENT_THRESH_STATE_LNC_HI, "lnc" },
+ { EVENT_THRESH_STATE_LCR_HI, "lcr" },
+ { EVENT_THRESH_STATE_LNR_HI, "lnr" },
+ { EVENT_THRESH_STATE_UNC_HI, "unc" },
+ { EVENT_THRESH_STATE_UCR_HI, "ucr" },
+ { EVENT_THRESH_STATE_UNR_HI, "unr" },
+ { 0, NULL },
+};
+
+static int
+ipmi_send_platform_event_num(struct ipmi_intf * intf, int num)
+{
+ struct platform_event_msg emsg;
+
+ memset(&emsg, 0, sizeof(struct platform_event_msg));
+
+ /* IPMB/LAN/etc */
+ switch (num) {
+ case 1: /* temperature */
+ printf("Sending SAMPLE event: Temperature - "
+ "Upper Critical - Going High\n");
+ emsg.evm_rev = 0x04;
+ emsg.sensor_type = 0x01;
+ emsg.sensor_num = 0x30;
+ emsg.event_dir = EVENT_DIR_ASSERT;
+ emsg.event_type = 0x01;
+ emsg.event_data[0] = EVENT_THRESH_STATE_UCR_HI;
+ emsg.event_data[1] = 0xff;
+ emsg.event_data[2] = 0xff;
+ break;
+ case 2: /* voltage error */
+ printf("Sending SAMPLE event: Voltage Threshold - "
+ "Lower Critical - Going Low\n");
+ emsg.evm_rev = 0x04;
+ emsg.sensor_type = 0x02;
+ emsg.sensor_num = 0x60;
+ emsg.event_dir = EVENT_DIR_ASSERT;
+ emsg.event_type = 0x01;
+ emsg.event_data[0] = EVENT_THRESH_STATE_LCR_LO;
+ emsg.event_data[1] = 0xff;
+ emsg.event_data[2] = 0xff;
+ break;
+ case 3: /* correctable ECC */
+ printf("Sending SAMPLE event: Memory - Correctable ECC\n");
+ emsg.evm_rev = 0x04;
+ emsg.sensor_type = 0x0c;
+ emsg.sensor_num = 0x53;
+ emsg.event_dir = EVENT_DIR_ASSERT;
+ emsg.event_type = 0x6f;
+ emsg.event_data[0] = 0x00;
+ emsg.event_data[1] = 0xff;
+ emsg.event_data[2] = 0xff;
+ break;
+ default:
+ lprintf(LOG_ERR, "Invalid event number: %d", num);
+ return -1;
+ }
+
+ return ipmi_send_platform_event(intf, &emsg);
+}
+
+static int
+ipmi_event_find_offset(uint8_t code,
+ struct ipmi_event_sensor_types * evt,
+ char * desc)
+{
+ if (desc == NULL || code == 0)
+ return 0x00;
+
+ while (evt->type) {
+ if (evt->code == code && evt->desc != NULL &&
+ strncasecmp(desc, evt->desc, __maxlen(desc, evt->desc)) == 0)
+ return evt->offset;
+ evt++;
+ }
+
+ lprintf(LOG_WARN, "Unable to find matching event offset for '%s'", desc);
+ return -1;
+}
+
+static void
+print_sensor_states(uint8_t sensor_type, uint8_t event_type)
+{
+ ipmi_sdr_print_discrete_state_mini(
+ "Sensor States: \n ", "\n ", sensor_type,
+ event_type, 0xff, 0xff);
+ printf("\n");
+}
+
+
+static int
+ipmi_event_fromsensor(struct ipmi_intf * intf, char * id, char * state, char * evdir)
+{
+ struct ipmi_rs * rsp;
+ struct sdr_record_list * sdr;
+ struct platform_event_msg emsg;
+ int off;
+ uint8_t target, lun, channel;
+
+ if (id == NULL) {
+ lprintf(LOG_ERR, "No sensor ID supplied");
+ return -1;
+ }
+
+ memset(&emsg, 0, sizeof(struct platform_event_msg));
+ emsg.evm_rev = 0x04;
+
+ if (evdir == NULL)
+ emsg.event_dir = EVENT_DIR_ASSERT;
+ else if (strncasecmp(evdir, "assert", 6) == 0)
+ emsg.event_dir = EVENT_DIR_ASSERT;
+ else if (strncasecmp(evdir, "deassert", 8) == 0)
+ emsg.event_dir = EVENT_DIR_DEASSERT;
+ else {
+ lprintf(LOG_ERR, "Invalid event direction %s. Must be 'assert' or 'deassert'", evdir);
+ return -1;
+ }
+
+ printf("Finding sensor %s... ", id);
+ sdr = ipmi_sdr_find_sdr_byid(intf, id);
+ if (sdr == NULL) {
+ printf("not found!\n");
+ return -1;
+ }
+ printf("ok\n");
+
+ switch (sdr->type)
+ {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+
+ emsg.sensor_type = sdr->record.common->sensor.type;
+ emsg.sensor_num = sdr->record.common->keys.sensor_num;
+ emsg.event_type = sdr->record.common->event_type;
+ target = sdr->record.common->keys.owner_id;
+ lun = sdr->record.common->keys.lun;
+ channel = sdr->record.common->keys.channel;
+ break;
+ default:
+ lprintf(LOG_ERR, "Unknown sensor type for id '%s'", id);
+ return -1;
+ }
+
+ emsg.event_data[1] = 0xff;
+ emsg.event_data[2] = 0xff;
+
+ switch (emsg.event_type)
+ {
+ /*
+ * Threshold Class
+ */
+ case 1:
+ {
+ int dir = 0;
+ int hilo = 0;
+ off = 1;
+
+ if (state == NULL || strncasecmp(state, "list", 4) == 0) {
+ printf("Sensor States:\n");
+ printf(" lnr : Lower Non-Recoverable \n");
+ printf(" lcr : Lower Critical\n");
+ printf(" lnc : Lower Non-Critical\n");
+ printf(" unc : Upper Non-Critical\n");
+ printf(" ucr : Upper Critical\n");
+ printf(" unr : Upper Non-Recoverable\n");
+ return -1;
+ }
+
+ if (0 != strncasecmp(state, "lnr", 3) &&
+ 0 != strncasecmp(state, "lcr", 3) &&
+ 0 != strncasecmp(state, "lnc", 3) &&
+ 0 != strncasecmp(state, "unc", 3) &&
+ 0 != strncasecmp(state, "ucr", 3) &&
+ 0 != strncasecmp(state, "unr", 3))
+ {
+ lprintf(LOG_ERR, "Invalid threshold identifier %s", state);
+ return -1;
+ }
+
+ if (state[0] == 'u')
+ hilo = 1;
+ else
+ hilo = 0;
+
+ if (emsg.event_dir == EVENT_DIR_ASSERT)
+ dir = hilo;
+ else
+ dir = !hilo;
+
+ if ((emsg.event_dir == EVENT_DIR_ASSERT && hilo == 1) ||
+ (emsg.event_dir == EVENT_DIR_DEASSERT && hilo == 0))
+ emsg.event_data[0] = (uint8_t)(str2val(state, ipmi_event_thresh_hi) & 0xf);
+ else if ((emsg.event_dir == EVENT_DIR_ASSERT && hilo == 0) ||
+ (emsg.event_dir == EVENT_DIR_DEASSERT && hilo == 1))
+ emsg.event_data[0] = (uint8_t)(str2val(state, ipmi_event_thresh_lo) & 0xf);
+ else {
+ lprintf(LOG_ERR, "Invalid Event");
+ return -1;
+ }
+
+ rsp = ipmi_sdr_get_sensor_thresholds(intf, emsg.sensor_num,
+ target, lun, channel);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Command Get Sensor Thresholds failed: invalid response.");
+ return (-1);
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Command Get Sensor Thresholds failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /* threshold reading */
+ emsg.event_data[2] = rsp->data[(emsg.event_data[0] / 2) + 1];
+
+ rsp = ipmi_sdr_get_sensor_hysteresis(intf, emsg.sensor_num,
+ target, lun, channel);
+ if (rsp != NULL && rsp->ccode == 0)
+ off = dir ? rsp->data[0] : rsp->data[1];
+ if (off <= 0)
+ off = 1;
+
+ /* trigger reading */
+ if (dir) {
+ if ((emsg.event_data[2] + off) > 0xff)
+ emsg.event_data[1] = 0xff;
+ else
+ emsg.event_data[1] = emsg.event_data[2] + off;
+ }
+ else {
+ if ((emsg.event_data[2] - off) < 0)
+ emsg.event_data[1] = 0;
+ else
+ emsg.event_data[1] = emsg.event_data[2] - off;
+ }
+
+ /* trigger in byte 2, threshold in byte 3 */
+ emsg.event_data[0] |= 0x50;
+ }
+ break;
+
+ /*
+ * Digital Discrete
+ */
+ case 3: case 4: case 5: case 6: case 8: case 9:
+ {
+ int x;
+ const char * digi_on[] = { "present", "assert", "limit",
+ "fail", "yes", "on", "up" };
+ const char * digi_off[] = { "absent", "deassert", "nolimit",
+ "nofail", "no", "off", "down" };
+ /*
+ * print list of available states for this sensor
+ */
+ if (state == NULL || strncasecmp(state, "list", 4) == 0) {
+ print_sensor_states(emsg.sensor_type, emsg.event_type);
+ printf("Sensor State Shortcuts:\n");
+ for (x = 0; x < sizeof(digi_on)/sizeof(*digi_on); x++) {
+ printf(" %-9s %-9s\n", digi_on[x], digi_off[x]);
+ }
+ return 0;
+ }
+
+ off = 0;
+ for (x = 0; x < sizeof(digi_on)/sizeof(*digi_on); x++) {
+ if (strncasecmp(state, digi_on[x], strlen(digi_on[x])) == 0) {
+ emsg.event_data[0] = 1;
+ off = 1;
+ break;
+ }
+ else if (strncasecmp(state, digi_off[x], strlen(digi_off[x])) == 0) {
+ emsg.event_data[0] = 0;
+ off = 1;
+ break;
+ }
+ }
+ if (off == 0) {
+ off = ipmi_event_find_offset(
+ emsg.event_type, generic_event_types, state);
+ if (off < 0)
+ return -1;
+ emsg.event_data[0] = off;
+ }
+ }
+ break;
+
+ /*
+ * Generic Discrete
+ */
+ case 2: case 7: case 10: case 11: case 12:
+ {
+ /*
+ * print list of available states for this sensor
+ */
+ if (state == NULL || strncasecmp(state, "list", 4) == 0) {
+ print_sensor_states(emsg.sensor_type, emsg.event_type);
+ return 0;
+ }
+ off = ipmi_event_find_offset(
+ emsg.event_type, generic_event_types, state);
+ if (off < 0)
+ return -1;
+ emsg.event_data[0] = off;
+ }
+ break;
+
+ /*
+ * Sensor-Specific Discrete
+ */
+ case 0x6f:
+ {
+ /*
+ * print list of available states for this sensor
+ */
+ if (state == NULL || strncasecmp(state, "list", 4) == 0) {
+ print_sensor_states(emsg.sensor_type, emsg.event_type);
+ return 0;
+ }
+ off = ipmi_event_find_offset(
+ emsg.sensor_type, sensor_specific_types, state);
+ if (off < 0)
+ return -1;
+ emsg.event_data[0] = off;
+ }
+ break;
+
+ default:
+ return -1;
+
+ }
+
+ return ipmi_send_platform_event(intf, &emsg);
+}
+
+static int
+ipmi_event_fromfile(struct ipmi_intf * intf, char * file)
+{
+ FILE * fp;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct sel_event_record sel_event;
+ uint8_t rqdata[8];
+ char buf[1024];
+ char * ptr, * tok;
+ int i, j;
+ uint8_t chmed;
+ int rc = 0;
+
+ if (file == NULL)
+ return -1;
+
+ memset(rqdata, 0, 8);
+
+ /* setup Platform Event Message command */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = 0x02;
+ req.msg.data = rqdata;
+ req.msg.data_len = 7;
+
+ chmed = ipmi_current_channel_medium(intf);
+ if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) {
+ /* system interface, need extra generator ID */
+ rqdata[0] = 0x41; // As per Fig. 29-2 and Table 5-4
+ req.msg.data_len = 8;
+ }
+
+ fp = ipmi_open_file_read(file);
+ if (fp == NULL)
+ return -1;
+
+ while (feof(fp) == 0) {
+ if (fgets(buf, 1024, fp) == NULL)
+ continue;
+
+ /* clip off optional comment tail indicated by # */
+ ptr = strchr(buf, '#');
+ if (ptr)
+ *ptr = '\0';
+ else
+ ptr = buf + strlen(buf);
+
+ /* clip off trailing and leading whitespace */
+ ptr--;
+ while (isspace((int)*ptr) && ptr >= buf)
+ *ptr-- = '\0';
+ ptr = buf;
+ while (isspace((int)*ptr))
+ ptr++;
+ if (strlen(ptr) == 0)
+ continue;
+
+ /* parse the event, 7 bytes with optional comment */
+ /* 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # event */
+ i = 0;
+ tok = strtok(ptr, " ");
+ while (tok) {
+ if (i == 7)
+ break;
+ j = i++;
+ if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM)
+ j++;
+ rqdata[j] = (uint8_t)strtol(tok, NULL, 0);
+ tok = strtok(NULL, " ");
+ }
+ if (i < 7) {
+ lprintf(LOG_ERR, "Invalid Event: %s",
+ buf2str(rqdata, sizeof(rqdata)));
+ continue;
+ }
+
+ memset(&sel_event, 0, sizeof(struct sel_event_record));
+ sel_event.record_id = 0;
+ sel_event.sel_type.standard_type.gen_id = 2;
+
+ j = (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) ? 1 : 0;
+ sel_event.sel_type.standard_type.evm_rev = rqdata[j++];
+ sel_event.sel_type.standard_type.sensor_type = rqdata[j++];
+ sel_event.sel_type.standard_type.sensor_num = rqdata[j++];
+ sel_event.sel_type.standard_type.event_type = rqdata[j] & 0x7f;
+ sel_event.sel_type.standard_type.event_dir = (rqdata[j++] & 0x80) >> 7;
+ sel_event.sel_type.standard_type.event_data[0] = rqdata[j++];
+ sel_event.sel_type.standard_type.event_data[1] = rqdata[j++];
+ sel_event.sel_type.standard_type.event_data[2] = rqdata[j++];
+
+ ipmi_sel_print_std_entry(intf, &sel_event);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Platform Event Message command failed");
+ rc = -1;
+ }
+ else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Platform Event Message command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ rc = -1;
+ }
+ }
+
+ fclose(fp);
+ return rc;
+}
+
+static void
+ipmi_event_usage(void)
+{
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, "usage: event <num>");
+ lprintf(LOG_NOTICE, " Send generic test events");
+ lprintf(LOG_NOTICE, " 1 : Temperature - Upper Critical - Going High");
+ lprintf(LOG_NOTICE, " 2 : Voltage Threshold - Lower Critical - Going Low");
+ lprintf(LOG_NOTICE, " 3 : Memory - Correctable ECC");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, "usage: event file <filename>");
+ lprintf(LOG_NOTICE, " Read and generate events from file");
+ lprintf(LOG_NOTICE, " Use the 'sel save' command to generate from SEL");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, "usage: event <sensorid> <state> [event_dir]");
+ lprintf(LOG_NOTICE, " sensorid : Sensor ID string to use for event data");
+ lprintf(LOG_NOTICE, " state : Sensor state, use 'list' to see possible states for sensor");
+ lprintf(LOG_NOTICE, " event_dir : assert, deassert [default=assert]");
+ lprintf(LOG_NOTICE, "");
+}
+
+int
+ipmi_event_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
+ ipmi_event_usage();
+ return 0;
+ }
+ if (strncmp(argv[0], "file", 4) == 0) {
+ if (argc < 2) {
+ ipmi_event_usage();
+ return 0;
+ }
+ return ipmi_event_fromfile(intf, argv[1]);
+ }
+ if (strlen(argv[0]) == 1) {
+ switch (argv[0][0]) {
+ case '1': return ipmi_send_platform_event_num(intf, 1);
+ case '2': return ipmi_send_platform_event_num(intf, 2);
+ case '3': return ipmi_send_platform_event_num(intf, 3);
+ }
+ }
+ if (argc < 2)
+ rc = ipmi_event_fromsensor(intf, argv[0], NULL, NULL);
+ else if (argc < 3)
+ rc = ipmi_event_fromsensor(intf, argv[0], argv[1], NULL);
+ else
+ rc = ipmi_event_fromsensor(intf, argv[0], argv[1], argv[2]);
+
+ return rc;
+}
diff --git a/lib/ipmi_firewall.c b/lib/ipmi_firewall.c
new file mode 100644
index 0000000..8bda398
--- /dev/null
+++ b/lib/ipmi_firewall.c
@@ -0,0 +1,1191 @@
+/*
+ * Copyright (c) 2005 International Business Machines, Inc. All Rights Reserved.
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/bswap.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_firewall.h>
+#include <ipmitool/ipmi_strings.h>
+
+static void
+printf_firewall_usage(void)
+{
+ lprintf(LOG_NOTICE,
+"Firmware Firewall Commands:");
+ lprintf(LOG_NOTICE,
+"\tinfo [channel H] [lun L]");
+ lprintf(LOG_NOTICE,
+"\tinfo [channel H] [lun L [netfn N [command C [subfn S]]]]");
+ lprintf(LOG_NOTICE,
+"\tenable [channel H] [lun L [netfn N [command C [subfn S]]]]");
+ lprintf(LOG_NOTICE,
+"\tdisable [channel H] [lun L [netfn N [command C [subfn S]]]] [force])");
+ lprintf(LOG_NOTICE,
+"\treset [channel H]");
+ lprintf(LOG_NOTICE,
+"\t\twhere H is a Channel, L is a LUN, N is a NetFn,");
+ lprintf(LOG_NOTICE,
+"\t\tC is a Command and S is a Sub-Function");
+}
+
+void
+printf_firewall_info_usage(void)
+{
+ lprintf(LOG_NOTICE,
+"info [channel H]");
+ lprintf(LOG_NOTICE,
+"\tList all of the firewall information for all LUNs, NetFns");
+ lprintf(LOG_NOTICE,
+"\tand Commands, This is a long list and is not very human readable.");
+ lprintf(LOG_NOTICE,
+"info [channel H] lun L");
+ lprintf(LOG_NOTICE,
+"\tThis also prints a long list that is not very human readable.");
+ lprintf(LOG_NOTICE,
+"info [channel H] lun L netfn N");
+ lprintf(LOG_NOTICE,
+"\tThis prints out information for a single LUN/NetFn pair.");
+ lprintf(LOG_NOTICE,
+"\tThat is not really very usable, but at least it is short.");
+ lprintf(LOG_NOTICE,
+"info [channel H] lun L netfn N command C");
+ lprintf(LOG_NOTICE,
+"\tThis is the one you want -- it prints out detailed human");
+ lprintf(LOG_NOTICE,
+"\treadable information. It shows the support, configurable, and");
+ lprintf(LOG_NOTICE,
+"\tenabled bits for the Command C on LUN/NetFn pair L,N and the");
+ lprintf(LOG_NOTICE,
+"\tsame information about each of its Sub-functions.");
+}
+
+// print n bytes of bit field bf (if invert, print ~bf)
+static void print_bitfield(const unsigned char * bf, int n, int invert, int loglevel) {
+ int i = 0;
+ if (loglevel < 0) {
+ while (i<n) {
+ printf("%02x", (unsigned char) (invert?~bf[i]:bf[i]));
+ if (++i % 4 == 0)
+ printf(" ");
+ }
+ printf("\n");
+ } else {
+ while (i<n) {
+ lprintf(loglevel, "%02x", (unsigned char) (invert?~bf[i]:bf[i]));
+ if (++i % 4 == 0)
+ lprintf(loglevel, " ");
+ }
+ lprintf(loglevel, "\n");
+ }
+
+}
+
+static int
+ipmi_firewall_parse_args(int argc, char ** argv, struct ipmi_function_params * p)
+{
+ int i;
+ uint8_t conv_err = 0;
+
+ if (!p) {
+ lprintf(LOG_ERR, "ipmi_firewall_parse_args: p is NULL");
+ return -1;
+ }
+ for (i=0; i<argc; i++) {
+ if (strncmp(argv[i], "channel", 7) == 0 && (++i < argc)) {
+ uint8_t channel_tmp = 0;
+ if (is_ipmi_channel_num(argv[i], &channel_tmp) != 0) {
+ conv_err = 1;
+ break;
+ } else {
+ p->channel = channel_tmp;
+ }
+ }
+ else if (strncmp(argv[i], "lun", 3) == 0 && (++i < argc)) {
+ if (str2int(argv[i], &(p->lun)) != 0) {
+ lprintf(LOG_ERR, "Given lun '%s' is invalid.", argv[i]);
+ conv_err = 1;
+ break;
+ }
+ }
+ else if (strncmp(argv[i], "force", 5) == 0) {
+ p->force = 1;
+ }
+ else if (strncmp(argv[i], "netfn", 5) == 0 && (++i < argc)) {
+ if (str2int(argv[i], &(p->netfn)) != 0) {
+ lprintf(LOG_ERR, "Given netfn '%s' is invalid.", argv[i]);
+ conv_err = 1;
+ break;
+ }
+ }
+ else if (strncmp(argv[i], "command", 7) == 0 && (++i < argc)) {
+ if (str2int(argv[i], &(p->command)) != 0) {
+ lprintf(LOG_ERR, "Given command '%s' is invalid.", argv[i]);
+ conv_err = 1;
+ break;
+ }
+ }
+ else if (strncmp(argv[i], "subfn", 5) == 0 && (++i < argc)) {
+ if (str2int(argv[i], &(p->subfn)) != 0) {
+ lprintf(LOG_ERR, "Given subfn '%s' is invalid.", argv[i]);
+ conv_err = 1;
+ break;
+ }
+ }
+ }
+ if (conv_err != 0) {
+ return (-1);
+ }
+ if (p->subfn >= MAX_SUBFN) {
+ lprintf(LOG_ERR, "subfn is out of range (0-%d)", MAX_SUBFN-1);
+ return -1;
+ }
+ if (p->command >= MAX_COMMAND) {
+ lprintf(LOG_ERR, "command is out of range (0-%d)", MAX_COMMAND-1);
+ return -1;
+ }
+ if (p->netfn >= MAX_NETFN) {
+ lprintf(LOG_ERR, "netfn is out of range (0-%d)", MAX_NETFN-1);
+ return -1;
+ }
+ if (p->lun >= MAX_LUN) {
+ lprintf(LOG_ERR, "lun is out of range (0-%d)", MAX_LUN-1);
+ return -1;
+ }
+ if (p->netfn >= 0 && p->lun < 0) {
+ lprintf(LOG_ERR, "if netfn is set, so must be lun");
+ return -1;
+ }
+ if (p->command >= 0 && p->netfn < 0) {
+ lprintf(LOG_ERR, "if command is set, so must be netfn");
+ return -1;
+ }
+ if (p->subfn >= 0 && p->command < 0) {
+ lprintf(LOG_ERR, "if subfn is set, so must be command");
+ return -1;
+ }
+ return 0;
+}
+
+/* _get_netfn_suport
+ *
+ * @intf: ipmi interface
+ * @channel: ipmi channel
+ * @lun: a pointer to a 4 byte field
+ * @netfn: a pointer to a 128-bit bitfield (16 bytes)
+ *
+ * returns 0 on success and fills in the bitfield for
+ * the 32 netfn * 4 LUN pairs that support commands
+ * returns -1 on error
+ */
+static int
+_get_netfn_support(struct ipmi_intf * intf, int channel, unsigned char * lun, unsigned char * netfn)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char * d, rqdata;
+ unsigned int l;
+
+ if (!lun || !netfn) {
+ lprintf(LOG_ERR, "_get_netfn_suport: lun or netfn is NULL");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_NETFN_SUPPORT;
+ rqdata = (unsigned char) channel;
+ req.msg.data = &rqdata;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get NetFn Support command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get NetFn Support command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ for (l=0; l<4; l++) {
+ lun[l] = (*d)>>(2*l) & 0x3;
+ }
+ d++;
+
+ memcpy(netfn, d, 16);
+
+ return 0;
+}
+
+/* _get_command_suport
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @lnfn: a pointer to a struct lun_netfn_support
+ *
+ * returns 0 on success and fills in lnfn according to the request in p
+ * returns -1 on error
+ */
+static int
+_get_command_support(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct lun_netfn_support * lnfn)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char * d, rqdata[3];
+ unsigned int c;
+
+ if (!p || !lnfn) {
+ lprintf(LOG_ERR, "_get_netfn_suport: p or lnfn is NULL");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_COMMAND_SUPPORT;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=0) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ for (c=0; c<128; c++) {
+ if (!(d[c>>3] & (1<<(c%8))))
+ lnfn->command[c].support |= BIT_AVAILABLE;
+ }
+ memcpy(lnfn->command_mask, d, MAX_COMMAND_BYTES/2);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_COMMAND_SUPPORT;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = 0x40 | p->netfn;
+ rqdata[2] = p->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=1) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ for (c=0; c<128; c++) {
+ if (!(d[c>>3] & (1<<(c%8))))
+ lnfn->command[128+c].support |= BIT_AVAILABLE;
+ }
+ memcpy(lnfn->command_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2);
+ return 0;
+}
+
+/* _get_command_configurable
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @lnfn: a pointer to a struct lun_netfn_support
+ *
+ * returns 0 on success and fills in lnfn according to the request in p
+ * returns -1 on error
+ */
+static int
+_get_command_configurable(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct lun_netfn_support * lnfn)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char * d, rqdata[3];
+ unsigned int c;
+
+ if (!p || !lnfn) {
+ lprintf(LOG_ERR, "_get_command_configurable: p or lnfn is NULL");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=0) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ for (c=0; c<128; c++) {
+ if (d[c>>3] & (1<<(c%8)))
+ lnfn->command[c].support |= BIT_CONFIGURABLE;
+ }
+ memcpy(lnfn->config_mask, d, MAX_COMMAND_BYTES/2);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = 0x40 | p->netfn;
+ rqdata[2] = p->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=1) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ for (c=0; c<128; c++) {
+ if (d[c>>3] & (1<<(c%8)))
+ lnfn->command[128+c].support |= BIT_CONFIGURABLE;
+ }
+ memcpy(lnfn->config_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2);
+ return 0;
+}
+
+/* _get_command_enables
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @lnfn: a pointer to a struct lun_netfn_support
+ *
+ * returns 0 on success and fills in lnfn according to the request in p
+ * returns -1 on error
+ */
+static int
+_get_command_enables(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct lun_netfn_support * lnfn)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char * d, rqdata[3];
+ unsigned int c;
+
+ if (!p || !lnfn) {
+ lprintf(LOG_ERR, "_get_command_enables: p or lnfn is NULL");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_COMMAND_ENABLES;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ for (c=0; c<128; c++) {
+ if (d[c>>3] & (1<<(c%8)))
+ lnfn->command[c].support |= BIT_ENABLED;
+ }
+ memcpy(lnfn->enable_mask, d, MAX_COMMAND_BYTES/2);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_COMMAND_ENABLES;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = 0x40 | p->netfn;
+ rqdata[2] = p->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ for (c=0; c<128; c++) {
+ if (d[c>>3] & (1<<(c%8)))
+ lnfn->command[128+c].support |= BIT_ENABLED;
+ }
+ memcpy(lnfn->enable_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2);
+ return 0;
+}
+
+/* _set_command_enables
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @lnfn: a pointer to a struct lun_netfn_support that contains current info
+ * @enable: a pointer to a 32 byte bitfield that contains the desired enable state
+ * @gun: here is a gun to shoot yourself in the foot. If this is true
+ * you are allowed to disable this command
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+_set_command_enables(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct lun_netfn_support * lnfn,
+ unsigned char * enable, int gun)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char * d, rqdata[19];
+ unsigned int c;
+
+ if (!p || !lnfn) {
+ lprintf(LOG_ERR, "_set_command_enables: p or lnfn is NULL");
+ return -1;
+ }
+
+ lprintf(LOG_INFO, "support: ");
+ print_bitfield(lnfn->command_mask, MAX_COMMAND_BYTES, 1, LOG_INFO);
+ lprintf(LOG_INFO, "configurable: ");
+ print_bitfield(lnfn->config_mask, MAX_COMMAND_BYTES, 0, LOG_INFO);
+ lprintf(LOG_INFO, "enabled: ");
+ print_bitfield(lnfn->enable_mask, MAX_COMMAND_BYTES, 0, LOG_INFO);
+ lprintf(LOG_INFO, "enable mask before: ");
+ print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO);
+
+ // mask off the appropriate bits (if not configurable, set enable bit
+ // must be the same as the current enable bit)
+ for (c=0; c<(MAX_COMMAND_BYTES); c++) {
+ enable[c] = (lnfn->config_mask[c] & enable[c]) |
+ (~lnfn->config_mask[c] & lnfn->enable_mask[c]);
+ }
+
+ // take the gun out of their hand if they are not supposed to have it
+ if (!gun) {
+ enable[SET_COMMAND_ENABLE_BYTE] =
+ (lnfn->config_mask[SET_COMMAND_ENABLE_BYTE]
+ & SET_COMMAND_ENABLE_BIT) |
+ (~lnfn->config_mask[SET_COMMAND_ENABLE_BYTE]
+ & lnfn->enable_mask[SET_COMMAND_ENABLE_BYTE]);
+ }
+ lprintf(LOG_INFO, "enable mask after: ");
+ print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_SET_COMMAND_ENABLES;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ memcpy(&rqdata[3], enable, MAX_COMMAND_BYTES/2);
+ req.msg.data = rqdata;
+ req.msg.data_len = 19;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_SET_COMMAND_ENABLES;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = 0x40 | p->netfn;
+ rqdata[2] = p->lun;
+ memcpy(&rqdata[3], enable+MAX_COMMAND_BYTES/2, MAX_COMMAND_BYTES/2);
+ req.msg.data = rqdata;
+ req.msg.data_len = 19;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %s",
+ p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ d = rsp->data;
+ return 0;
+}
+
+/* _get_subfn_support
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @cmd: a pointer to a struct command_support
+ *
+ * returns 0 on success and fills in cmd according to the request in p
+ * returns -1 on error
+ */
+static int
+_get_subfn_support(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct command_support * cmd)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char rqdata[4];
+
+ if (!p || !cmd) {
+ lprintf(LOG_ERR, "_get_subfn_support: p or cmd is NULL");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_SUPPORT;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ rqdata[3] = p->command;
+ req.msg.data = rqdata;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Command Sub-function Support (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Command Sub-function Support (LUN=%d, NetFn=%d, command=%d) command failed: %s",
+ p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(cmd->subfn_support, rsp->data, sizeof(cmd->subfn_support));
+ return 0;
+}
+
+/* _get_subfn_configurable
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @cmd: a pointer to a struct command_support
+ *
+ * returns 0 on success and fills in cmd according to the request in p
+ * returns -1 on error
+ */
+static int
+_get_subfn_configurable(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct command_support * cmd)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char rqdata[4];
+
+ if (!p || !cmd) {
+ lprintf(LOG_ERR, "_get_subfn_configurable: p or cmd is NULL");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_CONFIGURABLE_COMMAND_SUBFUNCTIONS;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ rqdata[3] = p->command;
+ req.msg.data = rqdata;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Configurable Command Sub-function (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Configurable Command Sub-function (LUN=%d, NetFn=%d, command=%d) command failed: %s",
+ p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(cmd->subfn_config, rsp->data, sizeof(cmd->subfn_config));
+ return 0;
+}
+
+/* _get_subfn_enables
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @cmd: a pointer to a struct command_support
+ *
+ * returns 0 on success and fills in cmd according to the request in p
+ * returns -1 on error
+ */
+static int
+_get_subfn_enables(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct command_support * cmd)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char rqdata[4];
+
+ if (!p || !cmd) {
+ lprintf(LOG_ERR, "_get_subfn_enables: p or cmd is NULL");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_ENABLES;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ rqdata[3] = p->command;
+ req.msg.data = rqdata;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed: %s",
+ p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(cmd->subfn_enable, rsp->data, sizeof(cmd->subfn_enable));
+ return 0;
+}
+
+/* _set_subfn_enables
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @cmd: a pointer to a struct command_support
+ * @enable: a pointer to a 4 byte bitfield that contains the desired enable state
+ *
+ * returns 0 on success (and modifies enable to be the bits it actually set)
+ * returns -1 on error
+ */
+static int
+_set_subfn_enables(struct ipmi_intf * intf,
+ struct ipmi_function_params * p, struct command_support * cmd,
+ unsigned char * enable)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char rqdata[8];
+ unsigned int c;
+
+ if (!p || !cmd) {
+ lprintf(LOG_ERR, "_set_subfn_enables: p or cmd is NULL");
+ return -1;
+ }
+
+ lprintf(LOG_INFO, "support: ");
+ print_bitfield(cmd->subfn_support, MAX_SUBFN_BYTES, 1, LOG_INFO);
+ lprintf(LOG_INFO, "configurable: ");
+ print_bitfield(cmd->subfn_config, MAX_SUBFN_BYTES, 0, LOG_INFO);
+ lprintf(LOG_INFO, "enabled: ");
+ print_bitfield(cmd->subfn_enable, MAX_SUBFN_BYTES, 0, LOG_INFO);
+ lprintf(LOG_INFO, "enable mask before: ");
+ print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO);
+ // mask off the appropriate bits (if not configurable, set enable bit
+ // must be the same as the current enable bit)
+ for (c=0; c<sizeof(cmd->subfn_enable); c++) {
+ enable[c] = (cmd->subfn_config[c] & enable[c]) |
+ (~cmd->subfn_config[c] & cmd->subfn_enable[c]);
+ }
+ lprintf(LOG_INFO, "enable mask after: ");
+ print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_SET_COMMAND_SUBFUNCTION_ENABLES;
+ rqdata[0] = (unsigned char) p->channel;
+ rqdata[1] = p->netfn;
+ rqdata[2] = p->lun;
+ rqdata[3] = p->command;
+ memcpy(&rqdata[4], enable, MAX_SUBFN_BYTES);
+ req.msg.data = rqdata;
+ req.msg.data_len = 8;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed: %s",
+ p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* _gather_info
+ *
+ * @intf: ipmi interface
+ * @p: a pointer to a struct ipmi_function_params
+ * @bmc: a pointer to a struct bmc_fn_support
+ * @enable: a pointer to a 4 byte bitfield that contains the desired enable state
+ *
+ * returns 0 on success and fills in bmc according to request p
+ * returns -1 on error
+ */
+static int _gather_info(struct ipmi_intf * intf, struct ipmi_function_params * p, struct bmc_fn_support * bmc)
+{
+ int ret, l, n;
+ unsigned char lun[MAX_LUN], netfn[16];
+
+ ret = _get_netfn_support(intf, p->channel, lun, netfn);
+ if (!ret) {
+ for (l=0; l<MAX_LUN; l++) {
+ if (p->lun >= 0 && p->lun != l)
+ continue;
+ bmc->lun[l].support = lun[l];
+ if (lun[l]) {
+ for (n=0; n<MAX_NETFN_PAIR; n++) {
+ int offset = l*MAX_NETFN_PAIR+n;
+ bmc->lun[l].netfn[n].support =
+ !!(netfn[offset>>3] & (1<<(offset%8)));
+ }
+ }
+ }
+ }
+ if (p->netfn >= 0) {
+ if (!((p->lun < 0 || bmc->lun[p->lun].support) &&
+ (p->netfn < 0 || bmc->lun[p->lun].netfn[p->netfn>>1].support))) {
+ lprintf(LOG_ERR, "LUN or LUN/NetFn pair %d,%d not supported", p->lun, p->netfn);
+ return 0;
+ }
+ ret = _get_command_support(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1]));
+ ret |= _get_command_configurable(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1]));
+ ret |= _get_command_enables(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1]));
+ if (!ret && p->command >= 0) {
+ ret = _get_subfn_support(intf, p,
+ &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command]));
+ ret |= _get_subfn_configurable(intf, p,
+ &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command]));
+ ret |= _get_subfn_enables(intf, p,
+ &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command]));
+ }
+ }
+ else if (p->lun >= 0) {
+ l = p->lun;
+ if (bmc->lun[l].support) {
+ for (n=0; n<MAX_NETFN_PAIR; n++) {
+ p->netfn = n*2;
+ if (bmc->lun[l].netfn[n].support) {
+ ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n]));
+ ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n]));
+ ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n]));
+ }
+ if (ret)
+ bmc->lun[l].netfn[n].support = 0;
+ }
+ }
+ p->netfn = -1;
+ } else {
+ for (l=0; l<4; l++) {
+ p->lun = l;
+ if (bmc->lun[l].support) {
+ for (n=0; n<MAX_NETFN_PAIR; n++) {
+ p->netfn = n*2;
+ if (bmc->lun[l].netfn[n].support) {
+ ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n]));
+ ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n]));
+ ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n]));
+ }
+ if (ret)
+ bmc->lun[l].netfn[n].support = 0;
+ }
+ }
+ }
+ p->lun = -1;
+ p->netfn = -1;
+ }
+
+ return 0;
+}
+
+/* ipmi_firewall_info - print out info for firewall functions
+ *
+ * @intf: ipmi inteface
+ * @argc: argument count
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_firewall_info(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int ret = 0;
+ struct ipmi_function_params p = {0xe, -1, -1, -1, -1};
+ struct bmc_fn_support * bmc_fn_support;
+ unsigned int l, n, c;
+
+ if ((argc > 0 && strncmp(argv[0], "help", 4) == 0) || ipmi_firewall_parse_args(argc, argv, &p) < 0)
+ {
+ printf_firewall_info_usage();
+ return 0;
+ }
+
+ bmc_fn_support = malloc(sizeof(struct bmc_fn_support));
+ if (!bmc_fn_support) {
+ lprintf(LOG_ERR, "malloc struct bmc_fn_support failed");
+ return -1;
+ }
+
+ ret = _gather_info(intf, &p, bmc_fn_support);
+
+ if (p.command >= 0) {
+ struct command_support * cmd;
+ if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) &&
+ (p.netfn < 0 || bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support) &&
+ bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command].support))
+ {
+ lprintf(LOG_ERR, "Command 0x%02x not supported on LUN/NetFn pair %02x,%02x",
+ p.command, p.lun, p.netfn);
+ free(bmc_fn_support);
+ bmc_fn_support = NULL;
+ return 0;
+ }
+ cmd =
+ &bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command];
+ c = cmd->support;
+ printf("(A)vailable, (C)onfigurable, (E)nabled: | A | C | E |\n");
+ printf("-----------------------------------------------------\n");
+ printf("LUN %01d, NetFn 0x%02x, Command 0x%02x: | %c | %c | %c |\n",
+ p.lun, p.netfn, p.command,
+ (c & BIT_AVAILABLE) ? 'X' : ' ',
+ (c & BIT_CONFIGURABLE) ? 'X' : ' ',
+ (c & BIT_ENABLED) ? 'X': ' ');
+
+ for (n=0; n<MAX_SUBFN; n++) {
+ printf("sub-function 0x%02x: | %c | %c | %c |\n", n,
+ (!bit_test(cmd->subfn_support, n)) ? 'X' : ' ',
+ (bit_test(cmd->subfn_config, n)) ? 'X' : ' ',
+ (bit_test(cmd->subfn_enable, n)) ? 'X' : ' ');
+ }
+ }
+ else if (p.netfn >= 0) {
+ if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) &&
+ (bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support)))
+ {
+ lprintf(LOG_ERR, "LUN or LUN/NetFn pair %02x,%02x not supported",
+ p.lun, p.netfn);
+ free(bmc_fn_support);
+ bmc_fn_support = NULL;
+ return 0;
+ }
+ n = p.netfn >> 1;
+ l = p.lun;
+ printf("Commands on LUN 0x%02x, NetFn 0x%02x\n", p.lun, p.netfn);
+ printf("support: ");
+ print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask,
+ MAX_COMMAND_BYTES, 1, -1);
+ printf("configurable: ");
+ print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask,
+ MAX_COMMAND_BYTES, 0, -1);
+ printf("enabled: ");
+ print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask,
+ MAX_COMMAND_BYTES, 0, -1);
+ }
+ else {
+ for (l=0; l<4; l++) {
+ p.lun = l;
+ if (bmc_fn_support->lun[l].support) {
+ for (n=0; n<MAX_NETFN_PAIR; n++) {
+ p.netfn = n*2;
+ if (bmc_fn_support->lun[l].netfn[n].support) {
+ printf("%02x,%02x support: ", p.lun, p.netfn);
+ print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask,
+ MAX_COMMAND_BYTES, 1, -1);
+ printf("%02x,%02x configurable: ", p.lun, p.netfn);
+ print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask,
+ MAX_COMMAND_BYTES, 0, -1);
+ printf("%02x,%02x enabled: ", p.lun, p.netfn);
+ print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask,
+ MAX_COMMAND_BYTES, 0, -1);
+ }
+ }
+ }
+ }
+ p.lun = -1;
+ p.netfn = -1;
+ }
+
+ free(bmc_fn_support);
+ bmc_fn_support = NULL;
+ return ret;
+}
+
+/* ipmi_firewall_enable_disable - enable/disable BMC functions
+ *
+ * @intf: ipmi inteface
+ * @enable: whether to enable or disable
+ * @argc: argument count
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_firewall_enable_disable(struct ipmi_intf * intf, int enable, int argc, char ** argv)
+{
+ struct ipmi_function_params p = {0xe, -1, -1, -1, -1};
+ struct bmc_fn_support * bmc_fn_support;
+ unsigned int l, n, c, ret;
+ unsigned char enables[MAX_COMMAND_BYTES];
+
+ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
+ char * s1 = enable?"en":"dis";
+ char * s2 = enable?"":" [force]";
+ printf("%sable [channel H] lun L netfn N%s\n", s1, s2);
+ printf("\t%sable all commands on this LUN/NetFn pair\n", s1);
+ printf("%sable [channel H] lun L netfn N command C%s\n", s1, s2);
+ printf("\t%sable Command C and all its Sub-functions for this LUN/NetFn pair\n", s1);
+ printf("%sable [channel H] lun L netfn N command C subfn S\n", s1);
+ printf("\t%sable Sub-function S for Command C for this LUN/NetFn pair\n", s1);
+ if (!enable) {
+ printf("* force will allow you to disable the \"Command Set Enable\" command\n");
+ printf("\tthereby letting you shoot yourself in the foot\n");
+ printf("\tthis is only recommended for advanced users\n");
+ }
+ return 0;
+ }
+ if (ipmi_firewall_parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ bmc_fn_support = malloc(sizeof(struct bmc_fn_support));
+ if (!bmc_fn_support) {
+ lprintf(LOG_ERR, "malloc struct bmc_fn_support failed");
+ return -1;
+ }
+
+ ret = _gather_info(intf, &p, bmc_fn_support);
+ if (ret < 0) {
+ free(bmc_fn_support);
+ bmc_fn_support = NULL;
+ return ret;
+ }
+
+ l = p.lun;
+ n = p.netfn>>1;
+ c = p.command;
+ if (p.subfn >= 0) {
+ // firewall (en|dis)able [channel c] lun l netfn n command m subfn s
+ // (en|dis)able this sub-function for this commnad on this lun/netfn pair
+ memcpy(enables,
+ bmc_fn_support->lun[l].netfn[n].command[c].subfn_enable,
+ MAX_SUBFN_BYTES);
+ bit_set(enables, p.subfn, enable);
+ ret = _set_subfn_enables(intf, &p,
+ &bmc_fn_support->lun[l].netfn[n].command[c], enables);
+
+ } else if (p.command >= 0) {
+ // firewall (en|dis)able [channel c] lun l netfn n command m
+ // (en|dis)able all subfn and command for this commnad on this lun/netfn pair
+ memset(enables, enable?0xff:0, MAX_SUBFN_BYTES);
+ ret = _set_subfn_enables(intf, &p,
+ &bmc_fn_support->lun[l].netfn[n].command[c], enables);
+ memcpy(enables,
+ &bmc_fn_support->lun[l].netfn[n].enable_mask, sizeof(enables));
+ bit_set(enables, p.command, enable);
+ ret |= _set_command_enables(intf, &p,
+ &bmc_fn_support->lun[l].netfn[n], enables, p.force);
+ } else if (p.netfn >= 0) {
+ // firewall (en|dis)able [channel c] lun l netfn n
+ // (en|dis)able all commnads on this lun/netfn pair
+ memset(enables, enable?0xff:0, sizeof(enables));
+ ret = _set_command_enables(intf, &p,
+ &bmc_fn_support->lun[l].netfn[n], enables, p.force);
+ /*
+ } else if (p.lun >= 0) {
+ // firewall (en|dis)able [channel c] lun l
+ // (en|dis)able all commnads on all netfn pairs for this lun
+ */
+ }
+ free(bmc_fn_support);
+ bmc_fn_support = NULL;
+ return ret;
+}
+
+/* ipmi_firewall_reset - reset firmware firewall to enable everything
+ *
+ * @intf: ipmi inteface
+ * @argc: argument count
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_firewall_reset(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_function_params p = {0xe, -1, -1, -1, -1};
+ struct bmc_fn_support * bmc_fn_support;
+ unsigned int l, n, c, ret;
+ unsigned char enables[MAX_COMMAND_BYTES];
+
+ if (argc > 0 || (argc > 0 && strncmp(argv[0], "help", 4) == 0)) {
+ printf_firewall_usage();
+ return 0;
+ }
+ if (ipmi_firewall_parse_args(argc, argv, &p) < 0)
+ return -1;
+
+ bmc_fn_support = malloc(sizeof(struct bmc_fn_support));
+ if (!bmc_fn_support) {
+ lprintf(LOG_ERR, "malloc struct bmc_fn_support failed");
+ return -1;
+ }
+
+ ret = _gather_info(intf, &p, bmc_fn_support);
+ if (ret < 0) {
+ free(bmc_fn_support);
+ bmc_fn_support = NULL;
+ return ret;
+ }
+
+ for (l=0; l<MAX_LUN; l++) {
+ p.lun = l;
+ for (n=0; n<MAX_NETFN; n+=2) {
+ p.netfn = n;
+ for (c=0; c<MAX_COMMAND; c++) {
+ p.command = c;
+ printf("reset lun %d, netfn %d, command %d, subfn\n", l, n, c);
+ memset(enables, 0xff, MAX_SUBFN_BYTES);
+ ret = _set_subfn_enables(intf, &p,
+ &bmc_fn_support->lun[l].netfn[n].command[c], enables);
+ }
+ printf("reset lun %d, netfn %d, command\n", l, n);
+ memset(enables, 0xff, sizeof(enables));
+ ret = _set_command_enables(intf, &p,
+ &bmc_fn_support->lun[l].netfn[n], enables, 0);
+ }
+ }
+
+ free(bmc_fn_support);
+ bmc_fn_support = NULL;
+ return ret;
+}
+
+
+/* ipmi_firewall_main - top-level handler for firmware firewall functions
+ *
+ * @intf: ipmi interface
+ * @argc: number of arguments
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_firewall_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
+ printf_firewall_usage();
+ }
+ else if (strncmp(argv[0], "info", 4) == 0) {
+ rc = ipmi_firewall_info(intf, argc-1, &(argv[1]));
+ }
+ else if (strncmp(argv[0], "enable", 6) == 0) {
+ rc = ipmi_firewall_enable_disable(intf, 1, argc-1, &(argv[1]));
+ }
+ else if (strncmp(argv[0], "disable", 7) == 0) {
+ rc = ipmi_firewall_enable_disable(intf, 0, argc-1, &(argv[1]));
+ }
+ else if (strncmp(argv[0], "reset", 5) == 0) {
+ rc = ipmi_firewall_reset(intf, argc-1, &(argv[1]));
+ }
+ else {
+ printf_firewall_usage();
+ }
+
+ return rc;
+}
diff --git a/lib/ipmi_fru.c b/lib/ipmi_fru.c
new file mode 100644
index 0000000..1b2e0cd
--- /dev/null
+++ b/lib/ipmi_fru.c
@@ -0,0 +1,5209 @@
+/*
+* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistribution of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistribution in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* Neither the name of Sun Microsystems, Inc. or the names of
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* This software is provided "AS IS," without a warranty of any kind.
+* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+*/
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_fru.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_strings.h> /* IANA id strings */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define FRU_MULTIREC_CHUNK_SIZE (255 + sizeof(struct fru_multirec_header))
+
+extern int verbose;
+
+static void ipmi_fru_read_to_bin(struct ipmi_intf * intf, char * pFileName, uint8_t fruId);
+static void ipmi_fru_write_from_bin(struct ipmi_intf * intf, char * pFileName, uint8_t fruId);
+static int ipmi_fru_upg_ekeying(struct ipmi_intf * intf, char * pFileName, uint8_t fruId);
+static int ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf, uint8_t fruId,
+ struct fru_info *pFruInfo, uint32_t * pRetLocation,
+ uint32_t * pRetSize);
+static int ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea,
+ uint32_t size, uint32_t offset);
+static int ipmi_fru_get_multirec_size_from_file(char * pFileName, uint32_t * pSize, uint32_t * pOffset);
+int ipmi_fru_get_adjust_size_from_buffer(uint8_t *pBufArea, uint32_t *pSize);
+static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length);
+
+static int ipmi_fru_set_field_string(struct ipmi_intf * intf, unsigned
+ char fruId, uint8_t f_type, uint8_t f_index, char *f_string);
+static int
+ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId,
+ struct fru_info fru, struct fru_header header,
+ uint8_t f_type, uint8_t f_index, char *f_string);
+
+static void
+fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru,
+ uint8_t id, uint32_t offset);
+int
+read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
+ uint32_t offset, uint32_t length, uint8_t *frubuf);
+void free_fru_bloc(t_ipmi_fru_bloc *bloc);
+
+/* get_fru_area_str - Parse FRU area string from raw data
+*
+* @data: raw FRU data
+* @offset: offset into data for area
+*
+* returns pointer to FRU area string
+*/
+char * get_fru_area_str(uint8_t * data, uint32_t * offset)
+{
+ static const char bcd_plus[] = "0123456789 -.:,_";
+ char * str;
+ int len, off, size, i, j, k, typecode;
+ union {
+ uint32_t bits;
+ char chars[4];
+ } u;
+
+ size = 0;
+ off = *offset;
+
+ /* bits 6:7 contain format */
+ typecode = ((data[off] & 0xC0) >> 6);
+
+ // printf("Typecode:%i\n", typecode);
+ /* bits 0:5 contain length */
+ len = data[off++];
+ len &= 0x3f;
+
+ switch (typecode) {
+ case 0: /* 00b: binary/unspecified */
+ /* hex dump -> 2x length */
+ size = (len*2);
+ break;
+ case 2: /* 10b: 6-bit ASCII */
+ /* 4 chars per group of 1-3 bytes */
+ size = ((((len+2)*4)/3) & ~3);
+ break;
+ case 3: /* 11b: 8-bit ASCII */
+ case 1: /* 01b: BCD plus */
+ /* no length adjustment */
+ size = len;
+ break;
+ }
+
+ if (size < 1) {
+ *offset = off;
+ return NULL;
+ }
+ str = malloc(size+1);
+ if (str == NULL)
+ return NULL;
+ memset(str, 0, size+1);
+
+ if (len == 0) {
+ str[0] = '\0';
+ *offset = off;
+ return str;
+ }
+
+ switch (typecode) {
+ case 0: /* Binary */
+ strncpy(str, buf2str(&data[off], len), len*2);
+ break;
+
+ case 1: /* BCD plus */
+ for (k=0; k<len; k++)
+ str[k] = bcd_plus[(data[off+k] & 0x0f)];
+ str[k] = '\0';
+ break;
+
+ case 2: /* 6-bit ASCII */
+ for (i=j=0; i<len; i+=3) {
+ u.bits = 0;
+ k = ((len-i) < 3 ? (len-i) : 3);
+#if WORDS_BIGENDIAN
+ u.chars[3] = data[off+i];
+ u.chars[2] = (k > 1 ? data[off+i+1] : 0);
+ u.chars[1] = (k > 2 ? data[off+i+2] : 0);
+#define CHAR_IDX 3
+#else
+ memcpy((void *)&u.bits, &data[off+i], k);
+#define CHAR_IDX 0
+#endif
+ for (k=0; k<4; k++) {
+ str[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20);
+ u.bits >>= 6;
+ }
+ }
+ str[j] = '\0';
+ break;
+
+ case 3:
+ memcpy(str, &data[off], len);
+ str[len] = '\0';
+ break;
+ }
+
+ off += len;
+ *offset = off;
+
+ return str;
+}
+
+/* is_valid_filename - checks file/path supplied by user
+ *
+ * input_filename - user input string
+ *
+ * returns 0 if path is ok
+ * returns (-1) if path is NULL
+ * returns (-2) if path is too short
+ * returns (-3) if path is too long
+ */
+int
+is_valid_filename(const char *input_filename)
+{
+ if (input_filename == NULL) {
+ lprintf(LOG_ERR, "ERROR: NULL pointer passed.");
+ return (-1);
+ }
+
+ if (strlen(input_filename) < 1) {
+ lprintf(LOG_ERR, "File/path is invalid.");
+ return (-2);
+ }
+
+ if (strlen(input_filename) >= 512) {
+ lprintf(LOG_ERR, "File/path must be shorter than 512 bytes.");
+ return (-3);
+ }
+
+ return 0;
+} /* is_valid_filename() */
+
+/* build_fru_bloc - build fru bloc for write protection
+*
+* @intf: ipmi interface
+* @fru_info: information about FRU device
+* @id : Fru id
+* @soffset : Source offset (from buffer)
+* @doffset : Destination offset (in device)
+* @length : Size of data to write (in bytes)
+* @pFrubuf : Pointer on data to write
+*
+* returns 0 on success
+* returns -1 on error
+*/
+#define FRU_NUM_BLOC_COMMON_HEADER 6
+t_ipmi_fru_bloc *
+build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id)
+{
+ t_ipmi_fru_bloc * p_first, * p_bloc, * p_new;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct fru_header header;
+ struct fru_multirec_header rec_hdr;
+ uint8_t msg_data[4];
+ uint32_t off;
+ uint16_t i;
+
+ /*
+ * get COMMON Header format
+ */
+ msg_data[0] = id;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+ msg_data[3] = 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, " Device not present (No Response)");
+ return NULL;
+ }
+
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR," Device not present (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return NULL;
+ }
+
+ if (verbose > 1) {
+ printbuf(rsp->data, rsp->data_len, "FRU DATA");
+ }
+
+ memcpy(&header, rsp->data + 1, 8);
+
+ /* verify header checksum */
+ if (ipmi_csum((uint8_t *)&header, 8)) {
+ lprintf(LOG_ERR, " Bad header checksum");
+ return NULL;
+ }
+
+ if (header.version != 1) {
+ lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", header.version);
+ return NULL;
+ }
+
+ /******************************************
+ Malloc and fill up the bloc contents
+ *******************************************/
+
+ // Common header
+ p_first = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_first) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+
+ p_bloc = p_first;
+ p_bloc->next = NULL;
+ p_bloc->start= 0;
+ p_bloc->size = fru->size;
+ strcpy((char *)p_bloc->blocId, "Common Header Section");
+
+ for (i = 0; i < 4; i++) {
+ if (header.offsets[i]) {
+ p_new = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_new) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ free_fru_bloc(p_first);
+ return NULL;
+ }
+
+ p_new->next = NULL;
+ p_new->start = header.offsets[i] * 8;
+ p_new->size = fru->size - p_new->start;
+
+ strncpy((char *)p_new->blocId, section_id[i], sizeof(p_new->blocId));
+ /* Make sure string is null terminated */
+ p_new->blocId[sizeof(p_new->blocId)-1] = 0;
+
+ p_bloc->next = p_new;
+ p_bloc->size = p_new->start - p_bloc->start;
+ p_bloc = p_new;
+ }
+ }
+
+ // Multi
+ if (header.offset.multi) {
+ off = header.offset.multi * 8;
+
+ do {
+ /*
+ * check for odd offset for the case of fru devices
+ * accessed by words
+ */
+ if (fru->access && (off & 1)) {
+ lprintf(LOG_ERR, " Unaligned offset for a block: %d", off);
+ /* increment offset */
+ off++;
+ break;
+ }
+
+ if (read_fru_area(intf, fru, id, off, 5,
+ (uint8_t *) &rec_hdr) < 0) {
+ break;
+ }
+
+ p_new = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_new) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ free_fru_bloc(p_first);
+ return NULL;
+ }
+
+ p_new->next = NULL;
+ p_new->start = off;
+ p_new->size = fru->size - p_new->start;
+ sprintf((char *)p_new->blocId, "Multi-Rec Area: Type %i",
+ rec_hdr.type);
+
+ p_bloc->next = p_new;
+ p_bloc->size = p_new->start - p_bloc->start;
+ p_bloc = p_new;
+
+ off += rec_hdr.len + sizeof(struct fru_multirec_header);
+
+ /* verify record header */
+ if (ipmi_csum((uint8_t *)&rec_hdr,
+ sizeof(struct fru_multirec_header))) {
+ /* can't reliably judge for the rest space */
+ break;
+ }
+ } while (!(rec_hdr.format & 0x80) && (off < fru->size));
+
+ lprintf(LOG_DEBUG,"Multi-Record area ends at: %i (%xh)", off, off);
+
+ if (fru->size > off) {
+ // Bloc for remaining space
+ p_new = malloc(sizeof(struct ipmi_fru_bloc));
+ if (!p_new) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ free_fru_bloc(p_first);
+ return NULL;
+ }
+
+ p_new->next = NULL;
+ p_new->start = off;
+ p_new->size = fru->size - p_new->start;
+ strcpy((char *)p_new->blocId, "Unused space");
+
+ p_bloc->next = p_new;
+ p_bloc->size = p_new->start - p_bloc->start;
+ }
+ }
+
+ /* Dump blocs */
+ for(p_bloc = p_first, i = 0; p_bloc; p_bloc = p_bloc->next) {
+ lprintf(LOG_DEBUG ,"Bloc Numb : %i", i++);
+ lprintf(LOG_DEBUG ,"Bloc Id : %s", p_bloc->blocId);
+ lprintf(LOG_DEBUG ,"Bloc Start: %i", p_bloc->start);
+ lprintf(LOG_DEBUG ,"Bloc Size : %i", p_bloc->size);
+ lprintf(LOG_DEBUG ,"");
+ }
+
+ return p_first;
+}
+
+void
+free_fru_bloc(t_ipmi_fru_bloc *bloc)
+{
+ t_ipmi_fru_bloc * del;
+
+ while (bloc) {
+ del = bloc;
+ bloc = bloc->next;
+ free(del);
+ del = NULL;
+ }
+}
+
+/*
+ * write FRU[doffset:length] from the pFrubuf[soffset:length]
+ * rc=1 on success
+**/
+int
+write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
+ uint16_t soffset, uint16_t doffset,
+ uint16_t length, uint8_t *pFrubuf)
+{
+ uint16_t tmp, finish;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[255+3];
+ uint16_t writeLength;
+ uint16_t found_bloc = 0;
+
+ finish = doffset + length; /* destination offset */
+ if (finish > fru->size)
+ {
+ lprintf(LOG_ERROR, "Return error");
+ return -1;
+ }
+
+ if (fru->access && ((doffset & 1) || (length & 1))) {
+ lprintf(LOG_ERROR, "Odd offset or length specified");
+ return (-1);
+ }
+
+ t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id);
+ t_ipmi_fru_bloc * saved_fru_bloc = fru_bloc;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = SET_FRU_DATA;
+ req.msg.data = msg_data;
+
+ /* initialize request size only once */
+ if (fru->max_write_size == 0) {
+ uint16_t max_rq_size = ipmi_intf_get_max_request_data_size(intf);
+
+ /* validate lower bound of the maximum request data size */
+ if (max_rq_size <= 3) {
+ lprintf(LOG_ERROR, "Maximum request size is too small to send "
+ "a write request");
+ return -1;
+ }
+
+ /*
+ * Write FRU Info command returns the number of written bytes in
+ * a single byte field.
+ */
+ if (max_rq_size - 3 > 255) {
+ /* Limit the max write size with 255 bytes. */
+ fru->max_write_size = 255;
+ } else {
+ /* subtract 1 byte for FRU ID an 2 bytes for offset */
+ fru->max_write_size = max_rq_size - 3;
+ }
+
+ /* check word access */
+ if (fru->access) {
+ fru->max_write_size &= ~1;
+ }
+ }
+
+ do {
+ uint16_t end_bloc;
+ uint8_t protected_bloc = 0;
+
+ /* Write per bloc, try to find the end of a bloc*/
+ while (fru_bloc && fru_bloc->start + fru_bloc->size <= doffset) {
+ fru_bloc = fru_bloc->next;
+ found_bloc++;
+ }
+
+ if (fru_bloc && fru_bloc->start + fru_bloc->size < finish) {
+ end_bloc = fru_bloc->start + fru_bloc->size;
+ } else {
+ end_bloc = finish;
+ }
+
+ /* calculate write length */
+ tmp = end_bloc - doffset;
+
+ /* check that write length is more than maximum request size */
+ if (tmp > fru->max_write_size) {
+ writeLength = fru->max_write_size;
+ } else {
+ writeLength = tmp;
+ }
+
+ /* copy fru data */
+ memcpy(&msg_data[3], pFrubuf + soffset, writeLength);
+
+ /* check word access */
+ if (fru->access) {
+ writeLength &= ~1;
+ }
+
+ tmp = doffset;
+ if (fru->access) {
+ tmp >>= 1;
+ }
+
+ msg_data[0] = id;
+ msg_data[1] = (uint8_t)tmp;
+ msg_data[2] = (uint8_t)(tmp >> 8);
+ req.msg.data_len = writeLength + 3;
+
+ if(fru_bloc) {
+ lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)",
+ writeLength, found_bloc, fru_bloc->blocId);
+ } else {
+ lprintf(LOG_INFO,"Writing %d bytes", writeLength);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp) {
+ break;
+ }
+
+ if (rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) {
+ if (fru->max_write_size > 8) {
+ fru->max_write_size -= 8;
+ lprintf(LOG_INFO, "Retrying FRU write with request size %d",
+ fru->max_write_size);
+ continue;
+ }
+ } else if(rsp->ccode == 0x80) {
+ rsp->ccode = 0;
+ // Write protected section
+ protected_bloc = 1;
+ }
+
+ if (rsp->ccode > 0)
+ break;
+
+ if (protected_bloc == 0) {
+ // Write OK, bloc not protected, continue
+ lprintf(LOG_INFO,"Wrote %d bytes", writeLength);
+ doffset += writeLength;
+ soffset += writeLength;
+ } else {
+ if(fru_bloc) {
+ // Bloc protected, advise user and jump over protected bloc
+ lprintf(LOG_INFO,
+ "Bloc [%s] protected at offset: %i (size %i bytes)",
+ fru_bloc->blocId, fru_bloc->start, fru_bloc->size);
+ lprintf(LOG_INFO,"Jumping over this bloc");
+ } else {
+ lprintf(LOG_INFO,
+ "Remaining FRU is protected following offset: %i",
+ doffset);
+ }
+ soffset += end_bloc - doffset;
+ doffset = end_bloc;
+ }
+ } while (doffset < finish);
+
+ if (saved_fru_bloc) {
+ free_fru_bloc(saved_fru_bloc);
+ }
+
+ return doffset >= finish;
+}
+
+/* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length]
+*
+* @intf: ipmi interface
+* @fru: fru info
+* @id: fru id
+* @offset: offset into buffer
+* @length: how much to read
+* @frubuf: buffer read into
+*
+* returns -1 on error
+* returns 0 if successful
+*/
+int
+read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
+ uint32_t offset, uint32_t length, uint8_t *frubuf)
+{
+ uint32_t off = offset, tmp, finish;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[4];
+
+ if (offset > fru->size) {
+ lprintf(LOG_ERR, "Read FRU Area offset incorrect: %d > %d",
+ offset, fru->size);
+ return -1;
+ }
+
+ finish = offset + length;
+ if (finish > fru->size) {
+ finish = fru->size;
+ lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
+ "Adjusting to %d",
+ offset + length, finish - offset);
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ if (fru->max_read_size == 0) {
+ uint16_t max_rs_size = ipmi_intf_get_max_response_data_size(intf) - 1;
+
+ /* validate lower bound of the maximum response data size */
+ if (max_rs_size <= 1) {
+ lprintf(LOG_ERROR, "Maximum response size is too small to send "
+ "a read request");
+ return -1;
+ }
+
+ /*
+ * Read FRU Info command may read up to 255 bytes of data.
+ */
+ if (max_rs_size - 1 > 255) {
+ /* Limit the max read size with 255 bytes. */
+ fru->max_read_size = 255;
+ } else {
+ /* subtract 1 byte for bytes count */
+ fru->max_read_size = max_rs_size - 1;
+ }
+
+ /* check word access */
+ if (fru->access) {
+ fru->max_read_size &= ~1;
+ }
+ }
+
+ do {
+ tmp = fru->access ? off >> 1 : off;
+ msg_data[0] = id;
+ msg_data[1] = (uint8_t)(tmp & 0xff);
+ msg_data[2] = (uint8_t)(tmp >> 8);
+ tmp = finish - off;
+ if (tmp > fru->max_read_size)
+ msg_data[3] = (uint8_t)fru->max_read_size;
+ else
+ msg_data[3] = (uint8_t)tmp;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_NOTICE, "FRU Read failed");
+ break;
+ }
+ if (rsp->ccode > 0) {
+ /* if we get C8h or CAh completion code then we requested too
+ * many bytes at once so try again with smaller size */
+ if ((rsp->ccode == 0xc8 || rsp->ccode == 0xca)
+ && fru->max_read_size > 8) {
+ if (fru->max_read_size > 32) {
+ /* subtract read length more aggressively */
+ fru->max_read_size -= 8;
+ } else {
+ /* subtract length less aggressively */
+ fru->max_read_size--;
+ }
+
+ lprintf(LOG_INFO, "Retrying FRU read with request size %d",
+ fru->max_read_size);
+ continue;
+ }
+
+ lprintf(LOG_NOTICE, "FRU Read failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ break;
+ }
+
+ tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
+ memcpy(frubuf, rsp->data + 1, tmp);
+ off += tmp;
+ frubuf += tmp;
+ /* sometimes the size returned in the Info command
+ * is too large. return 0 so higher level function
+ * still attempts to parse what was returned */
+ if (tmp == 0 && off < finish) {
+ return 0;
+ }
+ } while (off < finish);
+
+ if (off < finish) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* read_fru_area - fill in frubuf[offset:length] from the FRU[offset:length]
+*
+* @intf: ipmi interface
+* @fru: fru info
+* @id: fru id
+* @offset: offset into buffer
+* @length: how much to read
+* @frubuf: buffer read into
+*
+* returns -1 on error
+* returns 0 if successful
+*/
+int
+read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
+ uint32_t offset, uint32_t length, uint8_t *frubuf)
+{
+ static uint32_t fru_data_rqst_size = 20;
+ uint32_t off = offset, tmp, finish;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[4];
+
+ if (offset > fru->size) {
+ lprintf(LOG_ERR, "Read FRU Area offset incorrect: %d > %d",
+ offset, fru->size);
+ return -1;
+ }
+
+ finish = offset + length;
+ if (finish > fru->size) {
+ finish = fru->size;
+ lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
+ "Adjusting to %d",
+ offset + length, finish - offset);
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+#ifdef LIMIT_ALL_REQUEST_SIZE
+ if (fru_data_rqst_size > 16)
+#else
+ if (fru->access && fru_data_rqst_size > 16)
+#endif
+ fru_data_rqst_size = 16;
+ do {
+ tmp = fru->access ? off >> 1 : off;
+ msg_data[0] = id;
+ msg_data[1] = (uint8_t)(tmp & 0xff);
+ msg_data[2] = (uint8_t)(tmp >> 8);
+ tmp = finish - off;
+ if (tmp > fru_data_rqst_size)
+ msg_data[3] = (uint8_t)fru_data_rqst_size;
+ else
+ msg_data[3] = (uint8_t)tmp;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_NOTICE, "FRU Read failed");
+ break;
+ }
+ if (rsp->ccode > 0) {
+ /* if we get C7 or C8 or CA return code then we requested too
+ * many bytes at once so try again with smaller size */
+ if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) &&
+ (--fru_data_rqst_size > 8)) {
+ lprintf(LOG_INFO, "Retrying FRU read with request size %d",
+ fru_data_rqst_size);
+ continue;
+ }
+ lprintf(LOG_NOTICE, "FRU Read failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ break;
+ }
+
+ tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
+ memcpy((frubuf + off)-offset, rsp->data + 1, tmp);
+ off += tmp;
+
+ /* sometimes the size returned in the Info command
+ * is too large. return 0 so higher level function
+ * still attempts to parse what was returned */
+ if (tmp == 0 && off < finish)
+ return 0;
+
+ } while (off < finish);
+
+ if (off < finish)
+ return -1;
+
+ return 0;
+}
+
+
+static void
+fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru,
+ uint8_t id, uint32_t offset)
+{
+ uint8_t * fru_data = NULL;
+ uint32_t fru_len, i;
+ struct fru_multirec_header * h;
+ uint32_t last_off, len;
+
+ i = last_off = offset;
+ fru_len = 0;
+
+ fru_data = malloc(fru->size + 1);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, " Out of memory!");
+ return;
+ }
+
+ memset(fru_data, 0, fru->size + 1);
+
+ do {
+ h = (struct fru_multirec_header *) (fru_data + i);
+
+ // read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time
+ if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
+ {
+ len = fru->size - last_off;
+ if (len > FRU_MULTIREC_CHUNK_SIZE)
+ len = FRU_MULTIREC_CHUNK_SIZE;
+
+ if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0)
+ break;
+
+ last_off += len;
+ }
+
+ //printf("Bloc Numb : %i\n", counter);
+ printf("Bloc Start: %i\n", i);
+ printf("Bloc Size : %i\n", h->len);
+ printf("\n");
+
+ i += h->len + sizeof (struct fru_multirec_header);
+ } while (!(h->format & 0x80));
+
+ i = offset;
+ do {
+ h = (struct fru_multirec_header *) (fru_data + i);
+
+ printf("Bloc Start: %i\n", i);
+ printf("Bloc Size : %i\n", h->len);
+ printf("\n");
+
+ i += h->len + sizeof (struct fru_multirec_header);
+ } while (!(h->format & 0x80));
+
+ lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i);
+
+ free(fru_data);
+ fru_data = NULL;
+}
+
+
+/* fru_area_print_chassis - Print FRU Chassis Area
+*
+* @intf: ipmi interface
+* @fru: fru info
+* @id: fru id
+* @offset: offset pointer
+*/
+static void
+fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru,
+ uint8_t id, uint32_t offset)
+{
+ char * fru_area;
+ uint8_t * fru_data;
+ uint32_t fru_len, i;
+ uint8_t tmp[2];
+
+ fru_len = 0;
+
+ /* read enough to check length field */
+ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
+ fru_len = 8 * tmp[1];
+ }
+
+ if (fru_len == 0) {
+ return;
+ }
+
+ fru_data = malloc(fru_len);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return;
+ }
+
+ memset(fru_data, 0, fru_len);
+
+ /* read in the full fru */
+ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
+ free(fru_data);
+ fru_data = NULL;
+ return;
+ }
+
+ /*
+ * skip first two bytes which specify
+ * fru area version and fru area length
+ */
+ i = 2;
+
+ printf(" Chassis Type : %s\n",
+ chassis_type_desc[fru_data[i] >
+ (sizeof(chassis_type_desc)/sizeof(chassis_type_desc[0])) - 1 ?
+ 2 : fru_data[i]]);
+
+ i++;
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Chassis Part Number : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Chassis Serial : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ /* read any extra fields */
+ while ((fru_data[i] != 0xc1) && (i < fru_len))
+ {
+ int j = i;
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Chassis Extra : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ if (i == j) {
+ break;
+ }
+ }
+
+ if (fru_area != NULL) {
+ free(fru_data);
+ fru_data = NULL;
+ }
+}
+
+/* fru_area_print_board - Print FRU Board Area
+*
+* @intf: ipmi interface
+* @fru: fru info
+* @id: fru id
+* @offset: offset pointer
+*/
+static void
+fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru,
+ uint8_t id, uint32_t offset)
+{
+ char * fru_area;
+ uint8_t * fru_data;
+ uint32_t fru_len;
+ uint32_t i;
+ time_t tval;
+ uint8_t tmp[2];
+
+ fru_len = 0;
+
+ /* read enough to check length field */
+ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
+ fru_len = 8 * tmp[1];
+ }
+
+ if (fru_len <= 0) {
+ return;
+ }
+
+ fru_data = malloc(fru_len);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return;
+ }
+
+ memset(fru_data, 0, fru_len);
+
+ /* read in the full fru */
+ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
+ free(fru_data);
+ fru_data = NULL;
+ return;
+ }
+
+ /*
+ * skip first three bytes which specify
+ * fru area version, fru area length
+ * and fru board language
+ */
+ i = 3;
+
+ tval=((fru_data[i+2] << 16) + (fru_data[i+1] << 8) + (fru_data[i]));
+ tval=tval * 60;
+ tval=tval + secs_from_1970_1996;
+ printf(" Board Mfg Date : %s", asctime(localtime(&tval)));
+ i += 3; /* skip mfg. date time */
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Board Mfg : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Board Product : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Board Serial : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Board Part Number : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0 && verbose > 0) {
+ printf(" Board FRU ID : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ /* read any extra fields */
+ while ((fru_data[i] != 0xc1) && (i < fru_len))
+ {
+ int j = i;
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Board Extra : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+ if (i == j)
+ break;
+ }
+
+ if (fru_area != NULL) {
+ free(fru_data);
+ fru_data = NULL;
+ }
+}
+
+/* fru_area_print_product - Print FRU Product Area
+*
+* @intf: ipmi interface
+* @fru: fru info
+* @id: fru id
+* @offset: offset pointer
+*/
+static void
+fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru,
+ uint8_t id, uint32_t offset)
+{
+ char * fru_area;
+ uint8_t * fru_data;
+ uint32_t fru_len, i;
+ uint8_t tmp[2];
+
+ fru_len = 0;
+
+ /* read enough to check length field */
+ if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
+ fru_len = 8 * tmp[1];
+ }
+
+ if (fru_len == 0) {
+ return;
+ }
+
+ fru_data = malloc(fru_len);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return;
+ }
+
+ memset(fru_data, 0, fru_len);
+
+
+ /* read in the full fru */
+ if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
+ free(fru_data);
+ fru_data = NULL;
+ return;
+ }
+
+ /*
+ * skip first three bytes which specify
+ * fru area version, fru area length
+ * and fru board language
+ */
+ i = 3;
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Product Manufacturer : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Product Name : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Product Part Number : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Product Version : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Product Serial : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Product Asset Tag : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0 && verbose > 0) {
+ printf(" Product FRU ID : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ /* read any extra fields */
+ while ((fru_data[i] != 0xc1) && (i < fru_len))
+ {
+ int j = i;
+ fru_area = get_fru_area_str(fru_data, &i);
+ if (fru_area != NULL) {
+ if (strlen(fru_area) > 0) {
+ printf(" Product Extra : %s\n", fru_area);
+ }
+ free(fru_area);
+ fru_area = NULL;
+ }
+ if (i == j)
+ break;
+ }
+
+ if (fru_area != NULL) {
+ free(fru_data);
+ fru_data = NULL;
+ }
+}
+
+/* fru_area_print_multirec - Print FRU Multi Record Area
+*
+* @intf: ipmi interface
+* @fru: fru info
+* @id: fru id
+* @offset: offset pointer
+*/
+static void
+fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru,
+ uint8_t id, uint32_t offset)
+{
+ uint8_t * fru_data;
+ struct fru_multirec_header * h;
+ struct fru_multirec_powersupply * ps;
+ struct fru_multirec_dcoutput * dc;
+ struct fru_multirec_dcload * dl;
+ uint16_t peak_capacity;
+ uint8_t peak_hold_up_time;
+ uint32_t last_off;
+
+ last_off = offset;
+
+ fru_data = malloc(FRU_MULTIREC_CHUNK_SIZE);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return;
+ }
+
+ memset(fru_data, 0, FRU_MULTIREC_CHUNK_SIZE);
+
+ h = (struct fru_multirec_header *) (fru_data);
+
+ do {
+ if (read_fru_area(intf, fru, id, last_off, sizeof(*h), fru_data) < 0) {
+ break;
+ }
+
+ if (h->len && read_fru_area(intf, fru, id,
+ last_off + sizeof(*h), h->len, fru_data + sizeof(*h)) < 0) {
+ break;
+ }
+
+ last_off += h->len + sizeof(*h);
+
+ switch (h->type) {
+ case FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION:
+ ps = (struct fru_multirec_powersupply *)
+ (fru_data + sizeof(struct fru_multirec_header));
+
+#if WORDS_BIGENDIAN
+ ps->capacity = BSWAP_16(ps->capacity);
+ ps->peak_va = BSWAP_16(ps->peak_va);
+ ps->lowend_input1 = BSWAP_16(ps->lowend_input1);
+ ps->highend_input1 = BSWAP_16(ps->highend_input1);
+ ps->lowend_input2 = BSWAP_16(ps->lowend_input2);
+ ps->highend_input2 = BSWAP_16(ps->highend_input2);
+ ps->combined_capacity = BSWAP_16(ps->combined_capacity);
+ ps->peak_cap_ht = BSWAP_16(ps->peak_cap_ht);
+#endif
+ peak_hold_up_time = (ps->peak_cap_ht & 0xf000) >> 12;
+ peak_capacity = ps->peak_cap_ht & 0x0fff;
+
+ printf (" Power Supply Record\n");
+ printf (" Capacity : %d W\n",
+ ps->capacity);
+ printf (" Peak VA : %d VA\n",
+ ps->peak_va);
+ printf (" Inrush Current : %d A\n",
+ ps->inrush_current);
+ printf (" Inrush Interval : %d ms\n",
+ ps->inrush_interval);
+ printf (" Input Voltage Range 1 : %d-%d V\n",
+ ps->lowend_input1 / 100, ps->highend_input1 / 100);
+ printf (" Input Voltage Range 2 : %d-%d V\n",
+ ps->lowend_input2 / 100, ps->highend_input2 / 100);
+ printf (" Input Frequency Range : %d-%d Hz\n",
+ ps->lowend_freq, ps->highend_freq);
+ printf (" A/C Dropout Tolerance : %d ms\n",
+ ps->dropout_tolerance);
+ printf (" Flags : %s%s%s%s%s\n",
+ ps->predictive_fail ? "'Predictive fail' " : "",
+ ps->pfc ? "'Power factor correction' " : "",
+ ps->autoswitch ? "'Autoswitch voltage' " : "",
+ ps->hotswap ? "'Hot swap' " : "",
+ ps->predictive_fail ? ps->rps_threshold ?
+ ps->tach ? "'Two pulses per rotation'" : "'One pulse per rotation'" :
+ ps->tach ? "'Failure on pin de-assertion'" : "'Failure on pin assertion'" : "");
+ printf (" Peak capacity : %d W\n",
+ peak_capacity);
+ printf (" Peak capacity holdup : %d s\n",
+ peak_hold_up_time);
+ if (ps->combined_capacity == 0)
+ printf (" Combined capacity : not specified\n");
+ else
+ printf (" Combined capacity : %d W (%s and %s)\n",
+ ps->combined_capacity,
+ combined_voltage_desc [ps->combined_voltage1],
+ combined_voltage_desc [ps->combined_voltage2]);
+ if (ps->predictive_fail)
+ printf (" Fan lower threshold : %d RPS\n",
+ ps->rps_threshold);
+ break;
+
+ case FRU_RECORD_TYPE_DC_OUTPUT:
+ dc = (struct fru_multirec_dcoutput *)
+ (fru_data + sizeof(struct fru_multirec_header));
+
+#if WORDS_BIGENDIAN
+ dc->nominal_voltage = BSWAP_16(dc->nominal_voltage);
+ dc->max_neg_dev = BSWAP_16(dc->max_neg_dev);
+ dc->max_pos_dev = BSWAP_16(dc->max_pos_dev);
+ dc->ripple_and_noise = BSWAP_16(dc->ripple_and_noise);
+ dc->min_current = BSWAP_16(dc->min_current);
+ dc->max_current = BSWAP_16(dc->max_current);
+#endif
+
+ printf (" DC Output Record\n");
+ printf (" Output Number : %d\n",
+ dc->output_number);
+ printf (" Standby power : %s\n",
+ dc->standby ? "Yes" : "No");
+ printf (" Nominal voltage : %.2f V\n",
+ (double) dc->nominal_voltage / 100);
+ printf (" Max negative deviation : %.2f V\n",
+ (double) dc->max_neg_dev / 100);
+ printf (" Max positive deviation : %.2f V\n",
+ (double) dc->max_pos_dev / 100);
+ printf (" Ripple and noise pk-pk : %d mV\n",
+ dc->ripple_and_noise);
+ printf (" Minimum current draw : %.3f A\n",
+ (double) dc->min_current / 1000);
+ printf (" Maximum current draw : %.3f A\n",
+ (double) dc->max_current / 1000);
+ break;
+
+ case FRU_RECORD_TYPE_DC_LOAD:
+ dl = (struct fru_multirec_dcload *)
+ (fru_data + sizeof(struct fru_multirec_header));
+
+#if WORDS_BIGENDIAN
+ dl->nominal_voltage = BSWAP_16(dl->nominal_voltage);
+ dl->min_voltage = BSWAP_16(dl->min_voltage);
+ dl->max_voltage = BSWAP_16(dl->max_voltage);
+ dl->ripple_and_noise = BSWAP_16(dl->ripple_and_noise);
+ dl->min_current = BSWAP_16(dl->min_current);
+ dl->max_current = BSWAP_16(dl->max_current);
+#endif
+
+ printf (" DC Load Record\n");
+ printf (" Output Number : %d\n",
+ dl->output_number);
+ printf (" Nominal voltage : %.2f V\n",
+ (double) dl->nominal_voltage / 100);
+ printf (" Min voltage allowed : %.2f V\n",
+ (double) dl->min_voltage / 100);
+ printf (" Max voltage allowed : %.2f V\n",
+ (double) dl->max_voltage / 100);
+ printf (" Ripple and noise pk-pk : %d mV\n",
+ dl->ripple_and_noise);
+ printf (" Minimum current load : %.3f A\n",
+ (double) dl->min_current / 1000);
+ printf (" Maximum current load : %.3f A\n",
+ (double) dl->max_current / 1000);
+ break;
+ case FRU_RECORD_TYPE_OEM_EXTENSION:
+ {
+ struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *)
+ &fru_data[sizeof(struct fru_multirec_header)];
+ uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
+
+ /* Now makes sure this is really PICMG record */
+
+ if( iana == IPMI_OEM_PICMG ){
+ printf(" PICMG Extension Record\n");
+ ipmi_fru_picmg_ext_print(fru_data,
+ sizeof(struct fru_multirec_header),
+ h->len);
+ }
+ /* FIXME: Add OEM record support here */
+ else{
+ printf(" OEM (%s) Record\n", val2str( iana, ipmi_oem_info));
+ }
+ }
+ break;
+ }
+ } while (!(h->format & 0x80));
+
+ lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off);
+
+ free(fru_data);
+}
+
+/* ipmi_fru_query_new_value - Query new values to replace original FRU content
+*
+* @data: FRU data
+* @offset: offset of the bytes to be modified in data
+* @len: size of the modified data
+*
+* returns : TRUE if data changed
+* returns : FALSE if data not changed
+*/
+int ipmi_fru_query_new_value(uint8_t *data,int offset, size_t len)
+{
+ int status=FALSE;
+ int ret;
+ char answer;
+
+ printf("Would you like to change this value <y/n> ? ");
+ ret = scanf("%c", &answer);
+ if (ret != 1) {
+ return FALSE;
+ }
+
+ if( answer == 'y' || answer == 'Y' ){
+ int i;
+ unsigned int *holder;
+
+ holder = malloc(len);
+ printf(
+ "Enter hex values for each of the %d entries (lsb first), "
+ "hit <enter> between entries\n", (int)len);
+
+ /* I can't assign scanf' %x into a single char */
+ for( i=0;i<len;i++ ){
+ ret = scanf("%x", holder+i);
+ if (ret != 1) {
+ free(holder);
+ return FALSE;
+ }
+ }
+ for( i=0;i<len;i++ ){
+ data[offset++] = (unsigned char) *(holder+i);
+ }
+ /* &data[offset++] */
+ free(holder);
+ holder = NULL;
+ status = TRUE;
+ }
+ else{
+ printf("Entered %c\n",answer);
+ }
+
+ return status;
+}
+
+/* ipmi_fru_oemkontron_edit -
+* Query new values to replace original FRU content
+* This is a generic enough to support any type of 'OEM' record
+* because the user supplies 'IANA number' , 'record Id' and 'record' version'
+*
+* However, the parser must have 'apriori' knowledge of the record format
+* The currently supported record is :
+*
+* IANA : 15000 (Kontron)
+* RECORD ID : 3
+* RECORD VERSION: 0 (or 1)
+*
+* I would have like to put that stuff in an OEM specific file, but apart for
+* the record format information, all commands are really standard 'FRU' command
+*
+*
+* @data: FRU data
+* @offset: start of the current multi record (start of header)
+* @len: len of the current record (excluding header)
+* @h: pointer to record header
+* @oh: pointer to OEM /PICMG header
+*
+* returns: TRUE if data changed
+* returns: FALSE if data not changed
+*/
+#define OEM_KONTRON_INFORMATION_RECORD 3
+
+#define EDIT_OEM_KONTRON_COMPLETE_ARG_COUNT 12
+#define GET_OEM_KONTRON_COMPLETE_ARG_COUNT 5
+/*
+./src/ipmitool fru edit 0
+oem 15000 3 0 name instance FIELD1 FIELD2 FIELD3 crc32
+*/
+
+#define OEM_KONTRON_SUBCOMMAND_ARG_POS 2
+#define OEM_KONTRON_IANA_ARG_POS 3
+#define OEM_KONTRON_RECORDID_ARG_POS 4
+#define OEM_KONTRON_FORMAT_ARG_POS 5
+#define OEM_KONTRON_NAME_ARG_POS 6
+#define OEM_KONTRON_INSTANCE_ARG_POS 7
+#define OEM_KONTRON_VERSION_ARG_POS 8
+#define OEM_KONTRON_BUILDDATE_ARG_POS 9
+#define OEM_KONTRON_UPDATEDATE_ARG_POS 10
+#define OEM_KONTRON_CRC32_ARG_POS 11
+
+#define OEM_KONTRON_FIELD_SIZE 8
+#define OEM_KONTRON_VERSION_FIELD_SIZE 10
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+typedef struct OemKontronInformationRecordV0{
+ uint8_t field1TypeLength;
+ uint8_t field1[OEM_KONTRON_FIELD_SIZE];
+ uint8_t field2TypeLength;
+ uint8_t field2[OEM_KONTRON_FIELD_SIZE];
+ uint8_t field3TypeLength;
+ uint8_t field3[OEM_KONTRON_FIELD_SIZE];
+ uint8_t crcTypeLength;
+ uint8_t crc32[OEM_KONTRON_FIELD_SIZE];
+}tOemKontronInformationRecordV0;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(0)
+#endif
+
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+typedef struct OemKontronInformationRecordV1{
+ uint8_t field1TypeLength;
+ uint8_t field1[OEM_KONTRON_VERSION_FIELD_SIZE];
+ uint8_t field2TypeLength;
+ uint8_t field2[OEM_KONTRON_FIELD_SIZE];
+ uint8_t field3TypeLength;
+ uint8_t field3[OEM_KONTRON_FIELD_SIZE];
+ uint8_t crcTypeLength;
+ uint8_t crc32[OEM_KONTRON_FIELD_SIZE];
+}tOemKontronInformationRecordV1;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(0)
+#endif
+
+/*
+./src/ipmitool fru get 0 oem iana 3
+
+*/
+
+static void ipmi_fru_oemkontron_get( int argc, char ** argv,uint8_t * fru_data,
+ int off,int len,
+ struct fru_multirec_header *h,
+ struct fru_multirec_oem_header *oh)
+{
+ static int badParams=FALSE;
+ int start = off;
+ int offset = start;
+ int length = len;
+ int i;
+ offset += sizeof(struct fru_multirec_oem_header);
+
+ if(!badParams){
+ /* the 'OEM' field is already checked in caller */
+ if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){
+ if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){
+ printf("usage: fru get <id> <oem>\n");
+ badParams = TRUE;
+ return;
+ }
+ }
+ if( argc<GET_OEM_KONTRON_COMPLETE_ARG_COUNT ){
+ printf("usage: oem <iana> <recordid>\n");
+ printf("usage: oem 15000 3\n");
+ badParams = TRUE;
+ return;
+ }
+ }
+
+ if(!badParams){
+
+ if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) {
+
+ uint8_t version;
+
+ printf("Kontron OEM Information Record\n");
+ version = oh->record_version;
+
+ int blockstart;
+ uint8_t blockCount;
+ uint8_t blockIndex=0;
+
+ unsigned int matchInstance = 0;
+ uint8_t instance = 0;
+
+ if (str2uchar(argv[OEM_KONTRON_INSTANCE_ARG_POS], &instance) != 0) {
+ lprintf(LOG_ERR,
+ "Instance argument '%s' is either invalid or out of range.",
+ argv[OEM_KONTRON_INSTANCE_ARG_POS]);
+ badParams = TRUE;
+ return;
+ }
+
+ blockCount = fru_data[offset++];
+
+ for(blockIndex=0;blockIndex<blockCount;blockIndex++){
+ void * pRecordData;
+ uint8_t nameLen;
+
+ blockstart = offset;
+ nameLen = ( fru_data[offset++] &= 0x3F );
+ printf(" Name: %*.*s\n",nameLen, nameLen, (const char *)(fru_data+offset));
+
+ offset+=nameLen;
+
+ pRecordData = &fru_data[offset];
+
+ printf(" Record Version: %d\n", version);
+ if( version == 0 )
+ {
+ printf(" Version: %*.*s\n",
+ OEM_KONTRON_FIELD_SIZE,
+ OEM_KONTRON_FIELD_SIZE,
+ ((tOemKontronInformationRecordV0 *) pRecordData)->field1);
+ printf(" Build Date: %*.*s\n",
+ OEM_KONTRON_FIELD_SIZE,
+ OEM_KONTRON_FIELD_SIZE,
+ ((tOemKontronInformationRecordV0 *) pRecordData)->field2);
+ printf(" Update Date: %*.*s\n",
+ OEM_KONTRON_FIELD_SIZE,
+ OEM_KONTRON_FIELD_SIZE,
+ ((tOemKontronInformationRecordV0 *) pRecordData)->field3);
+ printf(" Checksum: %*.*s\n\n",
+ OEM_KONTRON_FIELD_SIZE,
+ OEM_KONTRON_FIELD_SIZE,
+ ((tOemKontronInformationRecordV0 *) pRecordData)->crc32);
+ matchInstance++;
+ offset+= sizeof(tOemKontronInformationRecordV0);
+ offset++;
+ }
+ else if ( version == 1 )
+ {
+ printf(" Version: %*.*s\n",
+ OEM_KONTRON_VERSION_FIELD_SIZE,
+ OEM_KONTRON_VERSION_FIELD_SIZE,
+ ((tOemKontronInformationRecordV1 *) pRecordData)->field1);
+ printf(" Build Date: %*.*s\n",
+ OEM_KONTRON_FIELD_SIZE,
+ OEM_KONTRON_FIELD_SIZE,
+ ((tOemKontronInformationRecordV1 *) pRecordData)->field2);
+ printf(" Update Date: %*.*s\n",
+ OEM_KONTRON_FIELD_SIZE,
+ OEM_KONTRON_FIELD_SIZE,
+ ((tOemKontronInformationRecordV1 *) pRecordData)->field3);
+ printf(" Checksum: %*.*s\n\n",
+ OEM_KONTRON_FIELD_SIZE,
+ OEM_KONTRON_FIELD_SIZE,
+ ((tOemKontronInformationRecordV1 *) pRecordData)->crc32);
+ matchInstance++;
+ offset+= sizeof(tOemKontronInformationRecordV1);
+ offset++;
+ }
+ else
+ {
+ printf (" Unsupported version %d\n",version);
+ }
+ }
+ }
+ }
+}
+
+static int ipmi_fru_oemkontron_edit( int argc, char ** argv,uint8_t * fru_data,
+ int off,int len,
+ struct fru_multirec_header *h,
+ struct fru_multirec_oem_header *oh)
+{
+ static int badParams=FALSE;
+ int hasChanged = FALSE;
+ int start = off;
+ int offset = start;
+ int length = len;
+ int i;
+ uint8_t record_id = 0;
+ offset += sizeof(struct fru_multirec_oem_header);
+
+ if(!badParams){
+ /* the 'OEM' field is already checked in caller */
+ if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){
+ if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){
+ printf("usage: fru edit <id> <oem> <args...>\n");
+ badParams = TRUE;
+ return hasChanged;
+ }
+ }
+ if( argc<EDIT_OEM_KONTRON_COMPLETE_ARG_COUNT ){
+ printf("usage: oem <iana> <recordid> <format> <args...>\n");
+ printf("usage: oem 15000 3 0 <name> <instance> <field1>"\
+ " <field2> <field3> <crc32>\n");
+ badParams = TRUE;
+ return hasChanged;
+ }
+ if (str2uchar(argv[OEM_KONTRON_RECORDID_ARG_POS], &record_id) != 0) {
+ lprintf(LOG_ERR,
+ "Record ID argument '%s' is either invalid or out of range.",
+ argv[OEM_KONTRON_RECORDID_ARG_POS]);
+ badParams = TRUE;
+ return hasChanged;
+ }
+ if (record_id == OEM_KONTRON_INFORMATION_RECORD) {
+ for(i=OEM_KONTRON_VERSION_ARG_POS;i<=OEM_KONTRON_CRC32_ARG_POS;i++){
+ if( (strlen(argv[i]) != OEM_KONTRON_FIELD_SIZE) &&
+ (strlen(argv[i]) != OEM_KONTRON_VERSION_FIELD_SIZE)) {
+ printf("error: version fields must have %d characters\n",
+ OEM_KONTRON_FIELD_SIZE);
+ badParams = TRUE;
+ return hasChanged;
+ }
+ }
+ }
+ }
+
+ if(!badParams){
+
+ if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) {
+ uint8_t formatVersion = 0;
+ uint8_t version;
+
+ if (str2uchar(argv[OEM_KONTRON_FORMAT_ARG_POS], &formatVersion) != 0) {
+ lprintf(LOG_ERR,
+ "Format argument '%s' is either invalid or out of range.",
+ argv[OEM_KONTRON_FORMAT_ARG_POS]);
+ badParams = TRUE;
+ return hasChanged;
+ }
+
+ printf(" Kontron OEM Information Record\n");
+ version = oh->record_version;
+
+ if( version == formatVersion ){
+ int blockstart;
+ uint8_t blockCount;
+ uint8_t blockIndex=0;
+
+ uint8_t matchInstance = 0;
+ uint8_t instance = 0;
+
+ if (str2uchar(argv[OEM_KONTRON_INSTANCE_ARG_POS], &instance) != 0) {
+ lprintf(LOG_ERR,
+ "Instance argument '%s' is either invalid or out of range.",
+ argv[OEM_KONTRON_INSTANCE_ARG_POS]);
+ badParams = TRUE;
+ return hasChanged;
+ }
+
+ blockCount = fru_data[offset++];
+ printf(" blockCount: %d\n",blockCount);
+
+ for(blockIndex=0;blockIndex<blockCount;blockIndex++){
+ void * pRecordData;
+ uint8_t nameLen;
+
+ blockstart = offset;
+
+ nameLen = ( fru_data[offset++] & 0x3F );
+
+ if( version == 0 || version == 1 )
+ {
+ if(!strncmp((char *)argv[OEM_KONTRON_NAME_ARG_POS],
+ (const char *)(fru_data+offset),nameLen)&& (matchInstance == instance)){
+
+ printf ("Found : %s\n",argv[OEM_KONTRON_NAME_ARG_POS]);
+ offset+=nameLen;
+
+ pRecordData = &fru_data[offset];
+
+ if( version == 0 )
+ {
+ memcpy( ((tOemKontronInformationRecordV0 *)
+ pRecordData)->field1 ,
+ argv[OEM_KONTRON_VERSION_ARG_POS] ,
+ OEM_KONTRON_FIELD_SIZE);
+ memcpy( ((tOemKontronInformationRecordV0 *)
+ pRecordData)->field2 ,
+ argv[OEM_KONTRON_BUILDDATE_ARG_POS],
+ OEM_KONTRON_FIELD_SIZE);
+ memcpy( ((tOemKontronInformationRecordV0 *)
+ pRecordData)->field3 ,
+ argv[OEM_KONTRON_UPDATEDATE_ARG_POS],
+ OEM_KONTRON_FIELD_SIZE);
+ memcpy( ((tOemKontronInformationRecordV0 *)
+ pRecordData)->crc32 ,
+ argv[OEM_KONTRON_CRC32_ARG_POS] ,
+ OEM_KONTRON_FIELD_SIZE);
+ }
+ else
+ {
+ memcpy( ((tOemKontronInformationRecordV1 *)
+ pRecordData)->field1 ,
+ argv[OEM_KONTRON_VERSION_ARG_POS] ,
+ OEM_KONTRON_VERSION_FIELD_SIZE);
+ memcpy( ((tOemKontronInformationRecordV1 *)
+ pRecordData)->field2 ,
+ argv[OEM_KONTRON_BUILDDATE_ARG_POS],
+ OEM_KONTRON_FIELD_SIZE);
+ memcpy( ((tOemKontronInformationRecordV1 *)
+ pRecordData)->field3 ,
+ argv[OEM_KONTRON_UPDATEDATE_ARG_POS],
+ OEM_KONTRON_FIELD_SIZE);
+ memcpy( ((tOemKontronInformationRecordV1 *)
+ pRecordData)->crc32 ,
+ argv[OEM_KONTRON_CRC32_ARG_POS] ,
+ OEM_KONTRON_FIELD_SIZE);
+ }
+
+ matchInstance++;
+ hasChanged = TRUE;
+ }
+ else if(!strncmp((char *)argv[OEM_KONTRON_NAME_ARG_POS],
+ (const char *)(fru_data+offset), nameLen)){
+ printf ("Skipped : %s [instance %d]\n",argv[OEM_KONTRON_NAME_ARG_POS],
+ (unsigned int)matchInstance);
+ matchInstance++;
+ offset+=nameLen;
+ }
+ else {
+ offset+=nameLen;
+ }
+
+ if( version == 0 )
+ {
+ offset+= sizeof(tOemKontronInformationRecordV0);
+ }
+ else
+ {
+ offset+= sizeof(tOemKontronInformationRecordV1);
+ }
+ offset++;
+ }
+ else
+ {
+ printf (" Unsupported version %d\n",version);
+ }
+ }
+ }
+ else{
+ printf(" Version: %d\n",version);
+ }
+ }
+ if( hasChanged ){
+
+ uint8_t record_checksum =0;
+ uint8_t header_checksum =0;
+ int index;
+
+ lprintf(LOG_DEBUG,"Initial record checksum : %x",h->record_checksum);
+ lprintf(LOG_DEBUG,"Initial header checksum : %x",h->header_checksum);
+ for(index=0;index<length;index++){
+ record_checksum+= fru_data[start+index];
+ }
+ /* Update Record checksum */
+ h->record_checksum = ~record_checksum + 1;
+
+
+ for(index=0;index<(sizeof(struct fru_multirec_header) -1);index++){
+ uint8_t data= *( (uint8_t *)h+ index);
+ header_checksum+=data;
+ }
+ /* Update header checksum */
+ h->header_checksum = ~header_checksum + 1;
+
+ lprintf(LOG_DEBUG,"Final record checksum : %x",h->record_checksum);
+ lprintf(LOG_DEBUG,"Final header checksum : %x",h->header_checksum);
+
+ /* write back data */
+ }
+ }
+
+ return hasChanged;
+}
+
+/* ipmi_fru_picmg_ext_edit - Query new values to replace original FRU content
+*
+* @data: FRU data
+* @offset: start of the current multi record (start of header)
+* @len: len of the current record (excluding header)
+* @h: pointer to record header
+* @oh: pointer to OEM /PICMG header
+*
+* returns: TRUE if data changed
+* returns: FALSE if data not changed
+*/
+static int ipmi_fru_picmg_ext_edit(uint8_t * fru_data,
+ int off,int len,
+ struct fru_multirec_header *h,
+ struct fru_multirec_oem_header *oh)
+{
+ int hasChanged = FALSE;
+ int start = off;
+ int offset = start;
+ int length = len;
+ offset += sizeof(struct fru_multirec_oem_header);
+
+ switch (oh->record_id)
+ {
+ case FRU_AMC_ACTIVATION:
+ printf(" FRU_AMC_ACTIVATION\n");
+ {
+ int index=offset;
+ uint16_t max_current;
+
+ max_current = fru_data[offset];
+ max_current |= fru_data[++offset]<<8;
+
+ printf(" Maximum Internal Current(@12V): %.2f A (0x%02x)\n",
+ (float)max_current / 10.0f, max_current);
+
+ if( ipmi_fru_query_new_value(fru_data,index,2) ){
+ max_current = fru_data[index];
+ max_current |= fru_data[++index]<<8;
+ printf(" New Maximum Internal Current(@12V): %.2f A (0x%02x)\n",
+ (float)max_current / 10.0f, max_current);
+ hasChanged = TRUE;
+
+ }
+
+ printf(" Module Activation Readiness: %i sec.\n", fru_data[++offset]);
+ printf(" Descriptor Count: %i\n", fru_data[++offset]);
+ printf("\n");
+
+ for (++offset;
+ offset < (off + length);
+ offset += sizeof(struct fru_picmgext_activation_record)) {
+ struct fru_picmgext_activation_record * a =
+ (struct fru_picmgext_activation_record *) &fru_data[offset];
+
+ printf(" IPMB-Address: 0x%x\n", a->ibmb_addr);
+ printf(" Max. Module Current: %.2f A\n", (float)a->max_module_curr / 10.0f);
+
+ printf("\n");
+ }
+ }
+ break;
+
+ case FRU_AMC_CURRENT:
+ printf(" FRU_AMC_CURRENT\n");
+ {
+ int index=offset;
+ unsigned char current;
+
+ current = fru_data[index];
+
+ printf(" Current draw(@12V): %.2f A (0x%02x)\n",
+ (float)current / 10.0f, current);
+
+ if( ipmi_fru_query_new_value(fru_data, index, 1) ){
+ current = fru_data[index];
+
+ printf(" New Current draw(@12V): %.2f A (0x%02x)\n",
+ (float)current / 10.0f, current);
+ hasChanged = TRUE;
+ }
+ }
+ break;
+ }
+
+ if( hasChanged ){
+
+ uint8_t record_checksum =0;
+ uint8_t header_checksum =0;
+ int index;
+
+ lprintf(LOG_DEBUG,"Initial record checksum : %x",h->record_checksum);
+ lprintf(LOG_DEBUG,"Initial header checksum : %x",h->header_checksum);
+ for(index=0;index<length;index++){
+ record_checksum+= fru_data[start+index];
+ }
+ /* Update Record checksum */
+ h->record_checksum = ~record_checksum + 1;
+
+
+ for(index=0;index<(sizeof(struct fru_multirec_header) -1);index++){
+ uint8_t data= *( (uint8_t *)h+ index);
+ header_checksum+=data;
+ }
+ /* Update header checksum */
+ h->header_checksum = ~header_checksum + 1;
+
+ lprintf(LOG_DEBUG,"Final record checksum : %x",h->record_checksum);
+ lprintf(LOG_DEBUG,"Final header checksum : %x",h->header_checksum);
+
+ /* write back data */
+ }
+
+ return hasChanged;
+}
+
+/* ipmi_fru_picmg_ext_print - prints OEM fru record (PICMG)
+*
+* @fru_data: FRU data
+* @offset: offset of the bytes to be modified in data
+* @length: size of the record
+*
+* returns : n/a
+*/
+static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
+{
+ struct fru_multirec_oem_header *h;
+ int guid_count;
+ int offset = off;
+ int start_offset = off;
+ int i;
+
+ h = (struct fru_multirec_oem_header *) &fru_data[offset];
+ offset += sizeof(struct fru_multirec_oem_header);
+
+ switch (h->record_id)
+ {
+ case FRU_PICMG_BACKPLANE_P2P:
+ {
+ uint8_t index;
+ unsigned int data;
+ struct fru_picmgext_slot_desc *slot_d;
+
+ slot_d =
+ (struct fru_picmgext_slot_desc*)&fru_data[offset];
+ offset += sizeof(struct fru_picmgext_slot_desc);
+ printf(" FRU_PICMG_BACKPLANE_P2P\n");
+
+ while (offset <= (start_offset+length)) {
+ printf("\n");
+ printf(" Channel Type: ");
+ switch (slot_d->chan_type)
+ {
+ case 0x00:
+ case 0x07:
+ printf("PICMG 2.9\n");
+ break;
+ case 0x08:
+ printf("Single Port Fabric IF\n");
+ break;
+ case 0x09:
+ printf("Double Port Fabric IF\n");
+ break;
+ case 0x0a:
+ printf("Full Channel Fabric IF\n");
+ break;
+ case 0x0b:
+ printf("Base IF\n");
+ break;
+ case 0x0c:
+ printf("Update Channel IF\n");
+ break;
+ case 0x0d:
+ printf("ShMC Cross Connect\n");
+ break;
+ default:
+ printf("Unknown IF (0x%x)\n",
+ slot_d->chan_type);
+ break;
+ }
+ printf(" Slot Addr. : %02x\n",
+ slot_d->slot_addr );
+ printf(" Channel Count: %i\n",
+ slot_d->chn_count);
+
+ for (index = 0;
+ index < (slot_d->chn_count);
+ index++) {
+ struct fru_picmgext_chn_desc *d;
+ data = (fru_data[offset+0]) |
+ (fru_data[offset+1] << 8) |
+ (fru_data[offset+2] << 16);
+ d = (struct fru_picmgext_chn_desc *)&data;
+ if (verbose) {
+ printf( " "
+ "Chn: %02x -> "
+ "Chn: %02x in "
+ "Slot: %02x\n",
+ d->local_chn,
+ d->remote_chn,
+ d->remote_slot);
+ }
+ offset += FRU_PICMGEXT_CHN_DESC_RECORD_SIZE;
+ }
+ slot_d = (struct fru_picmgext_slot_desc*)&fru_data[offset];
+ offset += sizeof(struct fru_picmgext_slot_desc);
+ }
+ }
+ break;
+
+ case FRU_PICMG_ADDRESS_TABLE:
+ {
+ unsigned int hwaddr;
+ unsigned int sitetype;
+ unsigned int sitenum;
+ unsigned int entries;
+ unsigned int i;
+ char *picmg_site_type_strings[] = {
+ "AdvancedTCA Board",
+ "Power Entry",
+ "Shelf FRU Information",
+ "Dedicated ShMC",
+ "Fan Tray",
+ "Fan Filter Tray",
+ "Alarm",
+ "AdvancedMC Module",
+ "PMC",
+ "Rear Transition Module"};
+
+
+ printf(" FRU_PICMG_ADDRESS_TABLE\n");
+ printf(" Type/Len: 0x%02x\n", fru_data[offset++]);
+ printf(" Shelf Addr: ");
+ for (i=0;i<20;i++) {
+ printf("0x%02x ", fru_data[offset++]);
+ }
+ printf("\n");
+
+ entries = fru_data[offset++];
+ printf(" Addr Table Entries: 0x%02x\n", entries);
+
+ for (i=0; i<entries; i++) {
+ hwaddr = fru_data[offset];
+ sitenum = fru_data[offset + 1];
+ sitetype = fru_data[offset + 2];
+ printf(
+ " HWAddr: 0x%02x (0x%02x) SiteNum: %d SiteType: 0x%02x %s\n",
+ hwaddr, hwaddr * 2,
+ sitenum, sitetype,
+ (sitetype < 0xa) ?
+ picmg_site_type_strings[sitetype] :
+ "Reserved");
+ offset += 3;
+ }
+ }
+ break;
+
+ case FRU_PICMG_SHELF_POWER_DIST:
+ {
+ unsigned int entries;
+ unsigned int feeds;
+ unsigned int feedcnt;
+ unsigned int hwaddr;
+ unsigned int i;
+ unsigned int id;
+ unsigned int j;
+ unsigned int maxext;
+ unsigned int maxint;
+ unsigned int minexp;
+
+ printf(" FRU_PICMG_SHELF_POWER_DIST\n");
+
+ feeds = fru_data[offset++];
+ printf(" Number of Power Feeds: 0x%02x\n",
+ feeds);
+
+ for (i=0; i<feeds; i++) {
+ printf(" Feed %d:\n", i);
+ maxext = fru_data[offset] |
+ (fru_data[offset+1] << 8);
+ offset += 2;
+ maxint = fru_data[offset] |
+ (fru_data[offset+1] << 8);
+ offset += 2;
+ minexp = fru_data[offset];
+ offset += 1;
+ entries = fru_data[offset];
+ offset += 1;
+
+ printf(
+ " Max External Current: %d.%d Amps (0x%04x)\n",
+ maxext / 10, maxext % 10, maxext);
+ if (maxint < 0xffff) {
+ printf(
+ " Max Internal Current: %d.%d Amps (0x%04x)\n",
+ maxint / 10, maxint % 10,
+ maxint);
+ } else {
+ printf(
+ " Max Internal Current: Not Specified\n");
+ }
+
+ if (minexp >= 0x48 && minexp <= 0x90) {
+ printf(
+ " Min Expected Voltage: -%02d.%dV\n",
+ minexp / 2, (minexp % 2) * 5);
+ } else {
+ printf(
+ " Min Expected Voltage: -%dV (actual invalid value 0x%x)\n",
+ 36, minexp);
+ }
+ for (j=0; j < entries; j++) {
+ hwaddr = fru_data[offset++];
+ id = fru_data[offset++];
+ printf(
+ " FRU HW Addr: 0x%02x (0x%02x)",
+ hwaddr, hwaddr * 2);
+ printf(
+ " FRU ID: 0x%02x\n",
+ id);
+ }
+ }
+ }
+ break;
+
+ case FRU_PICMG_SHELF_ACTIVATION:
+ {
+ unsigned int i;
+ unsigned int count = 0;
+
+ printf(" FRU_PICMG_SHELF_ACTIVATION\n");
+ printf(
+ " Allowance for FRU Act Readiness: 0x%02x\n",
+ fru_data[offset++]);
+
+ count = fru_data[offset++];
+ printf(
+ " FRU activation and Power Desc Cnt: 0x%02x\n",
+ count);
+
+ for (i=0; i<count; i++) {
+ printf(" HW Addr: 0x%02x ",
+ fru_data[offset++]);
+ printf(" FRU ID: 0x%02x ",
+ fru_data[offset++]);
+ printf(" Max FRU Power: 0x%04x ",
+ fru_data[offset+0] |
+ (fru_data[offset+1]<<8));
+ offset += 2;
+ printf(" Config: 0x%02x \n",
+ fru_data[offset++]);
+ }
+ }
+ break;
+
+ case FRU_PICMG_SHMC_IP_CONN:
+ printf(" FRU_PICMG_SHMC_IP_CONN\n");
+ break;
+
+ case FRU_PICMG_BOARD_P2P:
+ printf(" FRU_PICMG_BOARD_P2P\n");
+
+ guid_count = fru_data[offset++];
+ printf(" GUID count: %2d\n", guid_count);
+ for (i = 0 ; i < guid_count; i++ ) {
+ int j;
+ printf(" GUID [%2d]: 0x", i);
+
+ for (j=0; j < sizeof(struct fru_picmgext_guid);
+ j++) {
+ printf("%02x", fru_data[offset+j]);
+ }
+
+ printf("\n");
+ offset += sizeof(struct fru_picmgext_guid);
+ }
+ printf("\n");
+
+ for (; offset < off + length;
+ offset += sizeof(struct fru_picmgext_link_desc)) {
+
+ /* to solve little endian /big endian problem */
+ struct fru_picmgext_link_desc *d;
+ unsigned int data = (fru_data[offset+0]) |
+ (fru_data[offset+1] << 8) |
+ (fru_data[offset+2] << 16) |
+ (fru_data[offset+3] << 24);
+ d = (struct fru_picmgext_link_desc *) &data;
+
+ printf(" Link Grouping ID: 0x%02x\n",
+ d->grouping);
+ printf(" Link Type Extension: 0x%02x - ",
+ d->ext);
+ if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE) {
+ switch (d->ext)
+ {
+ case 0:
+ printf("10/100/1000BASE-T Link (four-pair)\n");
+ break;
+ case 1:
+ printf("ShMC Cross-connect (two-pair)\n");
+ break;
+ default:
+ printf("Unknwon\n");
+ break;
+ }
+ } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET) {
+ switch (d->ext)
+ {
+ case 0:
+ printf("Fixed 1000Base-BX\n");
+ break;
+ case 1:
+ printf("Fixed 10GBASE-BX4 [XAUI]\n");
+ break;
+ case 2:
+ printf("FC-PI\n");
+ break;
+ default:
+ printf("Unknwon\n");
+ break;
+ }
+ } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND) {
+ printf("Unknwon\n");
+ } else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR) {
+ printf("Unknwon\n");
+ } else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE) {
+ printf("Unknwon\n");
+ } else {
+ printf("Unknwon\n");
+ }
+
+ printf(" Link Type: 0x%02x - ",
+ d->type);
+ if (d->type == 0 || d->type == 0xff) {
+ printf("Reserved\n");
+ }
+ else if (d->type >= 0x06 && d->type <= 0xef) {
+ printf("Reserved\n");
+ }
+ else if (d->type >= 0xf0 && d->type <= 0xfe) {
+ printf("OEM GUID Definition\n");
+ }
+ else {
+ switch (d->type)
+ {
+ case FRU_PICMGEXT_LINK_TYPE_BASE:
+ printf("PICMG 3.0 Base Interface 10/100/1000\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET:
+ printf("PICMG 3.1 Ethernet Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND:
+ printf("PICMG 3.2 Infiniband Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR:
+ printf("PICMG 3.3 Star Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_PCIE:
+ printf("PICMG 3.4 PCI Express Fabric Interface\n");
+ break;
+ default:
+ printf("Invalid\n");
+ break;
+ }
+ }
+ printf(" Link Designator: \n");
+ printf(" Port Flag: 0x%02x\n",
+ d->desig_port);
+ printf(" Interface: 0x%02x - ",
+ d->desig_if);
+ switch (d->desig_if)
+ {
+ case FRU_PICMGEXT_DESIGN_IF_BASE:
+ printf("Base Interface\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_FABRIC:
+ printf("Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL:
+ printf("Update Channel\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_RESERVED:
+ printf("Reserved\n");
+ break;
+ default:
+ printf("Invalid");
+ break;
+ }
+ printf(" Channel Number: 0x%02x\n",
+ d->desig_channel);
+ printf("\n");
+ }
+
+ break;
+
+ case FRU_AMC_CURRENT:
+ {
+ unsigned char current;
+ printf(" FRU_AMC_CURRENT\n");
+
+ current = fru_data[offset];
+ printf(" Current draw(@12V): %.2f A [ %.2f Watt ]\n",
+ (float)current / 10.0f,
+ (float)current / 10.0f * 12.0f);
+ printf("\n");
+ }
+ break;
+
+ case FRU_AMC_ACTIVATION:
+ printf(" FRU_AMC_ACTIVATION\n");
+ {
+ uint16_t max_current;
+
+ max_current = fru_data[offset];
+ max_current |= fru_data[++offset]<<8;
+ printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n",
+ (float)max_current / 10.0f,
+ (float)max_current / 10.0f * 12.0f);
+
+ printf(" Module Activation Readiness: %i sec.\n", fru_data[++offset]);
+ printf(" Descriptor Count: %i\n", fru_data[++offset]);
+ printf("\n");
+
+ for(++offset; offset < off + length;
+ offset += sizeof(struct fru_picmgext_activation_record))
+ {
+ struct fru_picmgext_activation_record *a;
+ a = (struct fru_picmgext_activation_record *)&fru_data[offset];
+ printf(" IPMB-Address: 0x%x\n",
+ a->ibmb_addr);
+ printf(" Max. Module Current: %.2f A\n",
+ (float)a->max_module_curr / 10.0f);
+ printf("\n");
+ }
+ }
+ break;
+
+ case FRU_AMC_CARRIER_P2P:
+ {
+ uint16_t index;
+ printf(" FRU_CARRIER_P2P\n");
+ for(; offset < off + length; ) {
+ struct fru_picmgext_carrier_p2p_record * h =
+ (struct fru_picmgext_carrier_p2p_record *)&fru_data[offset];
+ printf("\n");
+ printf(" Resource ID: %i",
+ (h->resource_id & 0x07));
+ printf(" Type: ");
+ if ((h->resource_id>>7) == 1) {
+ printf("AMC\n");
+ } else {
+ printf("Local\n");
+ }
+ printf(" Descriptor Count: %i\n",
+ h->p2p_count);
+ offset += sizeof(struct fru_picmgext_carrier_p2p_record);
+ for (index = 0; index < h->p2p_count; index++) {
+ /* to solve little endian /big endian problem */
+ unsigned char data[3];
+ struct fru_picmgext_carrier_p2p_descriptor * desc;
+# ifndef WORDS_BIGENDIAN
+ data[0] = fru_data[offset+0];
+ data[1] = fru_data[offset+1];
+ data[2] = fru_data[offset+2];
+# else
+ data[0] = fru_data[offset+2];
+ data[1] = fru_data[offset+1];
+ data[2] = fru_data[offset+0];
+# endif
+ desc = (struct fru_picmgext_carrier_p2p_descriptor*)&data;
+ printf(" Port: %02d\t-> Remote Port: %02d\t",
+ desc->local_port, desc->remote_port);
+ if ((desc->remote_resource_id >> 7) == 1) {
+ printf("[ AMC ID: %02d ]\n",
+ desc->remote_resource_id & 0x0F);
+ } else {
+ printf("[ local ID: %02d ]\n",
+ desc->remote_resource_id & 0x0F);
+ }
+ offset += sizeof(struct fru_picmgext_carrier_p2p_descriptor);
+ }
+ }
+ }
+ break;
+
+ case FRU_AMC_P2P:
+ {
+ unsigned int index;
+ unsigned char channel_count;
+ struct fru_picmgext_amc_p2p_record * h;
+ printf(" FRU_AMC_P2P\n");
+ guid_count = fru_data[offset];
+ printf(" GUID count: %2d\n", guid_count);
+ for (i = 0 ; i < guid_count; i++) {
+ int j;
+ printf(" GUID %2d: ", i);
+ for (j=0; j < sizeof(struct fru_picmgext_guid);
+ j++) {
+ printf("%02x", fru_data[offset+j]);
+ offset += sizeof(struct fru_picmgext_guid);
+ printf("\n");
+ }
+ h = (struct fru_picmgext_amc_p2p_record *)&fru_data[++offset];
+ printf(" %s",
+ (h->record_type ?
+ "AMC Module:" : "On-Carrier Device"));
+ printf(" Resource ID: %i\n", h->resource_id);
+ offset += sizeof(struct fru_picmgext_amc_p2p_record);
+ channel_count = fru_data[offset++];
+ printf(" Descriptor Count: %i\n",
+ channel_count);
+ for (index = 0; index < channel_count; index++) {
+ unsigned int data;
+ struct fru_picmgext_amc_channel_desc_record *d;
+ /* pack the data in little endian format.
+ * Stupid intel...
+ */
+ data = fru_data[offset] |
+ (fru_data[offset + 1] << 8) |
+ (fru_data[offset + 2] << 16);
+ d = (struct fru_picmgext_amc_channel_desc_record *)&data;
+ printf(" Lane 0 Port: %i\n",
+ d->lane0port);
+ printf(" Lane 1 Port: %i\n",
+ d->lane1port);
+ printf(" Lane 2 Port: %i\n",
+ d->lane2port);
+ printf(" Lane 3 Port: %i\n\n",
+ d->lane3port);
+ offset += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE;
+ }
+ for (; offset < off + length;) {
+ unsigned int data[2];
+ struct fru_picmgext_amc_link_desc_record *l;
+ l = (struct fru_picmgext_amc_link_desc_record *)&data[0];
+ data[0] = fru_data[offset] |
+ (fru_data[offset + 1] << 8) |
+ (fru_data[offset + 2] << 16) |
+ (fru_data[offset + 3] << 24);
+ data[1] = fru_data[offset + 4];
+ printf( " Link Designator: Channel ID: %i\n"
+ " Port Flag 0: %s%s%s%s\n",
+ l->channel_id,
+ (l->port_flag_0)?"o":"-",
+ (l->port_flag_1)?"o":"-",
+ (l->port_flag_2)?"o":"-",
+ (l->port_flag_3)?"o":"-" );
+ switch (l->type) {
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE:
+ /* AMC.1 */
+ printf( " Link Type: %02x - "
+ "AMC.1 PCI Express\n", l->type);
+ switch (l->type_ext) {
+ case AMC_LINK_TYPE_EXT_PCIE_G1_NSSC:
+ printf( " Link Type Ext: %i - "
+ " Gen 1 capable - non SSC\n",
+ l->type_ext);
+ break;
+ case AMC_LINK_TYPE_EXT_PCIE_G1_SSC:
+ printf( " Link Type Ext: %i - "
+ " Gen 1 capable - SSC\n",
+ l->type_ext);
+ break;
+ case AMC_LINK_TYPE_EXT_PCIE_G2_NSSC:
+ printf( " Link Type Ext: %i - "
+ " Gen 2 capable - non SSC\n",
+ l->type_ext);
+ break;
+ case AMC_LINK_TYPE_EXT_PCIE_G2_SSC:
+ printf( " Link Type Ext: %i - "
+ " Gen 2 capable - SSC\n",
+ l->type_ext);
+ break;
+ default:
+ printf( " Link Type Ext: %i - "
+ " Invalid\n",
+ l->type_ext);
+ break;
+ }
+ break;
+
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1:
+ case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2:
+ /* AMC.1 */
+ printf( " Link Type: %02x - "
+ "AMC.1 PCI Express Advanced Switching\n",
+ l->type);
+ printf(" Link Type Ext: %i\n",
+ l->type_ext);
+ break;
+
+ case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET:
+ /* AMC.2 */
+ printf( " Link Type: %02x - "
+ "AMC.2 Ethernet\n",
+ l->type);
+ switch (l->type_ext) {
+ case AMC_LINK_TYPE_EXT_ETH_1000_BX:
+ printf( " Link Type Ext: %i - "
+ " 1000Base-Bx (SerDES Gigabit) Ethernet Link\n",
+ l->type_ext);
+ break;
+
+ case AMC_LINK_TYPE_EXT_ETH_10G_XAUI:
+ printf( " Link Type Ext: %i - "
+ " 10Gbit XAUI Ethernet Link\n",
+ l->type_ext);
+ break;
+
+ default:
+ printf( " Link Type Ext: %i - "
+ " Invalid\n",
+ l->type_ext);
+ break;
+ }
+ break;
+
+ case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE:
+ /* AMC.3 */
+ printf( " Link Type: %02x - "
+ "AMC.3 Storage\n",
+ l->type);
+ switch (l->type_ext) {
+ case AMC_LINK_TYPE_EXT_STORAGE_FC:
+ printf( " Link Type Ext: %i - "
+ " Fibre Channel\n",
+ l->type_ext);
+ break;
+
+ case AMC_LINK_TYPE_EXT_STORAGE_SATA:
+ printf( " Link Type Ext: %i - "
+ " Serial ATA\n",
+ l->type_ext);
+ break;
+
+ case AMC_LINK_TYPE_EXT_STORAGE_SAS:
+ printf( " Link Type Ext: %i - "
+ " Serial Attached SCSI\n",
+ l->type_ext);
+ break;
+
+ default:
+ printf( " Link Type Ext: %i - "
+ " Invalid\n",
+ l->type_ext);
+ break;
+ }
+ break;
+
+ case FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO:
+ /* AMC.4 */
+ printf( " Link Type: %02x - "
+ "AMC.4 Serial Rapid IO\n",
+ l->type);
+ printf(" Link Type Ext: %i\n",
+ l->type_ext);
+ break;
+
+ default:
+ printf( " Link Type: %02x - "
+ "reserved or OEM GUID",
+ l->type);
+ printf(" Link Type Ext: %i\n",
+ l->type_ext);
+ break;
+ }
+
+ printf(" Link group Id: %i\n",
+ l->group_id);
+ printf(" Link Asym Match: %i\n\n",
+ l->asym_match);
+ offset += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE;
+ }
+ }
+ }
+ break;
+
+ case FRU_AMC_CARRIER_INFO:
+ {
+ unsigned char extVersion;
+ unsigned char siteCount;
+
+ printf(" FRU_CARRIER_INFO\n");
+
+ extVersion = fru_data[offset++];
+ siteCount = fru_data[offset++];
+
+ printf(" AMC.0 extension version: R%d.%d\n",
+ (extVersion >> 0)& 0x0F,
+ (extVersion >> 4)& 0x0F );
+ printf(" Carrier Sie Number Cnt: %d\n", siteCount);
+
+ for (i = 0 ; i < siteCount; i++ ){
+ printf(" Site ID: %i \n", fru_data[offset++]);
+ }
+ printf("\n");
+ }
+ break;
+ case FRU_PICMG_CLK_CARRIER_P2P:
+ {
+ unsigned char desc_count;
+ int i,j;
+
+ printf(" FRU_PICMG_CLK_CARRIER_P2P\n");
+
+ desc_count = fru_data[offset++];
+
+ for(i=0; i<desc_count; i++){
+ unsigned char resource_id;
+ unsigned char channel_count;
+
+ resource_id = fru_data[offset++];
+ channel_count = fru_data[offset++];
+
+ printf("\n");
+ printf(" Clock Resource ID: 0x%02x Type: ", resource_id);
+ if((resource_id & 0xC0)>>6 == 0) {printf("On-Carrier-Device\n");}
+ else if((resource_id & 0xC0)>>6 == 1) {printf("AMC slot\n");}
+ else if((resource_id & 0xC0)>>6 == 2) {printf("Backplane\n");}
+ else{ printf("reserved\n");}
+ printf(" Channel Count: 0x%02x\n", channel_count);
+
+ for(j=0; j<channel_count; j++){
+ unsigned char loc_channel, rem_channel, rem_resource;
+
+ loc_channel = fru_data[offset++];
+ rem_channel = fru_data[offset++];
+ rem_resource = fru_data[offset++];
+
+ printf(" CLK-ID: 0x%02x ->", loc_channel);
+ printf(" remote CLKID: 0x%02x ", rem_channel);
+ if((rem_resource & 0xC0)>>6 == 0) {printf("[ Carrier-Dev");}
+ else if((rem_resource & 0xC0)>>6 == 1) {printf("[ AMC slot ");}
+ else if((rem_resource & 0xC0)>>6 == 2) {printf("[ Backplane ");}
+ else{ printf("reserved ");}
+ printf(" 0x%02x ]\n", rem_resource&0xF);
+ }
+ }
+ printf("\n");
+ }
+ break;
+ case FRU_PICMG_CLK_CONFIG:
+ {
+ unsigned char resource_id, descr_count;
+ int i,j;
+
+ printf(" FRU_PICMG_CLK_CONFIG\n");
+
+ resource_id = fru_data[offset++];
+ descr_count = fru_data[offset++];
+
+ printf("\n");
+ printf(" Clock Resource ID: 0x%02x\n", resource_id);
+ printf(" Descr. Count: 0x%02x\n", descr_count);
+
+ for(i=0; i<descr_count; i++){
+ unsigned char channel_id, control;
+ unsigned char indirect_cnt, direct_cnt;
+
+ channel_id = fru_data[offset++];
+ control = fru_data[offset++];
+ printf(" CLK-ID: 0x%02x - ", channel_id);
+ printf("CTRL 0x%02x [ %12s ]\n",
+ control,
+ ((control&0x1)==0)?"Carrier IPMC":"Application");
+
+ indirect_cnt = fru_data[offset++];
+ direct_cnt = fru_data[offset++];
+ printf(" Cnt: Indirect 0x%02x / Direct 0x%02x\n",
+ indirect_cnt,
+ direct_cnt);
+
+ /* indirect desc */
+ for(j=0; j<indirect_cnt; j++){
+ unsigned char feature;
+ unsigned char dep_chn_id;
+
+ feature = fru_data[offset++];
+ dep_chn_id = fru_data[offset++];
+
+ printf(" Feature: 0x%02x [%8s] - ", feature, (feature&0x1)==1?"Source":"Receiver");
+ printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id);
+ }
+
+ /* direct desc */
+ for(j=0; j<direct_cnt; j++){
+ unsigned char feature, family, accuracy;
+ unsigned int freq, min_freq, max_freq;
+
+ feature = fru_data[offset++];
+ family = fru_data[offset++];
+ accuracy = fru_data[offset++];
+ freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
+ | (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
+ offset += 4;
+ min_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
+ | (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
+ offset += 4;
+ max_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
+ | (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
+ offset += 4;
+
+ printf(" - Feature: 0x%02x - PLL: %x / Asym: %s\n",
+ feature,
+ (feature > 1) & 1,
+ (feature&1)?"Source":"Receiver");
+ printf(" Family: 0x%02x - AccLVL: 0x%02x\n", family, accuracy);
+ printf(" FRQ: %-9ld - min: %-9ld - max: %-9ld\n",
+ freq, min_freq, max_freq);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ }
+ break;
+
+ case FRU_UTCA_FRU_INFO_TABLE:
+ case FRU_UTCA_CARRIER_MNG_IP:
+ case FRU_UTCA_CARRIER_INFO:
+ case FRU_UTCA_CARRIER_LOCATION:
+ case FRU_UTCA_SHMC_IP_LINK:
+ case FRU_UTCA_POWER_POLICY:
+ case FRU_UTCA_ACTIVATION:
+ case FRU_UTCA_PM_CAPABILTY:
+ case FRU_UTCA_FAN_GEOGRAPHY:
+ case FRU_UTCA_CLOCK_MAPPING:
+ case FRU_UTCA_MSG_BRIDGE_POLICY:
+ case FRU_UTCA_OEM_MODULE_DESC:
+ printf(" Not implemented yet. uTCA specific record found!!\n");
+ printf(" - Record ID: 0x%02x\n", h->record_id);
+ break;
+
+ default:
+ printf(" Unknown OEM Extension Record ID: %x\n", h->record_id);
+ break;
+
+ }
+}
+
+
+/* __ipmi_fru_print - Do actual work to print a FRU by its ID
+*
+* @intf: ipmi interface
+* @id: fru id
+*
+* returns -1 on error
+* returns 0 if successful
+* returns 1 if device not present
+*/
+static int
+__ipmi_fru_print(struct ipmi_intf * intf, uint8_t id)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ struct fru_header header;
+ uint8_t msg_data[4];
+
+ memset(&fru, 0, sizeof(struct fru_info));
+ memset(&header, 0, sizeof(struct fru_header));
+
+ /*
+ * get info about this FRU
+ */
+ memset(msg_data, 0, 4);
+ msg_data[0] = id;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
+ fru.size, fru.access ? "words" : "bytes");
+
+ if (fru.size < 1) {
+ lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
+ return -1;
+ }
+
+ /*
+ * retrieve the FRU header
+ */
+ msg_data[0] = id;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+ msg_data[3] = 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return 1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return 1;
+ }
+
+ if (verbose > 1)
+ printbuf(rsp->data, rsp->data_len, "FRU DATA");
+
+ memcpy(&header, rsp->data + 1, 8);
+
+ if (header.version != 1) {
+ lprintf(LOG_ERR, " Unknown FRU header version 0x%02x",
+ header.version);
+ return -1;
+ }
+
+ /* offsets need converted to bytes
+ * but that conversion is not done to the structure
+ * because we may end up with offset > 255
+ * which would overflow our 1-byte offset field */
+
+ lprintf(LOG_DEBUG, "fru.header.version: 0x%x",
+ header.version);
+ lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x",
+ header.offset.internal * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.chassis: 0x%x",
+ header.offset.chassis * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.board: 0x%x",
+ header.offset.board * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.product: 0x%x",
+ header.offset.product * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.multi: 0x%x",
+ header.offset.multi * 8);
+
+ /*
+ * rather than reading the entire part
+ * only read the areas we'll format
+ */
+ /* chassis area */
+ if ((header.offset.chassis*8) >= sizeof(struct fru_header))
+ fru_area_print_chassis(intf, &fru, id, header.offset.chassis*8);
+
+ /* board area */
+ if ((header.offset.board*8) >= sizeof(struct fru_header))
+ fru_area_print_board(intf, &fru, id, header.offset.board*8);
+
+ /* product area */
+ if ((header.offset.product*8) >= sizeof(struct fru_header))
+ fru_area_print_product(intf, &fru, id, header.offset.product*8);
+
+ /* multirecord area */
+ if( verbose==0 ) /* scipp parsing multirecord */
+ return 0;
+
+ if ((header.offset.multi*8) >= sizeof(struct fru_header))
+ fru_area_print_multirec(intf, &fru, id, header.offset.multi*8);
+
+ return 0;
+}
+
+/* ipmi_fru_print - Print a FRU from its SDR locator record
+*
+* @intf: ipmi interface
+* @fru: SDR FRU Locator Record
+*
+* returns -1 on error
+*/
+int
+ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru)
+{
+ char desc[17];
+ uint8_t bridged_request = 0;
+ uint32_t save_addr;
+ uint32_t save_channel;
+ int rc = 0;
+
+ if (fru == NULL)
+ return __ipmi_fru_print(intf, 0);
+
+ /* Logical FRU Device
+ * dev_type == 0x10
+ * modifier
+ * 0x00 = IPMI FRU Inventory
+ * 0x01 = DIMM Memory ID
+ * 0x02 = IPMI FRU Inventory
+ * 0x03 = System Processor FRU
+ * 0xff = unspecified
+ *
+ * EEPROM 24C01 or equivalent
+ * dev_type >= 0x08 && dev_type <= 0x0f
+ * modifier
+ * 0x00 = unspecified
+ * 0x01 = DIMM Memory ID
+ * 0x02 = IPMI FRU Inventory
+ * 0x03 = System Processor Cartridge
+ */
+ if (fru->dev_type != 0x10 &&
+ (fru->dev_type_modifier != 0x02 ||
+ fru->dev_type < 0x08 || fru->dev_type > 0x0f))
+ return -1;
+
+ if (fru->dev_slave_addr == IPMI_BMC_SLAVE_ADDR &&
+ fru->device_id == 0)
+ return 0;
+
+ memset(desc, 0, sizeof(desc));
+ memcpy(desc, fru->id_string, fru->id_code & 0x01f);
+ desc[fru->id_code & 0x01f] = 0;
+ printf("FRU Device Description : %s (ID %d)\n", desc, fru->device_id);
+
+ switch (fru->dev_type_modifier) {
+ case 0x00:
+ case 0x02:
+ if (BRIDGE_TO_SENSOR(intf, fru->dev_slave_addr,
+ fru->channel_num)) {
+ bridged_request = 1;
+ save_addr = intf->target_addr;
+ intf->target_addr = fru->dev_slave_addr;
+ save_channel = intf->target_channel;
+ intf->target_channel = fru->channel_num;
+ }
+ /* print FRU */
+ rc = __ipmi_fru_print(intf, fru->device_id);
+ if (bridged_request) {
+ intf->target_addr = save_addr;
+ intf->target_channel = save_channel;
+ }
+ break;
+ case 0x01:
+ rc = ipmi_spd_print_fru(intf, fru->device_id);
+ break;
+ default:
+ if (verbose)
+ printf(" Unsupported device 0x%02x "
+ "type 0x%02x with modifier 0x%02x\n",
+ fru->device_id, fru->dev_type,
+ fru->dev_type_modifier);
+ else
+ printf(" Unsupported device\n");
+ }
+ printf("\n");
+
+ return rc;
+}
+
+/* ipmi_fru_print_all - Print builtin FRU + SDR FRU Locator records
+*
+* @intf: ipmi interface
+*
+* returns -1 on error
+*/
+static int
+ipmi_fru_print_all(struct ipmi_intf * intf)
+{
+ struct ipmi_sdr_iterator * itr;
+ struct sdr_get_rs * header;
+ struct sdr_record_fru_locator * fru;
+ int rc;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct ipm_devid_rsp *devid;
+ struct sdr_record_mc_locator * mc;
+ uint32_t save_addr;
+
+ printf("FRU Device Description : Builtin FRU Device (ID 0)\n");
+ /* TODO: Figure out if FRU device 0 may show up in SDR records. */
+
+ /* Do a Get Device ID command to determine device support */
+ memset (&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Device ID command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Device ID command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ devid = (struct ipm_devid_rsp *) rsp->data;
+
+ /* Check the FRU inventory device bit to decide whether various */
+ /* FRU commands can be issued to FRU device #0 LUN 0 */
+
+ if (devid->adtl_device_support & 0x08) { /* FRU Inventory Device bit? */
+ rc = ipmi_fru_print(intf, NULL);
+ printf("\n");
+ }
+
+ if ((itr = ipmi_sdr_start(intf, 0)) == NULL)
+ return -1;
+
+ /* Walk the SDRs looking for FRU Devices and Management Controller Devices. */
+ /* For FRU devices, print the FRU from the SDR locator record. */
+ /* For MC devices, issue FRU commands to the satellite controller to print */
+ /* FRU data. */
+ while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL)
+ {
+ if (header->type == SDR_RECORD_TYPE_MC_DEVICE_LOCATOR ) {
+ /* Check the capabilities of the Management Controller Device */
+ mc = (struct sdr_record_mc_locator *)
+ ipmi_sdr_get_record(intf, header, itr);
+ /* Does this MC device support FRU inventory device? */
+ if (mc && (mc->dev_support & 0x08)) { /* FRU inventory device? */
+ /* Yes. Prepare to issue FRU commands to FRU device #0 LUN 0 */
+ /* using the slave address specified in the MC record. */
+
+ /* save current target address */
+ save_addr = intf->target_addr;
+
+ /* set new target address to satellite controller */
+ intf->target_addr = mc->dev_slave_addr;
+
+ printf("FRU Device Description : %-16s\n", mc->id_string);
+
+ /* print the FRU by issuing FRU commands to the satellite */
+ /* controller. */
+ rc = __ipmi_fru_print(intf, 0);
+
+ printf("\n");
+
+ /* restore previous target */
+ intf->target_addr = save_addr;
+ }
+
+ if (mc) {
+ free(mc);
+ mc = NULL;
+ }
+
+ continue;
+ }
+
+ if (header->type != SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR)
+ continue;
+
+ /* Print the FRU from the SDR locator record. */
+ fru = (struct sdr_record_fru_locator *)
+ ipmi_sdr_get_record(intf, header, itr);
+ if (fru == NULL || !fru->logical) {
+ if (fru) {
+ free(fru);
+ fru = NULL;
+ }
+ continue;
+ }
+ rc = ipmi_fru_print(intf, fru);
+ free(fru);
+ fru = NULL;
+ }
+
+ ipmi_sdr_end(intf, itr);
+
+ return rc;
+}
+
+/* ipmi_fru_read_help() - print help text for 'read'
+ *
+ * returns void
+ */
+void
+ipmi_fru_read_help()
+{
+ lprintf(LOG_NOTICE, "fru read <fru id> <fru file>");
+ lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified.");
+ lprintf(LOG_NOTICE, "Example: ipmitool fru read 0 /root/fru.bin");
+} /* ipmi_fru_read_help() */
+
+static void
+ipmi_fru_read_to_bin(struct ipmi_intf * intf,
+ char * pFileName,
+ uint8_t fruId)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ uint8_t msg_data[4];
+ uint8_t * pFruBuf;
+
+ msg_data[0] = fruId;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp)
+ return;
+
+ if (rsp->ccode > 0) {
+ if (rsp->ccode == 0xc3)
+ printf (" Timeout accessing FRU info. (Device not present?)\n");
+ return;
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ if (verbose) {
+ printf("Fru Size = %d bytes\n",fru.size);
+ printf("Fru Access = %xh\n", fru.access);
+ }
+
+ pFruBuf = malloc(fru.size);
+ if (pFruBuf != NULL) {
+ printf("Fru Size : %d bytes\n",fru.size);
+ read_fru_area(intf, &fru, fruId, 0, fru.size, pFruBuf);
+ } else {
+ lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size);
+ return;
+ }
+
+ if(pFruBuf != NULL)
+ {
+ FILE * pFile;
+ pFile = fopen(pFileName,"wb");
+ if (pFile) {
+ fwrite(pFruBuf, fru.size, 1, pFile);
+ printf("Done\n");
+ } else {
+ lprintf(LOG_ERR, "Error opening file %s\n", pFileName);
+ free(pFruBuf);
+ pFruBuf = NULL;
+ return;
+ }
+ fclose(pFile);
+ }
+ free(pFruBuf);
+ pFruBuf = NULL;
+}
+
+static void
+ipmi_fru_write_from_bin(struct ipmi_intf * intf,
+ char * pFileName,
+ uint8_t fruId)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ uint8_t msg_data[4];
+ uint8_t *pFruBuf;
+ uint16_t len = 0;
+ FILE *pFile;
+
+ msg_data[0] = fruId;
+
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp)
+ return;
+
+ if (rsp->ccode) {
+ if (rsp->ccode == 0xc3)
+ printf(" Timeout accessing FRU info. (Device not present?)\n");
+ return;
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ if (verbose) {
+ printf("Fru Size = %d bytes\n", fru.size);
+ printf("Fru Access = %xh\n", fru.access);
+ }
+
+ pFruBuf = malloc(fru.size);
+ if (pFruBuf == NULL) {
+ lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size);
+ return;
+ }
+
+ pFile = fopen(pFileName, "rb");
+ if (pFile != NULL) {
+ len = fread(pFruBuf, 1, fru.size, pFile);
+ printf("Fru Size : %d bytes\n", fru.size);
+ printf("Size to Write : %d bytes\n", len);
+ fclose(pFile);
+ } else {
+ lprintf(LOG_ERR, "Error opening file %s\n", pFileName);
+ }
+
+ if (len != 0) {
+ write_fru_area(intf, &fru, fruId,0, 0, len, pFruBuf);
+ lprintf(LOG_INFO,"Done");
+ }
+
+ free(pFruBuf);
+ pFruBuf = NULL;
+}
+
+/* ipmi_fru_write_help() - print help text for 'write'
+ *
+ * retruns void
+ */
+void
+ipmi_fru_write_help()
+{
+ lprintf(LOG_NOTICE, "fru write <fru id> <fru file>");
+ lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified.");
+ lprintf(LOG_NOTICE, "Example: ipmitool fru write 0 /root/fru.bin");
+} /* ipmi_fru_write_help() */
+
+/* ipmi_fru_edit_help - print help text for 'fru edit' command
+ *
+ * returns void
+ */
+void
+ipmi_fru_edit_help()
+{
+ lprintf(LOG_NOTICE,
+ "fru edit <fruid> field <section> <index> <string> - edit FRU string");
+ lprintf(LOG_NOTICE,
+ "fru edit <fruid> oem iana <record> <format> <args> - limited OEM support");
+} /* ipmi_fru_edit_help() */
+
+/* ipmi_fru_edit_multirec - Query new values to replace original FRU content
+*
+* @intf: interface to use
+* @id: FRU id to work on
+*
+* returns: nothing
+*/
+/* Work in progress, copy paste most of the stuff for other functions in this
+ file ... not elegant yet */
+static int
+ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id ,
+ int argc, char ** argv)
+{
+
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ struct fru_header header;
+ uint8_t msg_data[4];
+
+ uint16_t retStatus = 0;
+ uint32_t offFruMultiRec;
+ uint32_t fruMultiRecSize = 0;
+ struct fru_info fruInfo;
+ retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo,
+ &offFruMultiRec,
+ &fruMultiRecSize);
+
+
+ lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize);
+ lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec);
+
+ {
+
+
+ memset(&fru, 0, sizeof(struct fru_info));
+ memset(&header, 0, sizeof(struct fru_header));
+
+ /*
+ * get info about this FRU
+ */
+ memset(msg_data, 0, 4);
+ msg_data[0] = id;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
+ fru.size, fru.access ? "words" : "bytes");
+
+ if (fru.size < 1) {
+ lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
+ return -1;
+ }
+ }
+
+ {
+ uint8_t * fru_data;
+ uint32_t fru_len, i;
+ uint32_t offset= offFruMultiRec;
+ struct fru_multirec_header * h;
+ uint32_t last_off, len;
+ uint8_t error=0;
+
+ i = last_off = offset;
+ fru_len = 0;
+
+ memset(&fru, 0, sizeof(fru));
+ fru_data = malloc(fru.size + 1);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, " Out of memory!");
+ return -1;
+ }
+ memset(fru_data, 0, fru.size + 1);
+
+ do {
+ h = (struct fru_multirec_header *) (fru_data + i);
+
+ /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */
+ if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
+ {
+ len = fru.size - last_off;
+ if (len > FRU_MULTIREC_CHUNK_SIZE)
+ len = FRU_MULTIREC_CHUNK_SIZE;
+
+ if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0)
+ break;
+
+ last_off += len;
+ }
+ if( h->type == FRU_RECORD_TYPE_OEM_EXTENSION ){
+
+ struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *)
+ &fru_data[i + sizeof(struct fru_multirec_header)];
+ uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
+
+ uint32_t suppliedIana = 0 ;
+ /* Now makes sure this is really PICMG record */
+
+ /* Default to PICMG for backward compatibility */
+ if( argc <=2 ) {
+ suppliedIana = IPMI_OEM_PICMG;
+ } else {
+ if( !strncmp( argv[2] , "oem" , 3 )) {
+ /* Expect IANA number next */
+ if( argc <= 3 ) {
+ lprintf(LOG_ERR, "oem iana <record> <format> [<args>]");
+ error = 1;
+ } else {
+ if (str2uint(argv[3], &suppliedIana) == 0) {
+ lprintf(LOG_DEBUG,
+ "using iana: %d",
+ suppliedIana);
+ } else {
+ lprintf(LOG_ERR,
+ "Given IANA '%s' is invalid.",
+ argv[3]);
+ error = 1;
+ }
+ }
+ }
+ }
+
+ if( suppliedIana == iana ) {
+ lprintf(LOG_DEBUG, "Matching record found" );
+
+ if( iana == IPMI_OEM_PICMG ){
+ if( ipmi_fru_picmg_ext_edit(fru_data,
+ i + sizeof(struct fru_multirec_header),
+ h->len, h, oh )){
+ /* The fru changed */
+ write_fru_area(intf,&fru,id, i,i,
+ h->len+ sizeof(struct fru_multirec_header), fru_data);
+ }
+ }
+ else if( iana == IPMI_OEM_KONTRON ) {
+ if( ipmi_fru_oemkontron_edit( argc,argv,fru_data,
+ i + sizeof(struct fru_multirec_header),
+ h->len, h, oh )){
+ /* The fru changed */
+ write_fru_area(intf,&fru,id, i,i,
+ h->len+ sizeof(struct fru_multirec_header), fru_data);
+ }
+ }
+ /* FIXME: Add OEM record support here */
+ else{
+ printf(" OEM IANA (%s) Record not support in this mode\n",
+ val2str( iana, ipmi_oem_info));
+ error = 1;
+ }
+ }
+ }
+ i += h->len + sizeof (struct fru_multirec_header);
+ } while (!(h->format & 0x80) && (error != 1));
+
+ free(fru_data);
+ fru_data = NULL;
+ }
+ return 0;
+}
+
+/* ipmi_fru_get_help - print help text for 'fru get'
+ *
+ * returns void
+ */
+void
+ipmi_fru_get_help()
+{
+ lprintf(LOG_NOTICE,
+ "fru get <fruid> oem iana <record> <format> <args> - limited OEM support");
+} /* ipmi_fru_get_help() */
+
+void
+ipmi_fru_internaluse_help()
+{
+ lprintf(LOG_NOTICE,
+ "fru internaluse <fru id> info - get internal use area size");
+ lprintf(LOG_NOTICE,
+ "fru internaluse <fru id> print - print internal use area in hex");
+ lprintf(LOG_NOTICE,
+ "fru internaluse <fru id> read <fru file> - read internal use area to file");
+ lprintf(LOG_NOTICE,
+ "fru internaluse <fru id> write <fru file> - write internal use area from file");
+} /* void ipmi_fru_internaluse_help() */
+
+/* ipmi_fru_get_multirec - Query new values to replace original FRU content
+*
+* @intf: interface to use
+* @id: FRU id to work on
+*
+* returns: nothing
+*/
+/* Work in progress, copy paste most of the stuff for other functions in this
+ file ... not elegant yet */
+static int
+ipmi_fru_get_multirec(struct ipmi_intf * intf, uint8_t id ,
+ int argc, char ** argv)
+{
+
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ struct fru_header header;
+ uint8_t msg_data[4];
+
+ uint16_t retStatus = 0;
+ uint32_t offFruMultiRec;
+ uint32_t fruMultiRecSize = 0;
+ struct fru_info fruInfo;
+ retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo,
+ &offFruMultiRec,
+ &fruMultiRecSize);
+
+
+ lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize);
+ lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec);
+
+ {
+
+
+ memset(&fru, 0, sizeof(struct fru_info));
+ memset(&header, 0, sizeof(struct fru_header));
+
+ /*
+ * get info about this FRU
+ */
+ memset(msg_data, 0, 4);
+ msg_data[0] = id;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
+ fru.size, fru.access ? "words" : "bytes");
+
+ if (fru.size < 1) {
+ lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
+ return -1;
+ }
+ }
+
+ {
+ uint8_t * fru_data;
+ uint32_t fru_len, i;
+ uint32_t offset= offFruMultiRec;
+ struct fru_multirec_header * h;
+ uint32_t last_off, len;
+ uint8_t error=0;
+
+ i = last_off = offset;
+ fru_len = 0;
+
+ fru_data = malloc(fru.size + 1);
+ if (fru_data == NULL) {
+ lprintf(LOG_ERR, " Out of memory!");
+ return -1;
+ }
+ memset(fru_data, 0, fru.size + 1);
+
+ do {
+ h = (struct fru_multirec_header *) (fru_data + i);
+
+ /* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */
+ if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
+ {
+ len = fru.size - last_off;
+ if (len > FRU_MULTIREC_CHUNK_SIZE)
+ len = FRU_MULTIREC_CHUNK_SIZE;
+
+ if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0)
+ break;
+
+ last_off += len;
+ }
+ if( h->type == FRU_RECORD_TYPE_OEM_EXTENSION ){
+
+ struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *)
+ &fru_data[i + sizeof(struct fru_multirec_header)];
+ uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
+
+ uint32_t suppliedIana = 0 ;
+ /* Now makes sure this is really PICMG record */
+ if( !strncmp( argv[2] , "oem" , 3 )) {
+ /* Expect IANA number next */
+ if( argc <= 3 ) {
+ lprintf(LOG_ERR, "oem iana <record> <format>");
+ error = 1;
+ } else {
+ if (str2uint(argv[3], &suppliedIana) == 0) {
+ lprintf(LOG_DEBUG,
+ "using iana: %d",
+ suppliedIana);
+ } else {
+ lprintf(LOG_ERR,
+ "Given IANA '%s' is invalid.",
+ argv[3]);
+ error = 1;
+ }
+ }
+ }
+
+ if( suppliedIana == iana ) {
+ lprintf(LOG_DEBUG, "Matching record found" );
+
+ if( iana == IPMI_OEM_KONTRON ) {
+ ipmi_fru_oemkontron_get( argc,argv,fru_data,
+ i + sizeof(struct fru_multirec_header),
+ h->len, h, oh );
+ }
+ /* FIXME: Add OEM record support here */
+ else{
+ printf(" OEM IANA (%s) Record not supported in this mode\n",
+ val2str( iana, ipmi_oem_info));
+ error = 1;
+ }
+ }
+ }
+ i += h->len + sizeof (struct fru_multirec_header);
+ } while (!(h->format & 0x80) && (error != 1));
+
+ free(fru_data);
+ fru_data = NULL;
+ }
+ return 0;
+}
+
+static int
+ipmi_fru_upg_ekeying(struct ipmi_intf * intf,
+ char * pFileName,
+ uint8_t fruId)
+{
+ struct fru_info fruInfo;
+ uint8_t *buf = NULL;
+ uint32_t offFruMultiRec = 0;
+ uint32_t fruMultiRecSize = 0;
+ uint32_t offFileMultiRec = 0;
+ uint32_t fileMultiRecSize = 0;
+ if (pFileName == NULL) {
+ lprintf(LOG_ERR, "File expected, but none given.");
+ return (-1);
+ }
+ if (ipmi_fru_get_multirec_location_from_fru(intf, fruId, &fruInfo,
+ &offFruMultiRec, &fruMultiRecSize) != 0) {
+ lprintf(LOG_ERR, "Failed to get multirec location from FRU.");
+ return (-1);
+ }
+ lprintf(LOG_DEBUG, "FRU Size : %lu\n", fruMultiRecSize);
+ lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec);
+ if (ipmi_fru_get_multirec_size_from_file(pFileName, &fileMultiRecSize,
+ &offFileMultiRec) != 0) {
+ lprintf(LOG_ERR, "Failed to get multirec size from file '%s'.", pFileName);
+ return (-1);
+ }
+ buf = malloc(fileMultiRecSize);
+ if (buf == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return (-1);
+ }
+ if (ipmi_fru_get_multirec_from_file(pFileName, buf, fileMultiRecSize,
+ offFileMultiRec) != 0) {
+ lprintf(LOG_ERR, "Failed to get multirec from file '%s'.", pFileName);
+ if (buf != NULL) {
+ free(buf);
+ buf = NULL;
+ }
+ return (-1);
+ }
+ if (ipmi_fru_get_adjust_size_from_buffer(buf, &fileMultiRecSize) != 0) {
+ lprintf(LOG_ERR, "Failed to adjust size from buffer.");
+ if (buf != NULL) {
+ free(buf);
+ buf = NULL;
+ }
+ return (-1);
+ }
+ if (write_fru_area(intf, &fruInfo, fruId, 0, offFruMultiRec,
+ fileMultiRecSize, buf) != 0) {
+ lprintf(LOG_ERR, "Failed to write FRU area.");
+ if (buf != NULL) {
+ free(buf);
+ buf = NULL;
+ }
+ return (-1);
+ }
+ if (buf != NULL) {
+ free(buf);
+ buf = NULL;
+ }
+ lprintf(LOG_INFO, "Done upgrading Ekey.");
+ return 0;
+}
+
+/* ipmi_fru_upgekey_help - print help text for 'upgEkey'
+ *
+ * returns void
+ */
+void
+ipmi_fru_upgekey_help()
+{
+ lprintf(LOG_NOTICE, "fru upgEkey <fru id> <fru file>");
+ lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified.");
+ lprintf(LOG_NOTICE, "Example: ipmitool fru upgEkey 0 /root/fru.bin");
+} /* ipmi_fru_upgekey_help() */
+
+static int
+ipmi_fru_get_multirec_size_from_file(char * pFileName,
+ uint32_t * pSize,
+ uint32_t * pOffset)
+{
+ struct fru_header header;
+ FILE * pFile;
+ uint8_t len = 0;
+ uint32_t end = 0;
+ *pSize = 0;
+
+ pFile = fopen(pFileName,"rb");
+ if (pFile) {
+ rewind(pFile);
+ len = fread(&header, 1, 8, pFile);
+ fseek(pFile, 0, SEEK_END);
+ end = ftell(pFile);
+ fclose(pFile);
+ }
+
+ lprintf(LOG_DEBUG, "File Size = %lu\n", end);
+ lprintf(LOG_DEBUG, "Len = %u\n", len);
+
+ if (len != 8) {
+ printf("Error with file %s in getting size\n", pFileName);
+ return -1;
+ }
+
+ if (header.version != 0x01) {
+ printf ("Unknown FRU header version %02x.\n", header.version);
+ return -1;
+ }
+
+ /* Retreive length */
+ if (((header.offset.internal * 8) > (header.offset.internal * 8)) &&
+ ((header.offset.internal * 8) < end))
+ end = (header.offset.internal * 8);
+
+ if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) &&
+ ((header.offset.chassis * 8) < end))
+ end = (header.offset.chassis * 8);
+
+ if (((header.offset.board * 8) > (header.offset.board * 8)) &&
+ ((header.offset.board * 8) < end))
+ end = (header.offset.board * 8);
+
+ if (((header.offset.product * 8) > (header.offset.product * 8)) &&
+ ((header.offset.product * 8) < end))
+ end = (header.offset.product * 8);
+
+ *pSize = end - (header.offset.multi * 8);
+ *pOffset = (header.offset.multi * 8);
+
+ return 0;
+}
+
+int
+ipmi_fru_get_adjust_size_from_buffer(uint8_t * fru_data, uint32_t *pSize)
+{
+ struct fru_multirec_header * head;
+ int status = 0;
+ uint8_t checksum = 0;
+ uint8_t counter = 0;
+ uint16_t count = 0;
+ do {
+ checksum = 0;
+ head = (struct fru_multirec_header *) (fru_data + count);
+ if (verbose) {
+ printf("Adding (");
+ }
+ for (counter = 0; counter < sizeof(struct fru_multirec_header); counter++) {
+ if (verbose) {
+ printf(" %02X", *(fru_data + count + counter));
+ }
+ checksum += *(fru_data + count + counter);
+ }
+ if (verbose) {
+ printf(")");
+ }
+ if (checksum != 0) {
+ lprintf(LOG_ERR, "Bad checksum in Multi Records");
+ status = (-1);
+ if (verbose) {
+ printf("--> FAIL");
+ }
+ } else if (verbose) {
+ printf("--> OK");
+ }
+ if (verbose > 1 && checksum == 0) {
+ for (counter = 0; counter < head->len; counter++) {
+ printf(" %02X", *(fru_data + count + counter
+ + sizeof(struct fru_multirec_header)));
+ }
+ }
+ if (verbose) {
+ printf("\n");
+ }
+ count += head->len + sizeof (struct fru_multirec_header);
+ } while ((!(head->format & 0x80)) && (status == 0));
+
+ *pSize = count;
+ lprintf(LOG_DEBUG, "Size of multirec: %lu\n", *pSize);
+ return status;
+}
+
+static int
+ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea,
+ uint32_t size, uint32_t offset)
+{
+ FILE * pFile;
+ uint32_t len = 0;
+ if (pFileName == NULL) {
+ lprintf(LOG_ERR, "Invalid file name given.");
+ return (-1);
+ }
+
+ errno = 0;
+ pFile = fopen(pFileName, "rb");
+ if (!pFile) {
+ lprintf(LOG_ERR, "Error opening file '%s': %i -> %s.", pFileName, errno,
+ strerror(errno));
+ return (-1);
+ }
+ errno = 0;
+ if (fseek(pFile, offset, SEEK_SET) != 0) {
+ lprintf(LOG_ERR, "Failed to seek in file '%s': %i -> %s.", pFileName, errno,
+ strerror(errno));
+ fclose(pFile);
+ return (-1);
+ }
+ len = fread(pBufArea, size, 1, pFile);
+ fclose(pFile);
+
+ if (len != 1) {
+ lprintf(LOG_ERR, "Error in file '%s'.", pFileName);
+ return (-1);
+ }
+ return 0;
+}
+
+static int
+ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
+ uint8_t fruId,
+ struct fru_info *pFruInfo,
+ uint32_t * pRetLocation,
+ uint32_t * pRetSize)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[4];
+ uint32_t end;
+ struct fru_header header;
+
+ *pRetLocation = 0;
+
+ msg_data[0] = fruId;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp) {
+ if (verbose > 1)
+ printf("no response\n");
+ return -1;
+ }
+
+ if (rsp->ccode > 0) {
+ if (rsp->ccode == 0xc3)
+ printf (" Timeout accessing FRU info. (Device not present?)\n");
+ else
+ printf (" CCODE = 0x%02x\n", rsp->ccode);
+ return -1;
+ }
+ pFruInfo->size = (rsp->data[1] << 8) | rsp->data[0];
+ pFruInfo->access = rsp->data[2] & 0x1;
+
+ if (verbose > 1)
+ printf("pFruInfo->size = %d bytes (accessed by %s)\n",
+ pFruInfo->size, pFruInfo->access ? "words" : "bytes");
+
+ if (!pFruInfo->size)
+ return -1;
+
+ msg_data[0] = fruId;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+ msg_data[3] = 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp)
+ return -1;
+ if (rsp->ccode > 0) {
+ if (rsp->ccode == 0xc3)
+ printf (" Timeout while reading FRU data. (Device not present?)\n");
+ return -1;
+ }
+
+ if (verbose > 1)
+ printbuf(rsp->data, rsp->data_len, "FRU DATA");
+
+ memcpy(&header, rsp->data + 1, 8);
+
+ if (header.version != 0x01) {
+ printf (" Unknown FRU header version %02x.\n", header.version);
+ return -1;
+ }
+
+ end = pFruInfo->size;
+
+ /* Retreive length */
+ if (((header.offset.internal * 8) > (header.offset.internal * 8)) &&
+ ((header.offset.internal * 8) < end))
+ end = (header.offset.internal * 8);
+
+ if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) &&
+ ((header.offset.chassis * 8) < end))
+ end = (header.offset.chassis * 8);
+
+ if (((header.offset.board * 8) > (header.offset.board * 8)) &&
+ ((header.offset.board * 8) < end))
+ end = (header.offset.board * 8);
+
+ if (((header.offset.product * 8) > (header.offset.product * 8)) &&
+ ((header.offset.product * 8) < end))
+ end = (header.offset.product * 8);
+
+ *pRetSize = end;
+ *pRetLocation = 8 * header.offset.multi;
+
+ return 0;
+}
+
+/* ipmi_fru_get_internal_use_offset - Retreive internal use offset
+*
+* @intf: ipmi interface
+* @id: fru id
+*
+* returns -1 on error
+* returns 0 if successful
+* returns 1 if device not present
+*/
+static int
+ipmi_fru_get_internal_use_info( struct ipmi_intf * intf,
+ uint8_t id,
+ struct fru_info * fru,
+ uint16_t * size,
+ uint16_t * offset)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct fru_header header;
+ uint8_t msg_data[4];
+
+ // Init output value
+ * offset = 0;
+ * size = 0;
+
+ memset(fru, 0, sizeof(struct fru_info));
+ memset(&header, 0, sizeof(struct fru_header));
+
+ /*
+ * get info about this FRU
+ */
+ memset(msg_data, 0, 4);
+ msg_data[0] = id;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru->size = (rsp->data[1] << 8) | rsp->data[0];
+ fru->access = rsp->data[2] & 0x1;
+
+ lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
+ fru->size, fru->access ? "words" : "bytes");
+
+ if (fru->size < 1) {
+ lprintf(LOG_ERR, " Invalid FRU size %d", fru->size);
+ return -1;
+ }
+
+ /*
+ * retrieve the FRU header
+ */
+ msg_data[0] = id;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+ msg_data[3] = 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return 1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return 1;
+ }
+
+ if (verbose > 1)
+ printbuf(rsp->data, rsp->data_len, "FRU DATA");
+
+ memcpy(&header, rsp->data + 1, 8);
+
+ if (header.version != 1) {
+ lprintf(LOG_ERR, " Unknown FRU header version 0x%02x",
+ header.version);
+ return -1;
+ }
+
+ lprintf(LOG_DEBUG, "fru.header.version: 0x%x",
+ header.version);
+ lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x",
+ header.offset.internal * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.chassis: 0x%x",
+ header.offset.chassis * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.board: 0x%x",
+ header.offset.board * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.product: 0x%x",
+ header.offset.product * 8);
+ lprintf(LOG_DEBUG, "fru.header.offset.multi: 0x%x",
+ header.offset.multi * 8);
+
+ if((header.offset.internal*8) == 0)
+ {
+ * size = 0;
+ * offset = 0;
+ }
+ else
+ {
+ (* offset) = (header.offset.internal*8);
+
+ if(header.offset.chassis != 0)
+ {
+ (* size) = ((header.offset.chassis*8)-(* offset));
+ }
+ else if(header.offset.board != 0)
+ {
+ (* size) = ((header.offset.board*8)-(* offset));
+ }
+ else if(header.offset.product != 0)
+ {
+ (* size) = ((header.offset.product*8)-(* offset));
+ }
+ else if(header.offset.multi != 0)
+ {
+ (* size) = ((header.offset.multi*8)-(* offset));
+ }
+ else
+ {
+ (* size) = (fru->size - (* offset));
+ }
+ }
+ return 0;
+}
+
+/* ipmi_fru_info_internal_use - print internal use info
+*
+* @intf: ipmi interface
+* @id: fru id
+*
+* returns -1 on error
+* returns 0 if successful
+* returns 1 if device not present
+*/
+static int
+ipmi_fru_info_internal_use(struct ipmi_intf * intf, uint8_t id)
+{
+ struct fru_info fru;
+ uint16_t size;
+ uint16_t offset;
+ int rc = 0;
+
+ rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset);
+
+ if(rc == 0)
+ {
+ lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset);
+ printf( "Internal Use Area Size : %i\n", size);
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Cannot access internal use area");
+ return -1;
+ }
+ return 0;
+}
+
+/* ipmi_fru_help - print help text for FRU subcommand
+ *
+ * returns void
+ */
+void
+ipmi_fru_help()
+{
+ lprintf(LOG_NOTICE,
+ "FRU Commands: print read write upgEkey edit internaluse get");
+} /* ipmi_fru_help() */
+
+/* ipmi_fru_read_internal_use - print internal use are in hex or file
+*
+* @intf: ipmi interface
+* @id: fru id
+*
+* returns -1 on error
+* returns 0 if successful
+* returns 1 if device not present
+*/
+static int
+ipmi_fru_read_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName)
+{
+ struct fru_info fru;
+ uint16_t size;
+ uint16_t offset;
+ int rc = 0;
+
+ rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset);
+
+ if(rc == 0)
+ {
+ uint8_t * frubuf;
+
+ lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset);
+ printf( "Internal Use Area Size : %i\n", size);
+
+ frubuf = malloc( size );
+ if(frubuf)
+ {
+ rc = read_fru_area_section(intf, &fru, id, offset, size, frubuf);
+
+ if(rc == 0)
+ {
+ if(pFileName == NULL)
+ {
+ uint16_t counter;
+ for(counter = 0; counter < size; counter ++)
+ {
+ if((counter % 16) == 0)
+ printf("\n%02i- ", (counter / 16));
+ printf("%02X ", frubuf[counter]);
+ }
+ }
+ else
+ {
+ FILE * pFile;
+ pFile = fopen(pFileName,"wb");
+ if (pFile)
+ {
+ fwrite(frubuf, size, 1, pFile);
+ printf("Done\n");
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Error opening file %s\n", pFileName);
+ free(frubuf);
+ frubuf = NULL;
+ return -1;
+ }
+ fclose(pFile);
+ }
+ }
+ printf("\n");
+
+ free(frubuf);
+ frubuf = NULL;
+ }
+
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Cannot access internal use area");
+ }
+ return 0;
+}
+
+/* ipmi_fru_write_internal_use - print internal use are in hex or file
+*
+* @intf: ipmi interface
+* @id: fru id
+*
+* returns -1 on error
+* returns 0 if successful
+* returns 1 if device not present
+*/
+static int
+ipmi_fru_write_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName)
+{
+ struct fru_info fru;
+ uint16_t size;
+ uint16_t offset;
+ int rc = 0;
+
+ rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset);
+
+ if(rc == 0)
+ {
+ uint8_t * frubuf;
+ FILE * fp;
+ uint32_t fileLength = 0;
+
+ lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset);
+ printf( "Internal Use Area Size : %i\n", size);
+
+ fp = fopen(pFileName, "r");
+
+ if(fp)
+ {
+ /* Retreive file length, check if it's fits the Eeprom Size */
+ fseek(fp, 0 ,SEEK_END);
+ fileLength = ftell(fp);
+
+ lprintf(LOG_ERR, "File Size: %i", fileLength);
+ lprintf(LOG_ERR, "Area Size: %i", size);
+ if(fileLength != size)
+ {
+ lprintf(LOG_ERR, "File size does not fit Eeprom Size");
+ fclose(fp);
+ fp = NULL;
+ }
+ else
+ {
+ fseek(fp, 0 ,SEEK_SET);
+ }
+ }
+
+ if(fp)
+ {
+ frubuf = malloc( size );
+ if(frubuf)
+ {
+ uint16_t fru_read_size;
+ fru_read_size = fread(frubuf, 1, size, fp);
+
+ if(fru_read_size == size)
+ {
+ rc = write_fru_area(intf, &fru, id, 0, offset, size, frubuf);
+
+ if(rc == 0)
+ {
+ lprintf(LOG_INFO, "Done\n");
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Unable to read file: %i\n", fru_read_size);
+ }
+
+ free(frubuf);
+ frubuf = NULL;
+ }
+ fclose(fp);
+ fp = NULL;
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Cannot access internal use area");
+ }
+ return 0;
+}
+
+int
+ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ uint8_t fru_id = 0;
+
+ if (argc < 1) {
+ rc = ipmi_fru_print_all(intf);
+ }
+ else if (strncmp(argv[0], "help", 4) == 0) {
+ ipmi_fru_help();
+ return 0;
+ }
+ else if (strncmp(argv[0], "print", 5) == 0 ||
+ strncmp(argv[0], "list", 4) == 0) {
+ if (argc > 1) {
+ if (strcmp(argv[1], "help") == 0) {
+ lprintf(LOG_NOTICE, "fru print [fru id] - print information about FRU(s)");
+ return 0;
+ }
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ rc = __ipmi_fru_print(intf, fru_id);
+ } else {
+ rc = ipmi_fru_print_all(intf);
+ }
+ }
+ else if (!strncmp(argv[0], "read", 5)) {
+ if (argc > 1 && strcmp(argv[1], "help") == 0) {
+ ipmi_fru_read_help();
+ return 0;
+ } else if (argc < 3) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ ipmi_fru_read_help();
+ return (-1);
+ }
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ /* There is a file name in the parameters */
+ if (is_valid_filename(argv[2]) != 0)
+ return (-1);
+
+ if (verbose) {
+ printf("FRU ID : %d\n", fru_id);
+ printf("FRU File : %s\n", argv[2]);
+ }
+ /* TODO - rc is missing */
+ ipmi_fru_read_to_bin(intf, argv[2], fru_id);
+ }
+ else if (!strncmp(argv[0], "write", 5)) {
+ if (argc > 1 && strcmp(argv[1], "help") == 0) {
+ ipmi_fru_write_help();
+ return 0;
+ } else if (argc < 3) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ ipmi_fru_write_help();
+ return (-1);
+ }
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ /* There is a file name in the parameters */
+ if (is_valid_filename(argv[2]) != 0)
+ return (-1);
+
+ if (verbose) {
+ printf("FRU ID : %d\n", fru_id);
+ printf("FRU File : %s\n", argv[2]);
+ }
+ /* TODO - rc is missing */
+ ipmi_fru_write_from_bin(intf, argv[2], fru_id);
+ }
+ else if (!strncmp(argv[0], "upgEkey", 7)) {
+ if (argc > 1 && strcmp(argv[1], "help") == 0) {
+ ipmi_fru_upgekey_help();
+ return 0;
+ } else if (argc < 3) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ ipmi_fru_upgekey_help();
+ return (-1);
+ }
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ /* There is a file name in the parameters */
+ if (is_valid_filename(argv[2]) != 0)
+ return (-1);
+
+ rc = ipmi_fru_upg_ekeying(intf, argv[2], fru_id);
+ }
+ else if (!strncmp(argv[0], "internaluse", 11)) {
+ if (argc > 1 && strcmp(argv[1], "help") == 0) {
+ ipmi_fru_internaluse_help();
+ return 0;
+ }
+
+ if ( (argc >= 3) && (!strncmp(argv[2], "info", 4)) ) {
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ rc = ipmi_fru_info_internal_use(intf, fru_id);
+ }
+ else if ( (argc >= 3) && (!strncmp(argv[2], "print", 5)) ) {
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ rc = ipmi_fru_read_internal_use(intf, fru_id, NULL);
+ }
+ else if ( (argc >= 4) && (!strncmp(argv[2], "read", 4)) ) {
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ /* There is a file name in the parameters */
+ if (is_valid_filename(argv[3]) != 0)
+ return (-1);
+
+ lprintf(LOG_DEBUG, "FRU ID : %d", fru_id);
+ lprintf(LOG_DEBUG, "FRU File : %s", argv[3]);
+
+ rc = ipmi_fru_read_internal_use(intf, fru_id, argv[3]);
+ }
+ else if ( (argc >= 4) && (!strncmp(argv[2], "write", 5)) ) {
+
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ /* There is a file name in the parameters */
+ if (is_valid_filename(argv[3]) != 0)
+ return (-1);
+
+ lprintf(LOG_DEBUG, "FRU ID : %d", fru_id);
+ lprintf(LOG_DEBUG, "FRU File : %s", argv[3]);
+
+ rc = ipmi_fru_write_internal_use(intf, fru_id, argv[3]);
+ } else {
+ lprintf(LOG_ERR,
+ "Either unknown command or not enough parameters given.");
+ ipmi_fru_internaluse_help();
+ return (-1);
+ }
+ }
+ else if (!strncmp(argv[0], "edit", 4)) {
+ if (argc > 1 && strcmp(argv[1], "help") == 0) {
+ ipmi_fru_edit_help();
+ return 0;
+ } else if (argc < 2) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ ipmi_fru_edit_help();
+ return (-1);
+ }
+
+ if (argc >= 2) {
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ if (verbose) {
+ printf("FRU ID : %d\n", fru_id);
+ }
+ } else {
+ printf("Using default FRU ID: %d\n", fru_id);
+ }
+
+ if (argc >= 3) {
+ if (!strncmp(argv[2], "field", 5)) {
+ if (argc != 6) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ ipmi_fru_edit_help();
+ return (-1);
+ }
+ rc = ipmi_fru_set_field_string(intf, fru_id, *argv[3], *argv[4],
+ (char *) argv[5]);
+ } else if (!strncmp(argv[2], "oem", 3)) {
+ rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv);
+ } else {
+ lprintf(LOG_ERR, "Invalid command: %s", argv[2]);
+ ipmi_fru_edit_help();
+ return (-1);
+ }
+ } else {
+ rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv);
+ }
+ }
+ else if (!strncmp(argv[0], "get", 4)) {
+ if (argc > 1 && (strncmp(argv[1], "help", 4) == 0)) {
+ ipmi_fru_get_help();
+ return 0;
+ } else if (argc < 2) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ ipmi_fru_get_help();
+ return (-1);
+ }
+
+ if (argc >= 2) {
+ if (is_fru_id(argv[1], &fru_id) != 0)
+ return (-1);
+
+ if (verbose) {
+ printf("FRU ID : %d\n", fru_id);
+ }
+ } else {
+ printf("Using default FRU ID: %d\n", fru_id);
+ }
+
+ if (argc >= 3) {
+ if (!strncmp(argv[2], "oem", 3)) {
+ rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv);
+ } else {
+ lprintf(LOG_ERR, "Invalid command: %s", argv[2]);
+ ipmi_fru_get_help();
+ return (-1);
+ }
+ } else {
+ rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv);
+ }
+ }
+ else {
+ lprintf(LOG_ERR, "Invalid FRU command: %s", argv[0]);
+ ipmi_fru_help();
+ return (-1);
+ }
+
+ return rc;
+}
+
+/* ipmi_fru_set_field_string - Set a field string to a new value, Need to be the same size. If
+* size if not equal, the function ipmi_fru_set_field_string_rebuild
+* will be called.
+*
+* @intf: ipmi interface
+* @id: fru id
+* @f_type: Type of the Field : c=Chassis b=Board p=Product
+* @f_index: findex of the field, zero indexed.
+* @f_string: NULL terminated string
+*
+* returns -1 on error
+* returns 1 if successful
+*/
+static int
+ipmi_fru_set_field_string(struct ipmi_intf * intf, uint8_t fruId, uint8_t
+f_type, uint8_t f_index, char *f_string)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+
+ struct fru_info fru;
+ struct fru_header header;
+ uint8_t msg_data[4];
+ uint8_t checksum;
+ int i = 0;
+ int rc = 1;
+ uint8_t *fru_data = NULL;
+ uint8_t *fru_area = NULL;
+ uint32_t fru_field_offset, fru_field_offset_tmp;
+ uint32_t fru_section_len, header_offset;
+
+ memset(msg_data, 0, 4);
+ msg_data[0] = fruId;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ if (fru.size < 1) {
+ printf(" Invalid FRU size %d", fru.size);
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+ /*
+ * retrieve the FRU header
+ */
+ msg_data[0] = fruId;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+ msg_data[3] = 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ printf(" Device not present (No Response)\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+ if (rsp->ccode > 0)
+ {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+
+ if (verbose > 1)
+ printbuf(rsp->data, rsp->data_len, "FRU DATA");
+
+ memcpy(&header, rsp->data + 1, 8);
+
+ if (header.version != 1)
+ {
+ printf(" Unknown FRU header version 0x%02x",
+ header.version);
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+
+ fru_data = malloc( fru.size );
+
+ if( fru_data == NULL )
+ {
+ printf("Out of memory!\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+
+ /* Setup offset from the field type */
+
+ /* Chassis type field */
+ if (f_type == 'c' ) {
+ header_offset = (header.offset.chassis * 8);
+ read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
+ fru_field_offset = 3;
+ fru_section_len = *(fru_data + 1) * 8;
+ }
+ /* Board type field */
+ else if (f_type == 'b' ) {
+ header_offset = (header.offset.board * 8);
+ read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
+ fru_field_offset = 6;
+ fru_section_len = *(fru_data + 1) * 8;
+ }
+ /* Product type field */
+ else if (f_type == 'p' ) {
+ header_offset = (header.offset.product * 8);
+ read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
+ fru_field_offset = 3;
+ fru_section_len = *(fru_data + 1) * 8;
+ }
+ else
+ {
+ printf("Wrong field type.");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+ memset(fru_data, 0, fru.size);
+ if( read_fru_area(intf ,&fru, fruId, header_offset ,
+ fru_section_len , fru_data) < 0 )
+ {
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+ /* Convert index from character to decimal */
+ f_index= f_index - 0x30;
+
+ /*Seek to field index */
+ for (i=0; i <= f_index; i++) {
+ fru_field_offset_tmp = fru_field_offset;
+ if (fru_area != NULL) {
+ free(fru_area);
+ fru_area = NULL;
+ }
+ fru_area = (uint8_t *) get_fru_area_str(fru_data, &fru_field_offset);
+ }
+
+ if( (fru_area == NULL ) || strlen((const char *)fru_area) == 0 ) {
+ printf("Field not found !\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+
+ if ( strlen((const char *)fru_area) == strlen((const char *)f_string) )
+ {
+ printf("Updating Field '%s' with '%s' ...\n", fru_area, f_string );
+ memcpy(fru_data + fru_field_offset_tmp + 1,
+ f_string, strlen(f_string));
+
+ checksum = 0;
+ /* Calculate Header Checksum */
+ for( i = header_offset; i < header_offset
+ + fru_section_len - 1; i ++ )
+ {
+ checksum += fru_data[i];
+ }
+ checksum = (~checksum) + 1;
+ fru_data[header_offset + fru_section_len - 1] = checksum;
+
+ /* Write the updated section to the FRU data; source offset => 0 */
+ if( write_fru_area(intf, &fru, fruId, 0,
+ header_offset, fru_section_len, fru_data) < 0 )
+ {
+ printf("Write to FRU data failed.\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+ }
+ else {
+ printf("String size are not equal, resizing fru to fit new string\n");
+ if(
+ ipmi_fru_set_field_string_rebuild(intf,fruId,fru,header,f_type,f_index,f_string)
+ )
+ {
+ rc = (-1);
+ goto ipmi_fru_set_field_string_out;
+ }
+ }
+
+ ipmi_fru_set_field_string_out:
+ if (fru_data != NULL) {
+ free(fru_data);
+ fru_data = NULL;
+ }
+ if (fru_area != NULL) {
+ free(fru_area);
+ fru_area = NULL;
+ }
+
+ return rc;
+}
+
+/*
+ This function can update a string within of the following section when the size is not equal:
+
+ Chassis
+ Product
+ Board
+*/
+/* ipmi_fru_set_field_string_rebuild - Set a field string to a new value, When size are not
+* the same size.
+*
+* This function can update a string within of the following section when the size is not equal:
+*
+* - Chassis
+* - Product
+* - Board
+*
+* @intf: ipmi interface
+* @fruId: fru id
+* @fru: info about fru
+* @header: contain the header of the FRU
+* @f_type: Type of the Field : c=Chassis b=Board p=Product
+* @f_index: findex of the field, zero indexed.
+* @f_string: NULL terminated string
+*
+* returns -1 on error
+* returns 1 if successful
+*/
+
+#define DBG_RESIZE_FRU
+static int
+ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId,
+ struct fru_info fru, struct fru_header header,
+ uint8_t f_type, uint8_t f_index, char *f_string)
+{
+ uint8_t msg_data[4];
+ uint8_t checksum;
+ int i = 0;
+ uint8_t *fru_data_old = NULL;
+ uint8_t *fru_data_new = NULL;
+ uint8_t *fru_area = NULL;
+ uint32_t fru_field_offset, fru_field_offset_tmp;
+ uint32_t fru_section_len, old_section_len, header_offset;
+ uint32_t chassis_offset, board_offset, product_offset;
+ uint32_t chassis_len, board_len, product_len, product_len_new;
+ int num_byte_change = 0, padding_len = 0;
+ uint32_t counter;
+ unsigned char cksum;
+ int rc = 1;
+
+ fru_data_old = calloc( fru.size, sizeof(uint8_t) );
+
+ fru_data_new = malloc( fru.size );
+
+ if( fru_data_old == NULL || fru_data_new == NULL )
+ {
+ printf("Out of memory!\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_rebuild_out;
+ }
+
+ /*************************
+ 1) Read ALL FRU */
+ printf("Read All FRU area\n");
+ printf("Fru Size : %u bytes\n", fru.size);
+
+ /* Read current fru data */
+ read_fru_area(intf ,&fru, fruId, 0, fru.size , fru_data_old);
+
+ #ifdef DBG_RESIZE_FRU
+ printf("Copy to new FRU\n");
+ #endif
+
+ /*************************
+ 2) Copy all FRU to new FRU */
+ memcpy(fru_data_new, fru_data_old, fru.size);
+
+ /* Build location of all modifiable components */
+ chassis_offset = (header.offset.chassis * 8);
+ board_offset = (header.offset.board * 8);
+ product_offset = (header.offset.product * 8);
+
+ /* Retrieve length of all modifiable components */
+ chassis_len = *(fru_data_old + chassis_offset + 1) * 8;
+ board_len = *(fru_data_old + board_offset + 1) * 8;
+ product_len = *(fru_data_old + product_offset + 1) * 8;
+ product_len_new = product_len;
+
+ /* Chassis type field */
+ if (f_type == 'c' )
+ {
+ header_offset = chassis_offset;
+ fru_field_offset = chassis_offset + 3;
+ fru_section_len = chassis_len;
+ }
+ /* Board type field */
+ else if (f_type == 'b' )
+ {
+ header_offset = board_offset;
+ fru_field_offset = board_offset + 6;
+ fru_section_len = board_len;
+ }
+ /* Product type field */
+ else if (f_type == 'p' )
+ {
+ header_offset = product_offset;
+ fru_field_offset = product_offset + 3;
+ fru_section_len = product_len;
+ }
+ else
+ {
+ printf("Wrong field type.");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_rebuild_out;
+ }
+
+ /* Keep length for future old section display */
+ old_section_len = fru_section_len;
+
+ /*************************
+ 3) Seek to field index */
+ for (i = 0;i <= f_index; i++) {
+ fru_field_offset_tmp = fru_field_offset;
+ if (fru_area != NULL) {
+ free(fru_area);
+ fru_area = NULL;
+ }
+ fru_area = (uint8_t *) get_fru_area_str(fru_data_old, &fru_field_offset);
+ }
+
+ if( (fru_area == NULL ) || strlen((const char *)fru_area) == 0 ) {
+ printf("Field not found (1)!\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_rebuild_out;
+ }
+
+ #ifdef DBG_RESIZE_FRU
+ printf("Section Length: %u\n", fru_section_len);
+ #endif
+
+ /*************************
+ 4) Check number of padding bytes and bytes changed */
+ for(counter = 2; counter < fru_section_len; counter ++)
+ {
+ if(*(fru_data_old + (header_offset + fru_section_len - counter)) == 0)
+ padding_len ++;
+ else
+ break;
+ }
+ num_byte_change = strlen(f_string) - strlen(fru_area);
+
+ #ifdef DBG_RESIZE_FRU
+ printf("Padding Length: %u\n", padding_len);
+ printf("NumByte Change: %i\n", num_byte_change);
+ printf("Start SecChnge: %x\n", *(fru_data_old + fru_field_offset_tmp));
+ printf("End SecChnge : %x\n", *(fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1));
+
+ printf("Start Section : %x\n", *(fru_data_old + header_offset));
+ printf("End Sec wo Pad: %x\n", *(fru_data_old + header_offset + fru_section_len - 2 - padding_len));
+ printf("End Section : %x\n", *(fru_data_old + header_offset + fru_section_len - 1));
+ #endif
+
+ /* Calculate New Padding Length */
+ padding_len -= num_byte_change;
+
+ #ifdef DBG_RESIZE_FRU
+ printf("New Padding Length: %i\n", padding_len);
+ #endif
+
+ /*************************
+ 5) Check if section must be resize. This occur when padding length is not between 0 and 7 */
+ if( (padding_len < 0) || (padding_len >= 8))
+ {
+ uint32_t remaining_offset = ((header.offset.product * 8) + product_len);
+ int change_size_by_8;
+
+ if(padding_len >= 8)
+ {
+ /* Section must be set smaller */
+ change_size_by_8 = ((padding_len) / 8) * (-1);
+ }
+ else
+ {
+ /* Section must be set bigger */
+ change_size_by_8 = 1 + (((padding_len+1) / 8) * (-1));
+ }
+
+ /* Recalculate padding and section length base on the section changes */
+ fru_section_len += (change_size_by_8 * 8);
+ padding_len += (change_size_by_8 * 8);
+
+ #ifdef DBG_RESIZE_FRU
+ printf("change_size_by_8: %i\n", change_size_by_8);
+ printf("New Padding Length: %i\n", padding_len);
+ printf("change_size_by_8: %i\n", change_size_by_8);
+ printf("header.offset.board: %i\n", header.offset.board);
+ #endif
+
+ /* Must move sections */
+ /* Section that can be modified are as follow
+ Chassis
+ Board
+ product */
+
+ /* Chassis type field */
+ if (f_type == 'c' )
+ {
+ printf("Moving Section Chassis, from %i to %i\n",
+ ((header.offset.board) * 8),
+ ((header.offset.board + change_size_by_8) * 8)
+ );
+ memcpy(
+ (fru_data_new + ((header.offset.board + change_size_by_8) * 8)),
+ (fru_data_old + (header.offset.board) * 8),
+ board_len
+ );
+ header.offset.board += change_size_by_8;
+ }
+ /* Board type field */
+ if ((f_type == 'c' ) || (f_type == 'b' ))
+ {
+ printf("Moving Section Product, from %i to %i\n",
+ ((header.offset.product) * 8),
+ ((header.offset.product + change_size_by_8) * 8)
+ );
+ memcpy(
+ (fru_data_new + ((header.offset.product + change_size_by_8) * 8)),
+ (fru_data_old + (header.offset.product) * 8),
+ product_len
+ );
+ header.offset.product += change_size_by_8;
+ }
+
+ /* Adjust length of the section */
+ if (f_type == 'c')
+ {
+ *(fru_data_new + chassis_offset + 1) += change_size_by_8;
+ }
+ else if( f_type == 'b')
+ {
+ *(fru_data_new + board_offset + 1) += change_size_by_8;
+ }
+ else if( f_type == 'p')
+ {
+ *(fru_data_new + product_offset + 1) += change_size_by_8;
+ product_len_new = *(fru_data_new + product_offset + 1) * 8;
+ }
+
+ /* Rebuild Header checksum */
+ {
+ unsigned char * pfru_header = (unsigned char *) &header;
+ header.checksum = 0;
+ for(counter = 0; counter < (sizeof(struct fru_header) -1); counter ++)
+ {
+ header.checksum += pfru_header[counter];
+ }
+ header.checksum = (0 - header.checksum);
+ memcpy(fru_data_new, pfru_header, sizeof(struct fru_header));
+ }
+
+ /* Move remaining sections in 1 copy */
+ printf("Moving Remaining Bytes (Multi-Rec , etc..), from %i to %i\n",
+ remaining_offset,
+ ((header.offset.product) * 8) + product_len_new
+ );
+ if(((header.offset.product * 8) + product_len_new - remaining_offset) < 0)
+ {
+ memcpy(
+ fru_data_new + (header.offset.product * 8) + product_len_new,
+ fru_data_old + remaining_offset,
+ fru.size - remaining_offset
+ );
+ }
+ else
+ {
+ memcpy(
+ fru_data_new + (header.offset.product * 8) + product_len_new,
+ fru_data_old + remaining_offset,
+ fru.size - ((header.offset.product * 8) + product_len_new)
+ );
+ }
+ }
+
+ /* Update only if it's fits padding length as defined in the spec, otherwise, it's an internal
+ error */
+ /*************************
+ 6) Update Field and sections */
+ if( (padding_len >=0) && (padding_len < 8))
+ {
+ /* Do not requires any change in other section */
+
+ /* Change field length */
+ printf(
+ "Updating Field : '%s' with '%s' ... (Length from '%d' to '%d')\n",
+ fru_area, f_string,
+ (int)*(fru_data_old + fru_field_offset_tmp),
+ (int)(0xc0 + strlen(f_string)));
+ *(fru_data_new + fru_field_offset_tmp) = (0xc0 + strlen(f_string));
+ memcpy(fru_data_new + fru_field_offset_tmp + 1, f_string, strlen(f_string));
+
+ /* Copy remaing bytes in section */
+#ifdef DBG_RESIZE_FRU
+ printf("Copying remaining of sections: %d \n",
+ (int)((fru_data_old + header_offset + fru_section_len - 1) -
+ (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)));
+#endif
+
+ memcpy((fru_data_new + fru_field_offset_tmp + 1 +
+ strlen(f_string)),
+ (fru_data_old + fru_field_offset_tmp + 1 +
+ strlen(fru_area)),
+ ((fru_data_old + header_offset + fru_section_len - 1) -
+ (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)));
+
+ /* Add Padding if required */
+ for(counter = 0; counter < padding_len; counter ++)
+ {
+ *(fru_data_new + header_offset + fru_section_len - 1 -
+ padding_len + counter) = 0;
+ }
+
+ /* Calculate New Checksum */
+ cksum = 0;
+ for( counter = 0; counter <fru_section_len-1; counter ++ )
+ {
+ cksum += *(fru_data_new + header_offset + counter);
+ }
+ *(fru_data_new + header_offset + fru_section_len - 1) = (0 - cksum);
+
+ #ifdef DBG_RESIZE_FRU
+ printf("Calculate New Checksum: %x\n", (0 - cksum));
+ #endif
+
+ /****** ENABLE to show section modified before and after ********/
+ #if 0
+ printf("Section: ");
+ for( counter = 0; counter <old_section_len; counter ++ )
+ {
+ if((counter %16) == 0)
+ {
+ printf("\n");
+ }
+ printf( "%02X ", *(fru_data_old + header_offset + counter) );
+ }
+ printf("\n");
+
+ printf("Section: ");
+ for( counter = 0; counter <fru_section_len; counter ++ )
+ {
+ if((counter %16) == 0)
+ {
+ printf("\n");
+ }
+ printf( "%02X ", *(fru_data_new + header_offset + counter) );
+ }
+ printf("\n");
+ #endif
+ }
+ else
+ {
+ printf( "Internal error, padding length %i (must be from 0 to 7) ", padding_len );
+ rc = (-1);
+ goto ipmi_fru_set_field_string_rebuild_out;
+ }
+
+ /*************************
+ 7) Finally, write new FRU */
+ printf("Writing new FRU.\n");
+ if( write_fru_area( intf, &fru, fruId, 0, 0, fru.size, fru_data_new ) < 0 )
+ {
+ printf("Write to FRU data failed.\n");
+ rc = (-1);
+ goto ipmi_fru_set_field_string_rebuild_out;
+ }
+
+ printf("Done.\n");
+
+ ipmi_fru_set_field_string_rebuild_out:
+ if (fru_area != NULL) {
+ free(fru_area);
+ fru_area = NULL;
+ }
+ if (fru_data_new != NULL) {
+ free(fru_data_new);
+ fru_data_new = NULL;
+ }
+ if (fru_data_old != NULL) {
+ free(fru_data_old);
+ fru_data_old = NULL;
+ }
+
+ return rc;
+}
diff --git a/lib/ipmi_fwum.c b/lib/ipmi_fwum.c
new file mode 100644
index 0000000..b666a2b
--- /dev/null
+++ b/lib/ipmi_fwum.c
@@ -0,0 +1,1132 @@
+/*
+ * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved.
+ *
+ * Base on code from
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <ipmitool/log.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_fwum.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_mc.h>
+
+extern int verbose;
+unsigned char firmBuf[1024*512];
+tKFWUM_SaveFirmwareInfo save_fw_nfo;
+
+int KfwumGetFileSize(const char *pFileName,
+ unsigned long *pFileSize);
+int KfwumSetupBuffersFromFile(const char *pFileName,
+ unsigned long fileSize);
+void KfwumShowProgress(const char *task, unsigned long current,
+ unsigned long total);
+unsigned short KfwumCalculateChecksumPadding(unsigned char *pBuffer,
+ unsigned long totalSize);
+int KfwumGetInfo(struct ipmi_intf *intf, unsigned char output,
+ unsigned char *pNumBank);
+int KfwumGetDeviceInfo(struct ipmi_intf *intf,
+ unsigned char output, tKFWUM_BoardInfo *pBoardInfo);
+int KfwumGetStatus(struct ipmi_intf *intf);
+int KfwumManualRollback(struct ipmi_intf *intf);
+int KfwumStartFirmwareImage(struct ipmi_intf *intf,
+ unsigned long length, unsigned short padding);
+int KfwumSaveFirmwareImage(struct ipmi_intf *intf,
+ unsigned char sequenceNumber, unsigned long address,
+ unsigned char *pFirmBuf, unsigned char *pInBufLength);
+int KfwumFinishFirmwareImage(struct ipmi_intf *intf,
+ tKFWUM_InFirmwareInfo firmInfo);
+int KfwumUploadFirmware(struct ipmi_intf *intf,
+ unsigned char *pBuffer, unsigned long totalSize);
+int KfwumStartFirmwareUpgrade(struct ipmi_intf *intf);
+int KfwumGetInfoFromFirmware(unsigned char *pBuf,
+ unsigned long bufSize, tKFWUM_InFirmwareInfo *pInfo);
+void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo *pInfo);
+int KfwumGetTraceLog(struct ipmi_intf *intf);
+int ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo,
+ tKFWUM_InFirmwareInfo firmInfo);
+
+int ipmi_fwum_fwupgrade(struct ipmi_intf *intf, char *file, int action);
+int ipmi_fwum_info(struct ipmi_intf *intf);
+int ipmi_fwum_status(struct ipmi_intf *intf);
+void printf_kfwum_help(void);
+void printf_kfwum_info(tKFWUM_BoardInfo boardInfo,
+ tKFWUM_InFirmwareInfo firmInfo);
+
+/* String table */
+/* Must match eFWUM_CmdId */
+const char *CMD_ID_STRING[] = {
+ "GetFwInfo",
+ "KickWatchdog",
+ "GetLastAnswer",
+ "BootHandshake",
+ "ReportStatus",
+ "CtrlIPMBLine",
+ "SetFwState",
+ "GetFwStatus",
+ "GetSpiMemStatus",
+ "StartFwUpdate",
+ "StartFwImage",
+ "SaveFwImage",
+ "FinishFwImage",
+ "ReadFwImage",
+ "ManualRollback",
+ "GetTraceLog"
+};
+
+const char *EXT_CMD_ID_STRING[] = {
+ "FwUpgradeLock",
+ "ProcessFwUpg",
+ "ProcessFwRb",
+ "WaitHSAfterUpg",
+ "WaitFirstHSUpg",
+ "FwInfoStateChange"
+};
+
+const char *CMD_STATE_STRING[] = {
+ "Invalid",
+ "Begin",
+ "Progress",
+ "Completed"
+};
+
+const struct valstr bankStateValS[] = {
+ { 0x00, "Not programmed" },
+ { 0x01, "New firmware" },
+ { 0x02, "Wait for validation" },
+ { 0x03, "Last Known Good" },
+ { 0x04, "Previous Good" }
+};
+
+/* ipmi_fwum_main - entry point for this ipmitool mode
+ *
+ * @intf: ipmi interface
+ * @arc: number of arguments
+ * @argv: point to argument array
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_fwum_main(struct ipmi_intf *intf, int argc, char **argv)
+{
+ int rc = 0;
+ printf("FWUM extension Version %d.%d\n", VER_MAJOR, VER_MINOR);
+ if (argc < 1) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ printf_kfwum_help();
+ return (-1);
+ }
+ if (strncmp(argv[0], "help", 4) == 0) {
+ printf_kfwum_help();
+ rc = 0;
+ } else if (strncmp(argv[0], "info", 4) == 0) {
+ rc = ipmi_fwum_info(intf);
+ } else if (strncmp(argv[0], "status", 6) == 0) {
+ rc = ipmi_fwum_status(intf);
+ } else if (strncmp(argv[0], "rollback", 8) == 0) {
+ rc = KfwumManualRollback(intf);
+ } else if (strncmp(argv[0], "download", 8) == 0) {
+ if ((argc < 2) || (strlen(argv[1]) < 1)) {
+ lprintf(LOG_ERR,
+ "Path and file name must be specified.");
+ return (-1);
+ }
+ printf("Firmware File Name : %s\n", argv[1]);
+ rc = ipmi_fwum_fwupgrade(intf, argv[1], 0);
+ } else if (strncmp(argv[0], "upgrade", 7) == 0) {
+ if ((argc >= 2) && (strlen(argv[1]) > 0)) {
+ printf("Upgrading using file name %s\n", argv[1]);
+ rc = ipmi_fwum_fwupgrade(intf, argv[1], 1);
+ } else {
+ rc = KfwumStartFirmwareUpgrade(intf);
+ }
+ } else if (strncmp(argv[0], "tracelog", 8) == 0) {
+ rc = KfwumGetTraceLog(intf);
+ } else {
+ lprintf(LOG_ERR, "Invalid KFWUM command: %s", argv[0]);
+ printf_kfwum_help();
+ rc = (-1);
+ }
+ return rc;
+}
+
+void
+printf_kfwum_help(void)
+{
+ lprintf(LOG_NOTICE,
+"KFWUM Commands: info status download upgrade rollback tracelog");
+}
+
+/* private definitions and macros */
+typedef enum eFWUM_CmdId
+{
+ KFWUM_CMD_ID_GET_FIRMWARE_INFO = 0,
+ KFWUM_CMD_ID_KICK_IPMC_WATCHDOG = 1,
+ KFWUM_CMD_ID_GET_LAST_ANSWER = 2,
+ KFWUM_CMD_ID_BOOT_HANDSHAKE = 3,
+ KFWUM_CMD_ID_REPORT_STATUS = 4,
+ KFWUM_CMD_ID_GET_FIRMWARE_STATUS = 7,
+ KFWUM_CMD_ID_START_FIRMWARE_UPDATE = 9,
+ KFWUM_CMD_ID_START_FIRMWARE_IMAGE = 0x0a,
+ KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE = 0x0b,
+ KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE = 0x0c,
+ KFWUM_CMD_ID_READ_FIRMWARE_IMAGE = 0x0d,
+ KFWUM_CMD_ID_MANUAL_ROLLBACK = 0x0e,
+ KFWUM_CMD_ID_GET_TRACE_LOG = 0x0f,
+ KFWUM_CMD_ID_STD_MAX_CMD,
+ KFWUM_CMD_ID_EXTENDED_CMD = 0xC0
+} tKFWUM_CmdId;
+
+int
+ipmi_fwum_info(struct ipmi_intf *intf)
+{
+ tKFWUM_BoardInfo b_info;
+ int rc = 0;
+ unsigned char not_used;
+ if (verbose) {
+ printf("Getting Kontron FWUM Info\n");
+ }
+ if (KfwumGetDeviceInfo(intf, 1, &b_info) != 0) {
+ rc = (-1);
+ }
+ if (KfwumGetInfo(intf, 1, &not_used) != 0) {
+ rc = (-1);
+ }
+ return rc;
+}
+
+int
+ipmi_fwum_status(struct ipmi_intf *intf)
+{
+ if (verbose) {
+ printf("Getting Kontron FWUM Status\n");
+ }
+ if (KfwumGetStatus(intf) != 0) {
+ return (-1);
+ }
+ return 0;
+}
+
+/* ipmi_fwum_fwupgrade - function implements download/upload of the firmware
+ * data received as parameters
+ *
+ * @file: fw file
+ * @action: 0 = download, 1 = upload/start upload
+ *
+ * returns 0 on success, otherwise (-1)
+ */
+int
+ipmi_fwum_fwupgrade(struct ipmi_intf *intf, char *file, int action)
+{
+ tKFWUM_BoardInfo b_info;
+ tKFWUM_InFirmwareInfo fw_info = { 0 };
+ unsigned short padding;
+ unsigned long fsize = 0;
+ unsigned char not_used;
+ if (file == NULL) {
+ lprintf(LOG_ERR, "No file given.");
+ return (-1);
+ }
+ if (KfwumGetFileSize(file, &fsize) != 0) {
+ return (-1);
+ }
+ if (KfwumSetupBuffersFromFile(file, fsize) != 0) {
+ return (-1);
+ }
+ padding = KfwumCalculateChecksumPadding(firmBuf, fsize);
+ if (KfwumGetInfoFromFirmware(firmBuf, fsize, &fw_info) != 0) {
+ return (-1);
+ }
+ if (KfwumGetDeviceInfo(intf, 0, &b_info) != 0) {
+ return (-1);
+ }
+ if (ipmi_kfwum_checkfwcompat(b_info, fw_info) != 0) {
+ return (-1);
+ }
+ KfwumGetInfo(intf, 0, &not_used);
+ printf_kfwum_info(b_info, fw_info);
+ if (KfwumStartFirmwareImage(intf, fsize, padding) != 0) {
+ return (-1);
+ }
+ if (KfwumUploadFirmware(intf, firmBuf, fsize) != 0) {
+ return (-1);
+ }
+ if (KfwumFinishFirmwareImage(intf, fw_info) != 0) {
+ return (-1);
+ }
+ if (KfwumGetStatus(intf) != 0) {
+ return (-1);
+ }
+ if (action != 0) {
+ if (KfwumStartFirmwareUpgrade(intf) != 0) {
+ return (-1);
+ }
+ }
+ return 0;
+}
+
+/* KfwumGetFileSize - gets the file size
+ *
+ * @pFileName : filename ptr
+ * @pFileSize : output ptr for filesize
+ *
+ * returns 0 on success, otherwise (-1)
+ */
+int
+KfwumGetFileSize(const char *pFileName, unsigned long *pFileSize)
+{
+ FILE *pFileHandle = NULL;
+ pFileHandle = fopen(pFileName, "rb");
+ if (pFileHandle == NULL) {
+ return (-1);
+ }
+ if (fseek(pFileHandle, 0L , SEEK_END) == 0) {
+ *pFileSize = ftell(pFileHandle);
+ }
+ fclose(pFileHandle);
+ if (*pFileSize != 0) {
+ return 0;
+ }
+ return (-1);
+}
+
+/* KfwumSetupBuffersFromFile - small buffers are used to store the file data
+ *
+ * @pFileName : filename ptr
+ * unsigned long : filesize
+ *
+ * returns 0 on success, otherwise (-1)
+ */
+int
+KfwumSetupBuffersFromFile(const char *pFileName, unsigned long fileSize)
+{
+ int rc = (-1);
+ FILE *pFileHandle = NULL;
+ int count;
+ int modulus;
+ int qty = 0;
+
+ pFileHandle = fopen(pFileName, "rb");
+ if (pFileHandle == NULL) {
+ lprintf(LOG_ERR, "Failed to open '%s' for reading.",
+ pFileName);
+ return (-1);
+ }
+ count = fileSize / MAX_BUFFER_SIZE;
+ modulus = fileSize % MAX_BUFFER_SIZE;
+
+ rewind(pFileHandle);
+ for (qty = 0; qty < count; qty++) {
+ KfwumShowProgress("Reading Firmware from File",
+ qty, count);
+ if (fread(&firmBuf[qty * MAX_BUFFER_SIZE], 1,
+ MAX_BUFFER_SIZE,
+ pFileHandle) == MAX_BUFFER_SIZE) {
+ rc = 0;
+ }
+ }
+ if (modulus) {
+ if (fread(&firmBuf[qty * MAX_BUFFER_SIZE], 1,
+ modulus, pFileHandle) == modulus) {
+ rc = 0;
+ }
+ }
+ if (rc == 0) {
+ KfwumShowProgress("Reading Firmware from File", 100, 100);
+ }
+ fclose(pFileHandle);
+ return rc;
+}
+
+/* KfwumShowProgress - helper routine to display progress bar
+ *
+ * Converts current/total in percent
+ *
+ * *task : string identifying current operation
+ * current: progress
+ * total : limit
+ */
+void
+KfwumShowProgress(const char *task, unsigned long current, unsigned long total)
+{
+# define PROG_LENGTH 42
+ static unsigned long staticProgress=0xffffffff;
+ unsigned char spaces[PROG_LENGTH + 1];
+ unsigned short hash;
+ float percent = ((float)current / total);
+ unsigned long progress = 100 * (percent);
+
+ if (staticProgress == progress) {
+ /* We displayed the same last time.. so don't do it */
+ return;
+ }
+ staticProgress = progress;
+ printf("%-25s : ", task); /* total 20 bytes */
+ hash = (percent * PROG_LENGTH);
+ memset(spaces, '#', hash);
+ spaces[hash] = '\0';
+
+ printf("%s", spaces);
+ memset(spaces, ' ', (PROG_LENGTH - hash));
+ spaces[(PROG_LENGTH - hash)] = '\0';
+ printf("%s", spaces );
+
+ printf(" %3ld %%\r", progress); /* total 7 bytes */
+ if (progress == 100) {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+/* KfwumCalculateChecksumPadding - TBD
+ */
+unsigned short
+KfwumCalculateChecksumPadding(unsigned char *pBuffer, unsigned long totalSize)
+{
+ unsigned short sumOfBytes = 0;
+ unsigned short padding;
+ unsigned long counter;
+ for (counter = 0; counter < totalSize; counter ++) {
+ sumOfBytes += pBuffer[counter];
+ }
+ padding = 0 - sumOfBytes;
+ return padding;
+}
+
+/* KfwumGetInfo - Get Firmware Update Manager (FWUM) information
+ *
+ * *intf : IPMI interface
+ * output : when set to non zero, queried information is displayed
+ * pNumBank: output ptr for number of banks
+ *
+ * returns 0 on success, otherwise (-1)
+ */
+int
+KfwumGetInfo(struct ipmi_intf *intf, unsigned char output,
+ unsigned char *pNumBank)
+{
+ int rc = 0;
+ static struct KfwumGetInfoResp *pGetInfo;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_INFO;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp) {
+ lprintf(LOG_ERR, "Error in FWUM Firmware Get Info Command.");
+ return (-1);
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "FWUM Firmware Get Info returned %x",
+ rsp->ccode);
+ return (-1);
+ }
+
+ pGetInfo = (struct KfwumGetInfoResp *)rsp->data;
+ if (output) {
+ printf("\nFWUM info\n");
+ printf("=========\n");
+ printf("Protocol Revision : %02Xh\n",
+ pGetInfo->protocolRevision);
+ printf("Controller Device Id : %02Xh\n",
+ pGetInfo->controllerDeviceId);
+ printf("Firmware Revision : %u.%u%u",
+ pGetInfo->firmRev1, pGetInfo->firmRev2 >> 4,
+ pGetInfo->firmRev2 & 0x0f);
+ if (pGetInfo->byte.mode != 0) {
+ printf(" - DEBUG BUILD\n");
+ } else {
+ printf("\n");
+ }
+ printf("Number Of Memory Bank : %u\n", pGetInfo->numBank);
+ }
+ *pNumBank = pGetInfo->numBank;
+ /* Determine wich type of download to use: */
+ /* Old FWUM or Old IPMC fw (data_len < 7)
+ * --> Address with small buffer size
+ */
+ if ((pGetInfo->protocolRevision) <= 0x05 || (rsp->data_len < 7 )) {
+ save_fw_nfo.downloadType = KFWUM_DOWNLOAD_TYPE_ADDRESS;
+ save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER;
+ save_fw_nfo.overheadSize = KFWUM_OLD_CMD_OVERHEAD;
+ if (verbose) {
+ printf("Protocol Revision :");
+ printf(" <= 5 detected, adjusting buffers\n");
+ }
+ } else {
+ /* Both fw are using the new protocol */
+ save_fw_nfo.downloadType = KFWUM_DOWNLOAD_TYPE_SEQUENCE;
+ save_fw_nfo.overheadSize = KFWUM_NEW_CMD_OVERHEAD;
+ /* Buffer size depending on access type (Local or remote) */
+ /* Look if we run remote or locally */
+ if (verbose) {
+ printf("Protocol Revision :");
+ printf(" > 5 optimizing buffers\n");
+ }
+ if (strstr(intf->name,"lan") != NULL) {
+ /* also covers lanplus */
+ save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER;
+ if (verbose) {
+ printf("IOL payload size : %d\n",
+ save_fw_nfo.bufferSize);
+ }
+ } else if ((strstr(intf->name,"open")!= NULL)
+ && intf->target_addr != IPMI_BMC_SLAVE_ADDR
+ && (intf->target_addr != intf->my_addr)) {
+ save_fw_nfo.bufferSize = KFWUM_SMALL_BUFFER;
+ if (verbose) {
+ printf("IPMB payload size : %d\n",
+ save_fw_nfo.bufferSize);
+ }
+ } else {
+ save_fw_nfo.bufferSize = KFWUM_BIG_BUFFER;
+ if (verbose) {
+ printf("SMI payload size : %d\n",
+ save_fw_nfo.bufferSize);
+ }
+ }
+ }
+ return rc;
+}
+
+/* KfwumGetDeviceInfo - Get IPMC/Board information
+ *
+ * *intf: IPMI interface
+ * output: when set to non zero, queried information is displayed
+ * tKFWUM_BoardInfo: output ptr for IPMC/Board information
+ *
+ * returns 0 on success, otherwise (-1)
+ */
+int
+KfwumGetDeviceInfo(struct ipmi_intf *intf, unsigned char output,
+ tKFWUM_BoardInfo *pBoardInfo)
+{
+ struct ipm_devid_rsp *pGetDevId;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ /* Send Get Device Id */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in Get Device Id Command");
+ return (-1);
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Get Device Id returned %x",
+ rsp->ccode);
+ return (-1);
+ }
+ pGetDevId = (struct ipm_devid_rsp *)rsp->data;
+ pBoardInfo->iana = IPM_DEV_MANUFACTURER_ID(pGetDevId->manufacturer_id);
+ pBoardInfo->boardId = buf2short(pGetDevId->product_id);
+ if (output) {
+ printf("\nIPMC Info\n");
+ printf("=========\n");
+ printf("Manufacturer Id : %u\n",
+ pBoardInfo->iana);
+ printf("Board Id : %u\n",
+ pBoardInfo->boardId);
+ printf("Firmware Revision : %u.%u%u",
+ pGetDevId->fw_rev1, pGetDevId->fw_rev2 >> 4,
+ pGetDevId->fw_rev2 & 0x0f);
+ if (((pBoardInfo->iana == IPMI_OEM_KONTRON)
+ && (pBoardInfo->boardId = KFWUM_BOARD_KONTRON_5002))) {
+ printf(" SDR %u", pGetDevId->aux_fw_rev[0]);
+ }
+ printf("\n");
+ }
+ return 0;
+}
+
+/* KfwumGetStatus - Get (and prints) FWUM banks information
+ *
+ * *intf : IPMI interface
+ *
+ * returns 0 on success, otherwise (-1)
+ */
+int
+KfwumGetStatus(struct ipmi_intf * intf)
+{
+ int rc = 0;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct KfwumGetStatusResp *pGetStatus;
+ unsigned char numBank;
+ unsigned char counter;
+ unsigned long firmLength;
+ if (verbose) {
+ printf(" Getting Status!\n");
+ }
+ /* Retreive the number of bank */
+ rc = KfwumGetInfo(intf, 0, &numBank);
+ for(counter = 0;
+ (counter < numBank) && (rc == 0);
+ counter ++) {
+ /* Retreive the status of each bank */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_STATUS;
+ req.msg.data = &counter;
+ req.msg.data_len = 1;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Error in FWUM Firmware Get Status Command.");
+ rc = (-1);
+ break;
+ } else if (rsp->ccode) {
+ lprintf(LOG_ERR,
+ "FWUM Firmware Get Status returned %x",
+ rsp->ccode);
+ rc = (-1);
+ break;
+ }
+ pGetStatus = (struct KfwumGetStatusResp *) rsp->data;
+ printf("\nBank State %d : %s\n",
+ counter,
+ val2str(pGetStatus->bankState, bankStateValS));
+ if (!pGetStatus->bankState) {
+ continue;
+ }
+ firmLength = pGetStatus->firmLengthMSB;
+ firmLength = firmLength << 8;
+ firmLength |= pGetStatus->firmLengthMid;
+ firmLength = firmLength << 8;
+ firmLength |= pGetStatus->firmLengthLSB;
+ printf("Firmware Length : %ld bytes\n",
+ firmLength);
+ printf("Firmware Revision : %u.%u%u SDR %u\n",
+ pGetStatus->firmRev1,
+ pGetStatus->firmRev2 >> 4,
+ pGetStatus->firmRev2 & 0x0f,
+ pGetStatus->firmRev3);
+ }
+ printf("\n");
+ return rc;
+}
+
+/* KfwumManualRollback - Ask IPMC to rollback to previous version
+ *
+ * *intf : IPMI interface
+ *
+ * returns 0 on success
+ * returns (-1) on error
+ */
+int
+KfwumManualRollback(struct ipmi_intf *intf)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct KfwumManualRollbackReq thisReq;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_MANUAL_ROLLBACK;
+ thisReq.type = 0; /* Wait BMC shutdown */
+ req.msg.data = (unsigned char *)&thisReq;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in FWUM Manual Rollback Command.");
+ return (-1);
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR,
+ "Error in FWUM Manual Rollback Command returned %x",
+ rsp->ccode);
+ return (-1);
+ }
+ printf("FWUM Starting Manual Rollback \n");
+ return 0;
+}
+
+int
+KfwumStartFirmwareImage(struct ipmi_intf *intf, unsigned long length,
+ unsigned short padding)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct KfwumStartFirmwareDownloadResp *pResp;
+ struct KfwumStartFirmwareDownloadReq thisReq;
+
+ thisReq.lengthLSB = length & 0x000000ff;
+ thisReq.lengthMid = (length >> 8) & 0x000000ff;
+ thisReq.lengthMSB = (length >> 16) & 0x000000ff;
+ thisReq.paddingLSB = padding & 0x00ff;
+ thisReq.paddingMSB = (padding>> 8) & 0x00ff;
+ thisReq.useSequence = 0x01;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_IMAGE;
+ req.msg.data = (unsigned char *) &thisReq;
+ /* Look for download type */
+ if (save_fw_nfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS) {
+ req.msg.data_len = 5;
+ } else {
+ req.msg.data_len = 6;
+ }
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Error in FWUM Firmware Start Firmware Image Download Command.");
+ return (-1);
+ } else if (rsp->ccode) {
+ lprintf(LOG_ERR,
+ "FWUM Firmware Start Firmware Image Download returned %x",
+ rsp->ccode);
+ return (-1);
+ }
+ pResp = (struct KfwumStartFirmwareDownloadResp *)rsp->data;
+ printf("Bank holding new firmware : %d\n", pResp->bank);
+ sleep(5);
+ return 0;
+}
+
+int
+KfwumSaveFirmwareImage(struct ipmi_intf *intf, unsigned char sequenceNumber,
+ unsigned long address, unsigned char *pFirmBuf,
+ unsigned char *pInBufLength)
+{
+ int rc = 0;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct KfwumSaveFirmwareAddressReq addr_req;
+ struct KfwumSaveFirmwareSequenceReq seq_req;
+ int retry = 0;
+ int no_rsp = 0;
+ do {
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE;
+ if (save_fw_nfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS) {
+ addr_req.addressLSB = address & 0x000000ff;
+ addr_req.addressMid = (address >> 8) & 0x000000ff;
+ addr_req.addressMSB = (address >> 16) & 0x000000ff;
+ addr_req.numBytes = *pInBufLength;
+ memcpy(addr_req.txBuf, pFirmBuf, *pInBufLength);
+ req.msg.data = (unsigned char *)&addr_req;
+ req.msg.data_len = *pInBufLength + 4;
+ } else {
+ seq_req.sequenceNumber = sequenceNumber;
+ memcpy(seq_req.txBuf, pFirmBuf, *pInBufLength);
+ req.msg.data = (unsigned char *)&seq_req;
+ req.msg.data_len = *pInBufLength + sizeof(unsigned char);
+ /* + 1 => sequenceNumber*/
+ }
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Error in FWUM Firmware Save Firmware Image Download Command.");
+ /* We don't receive "C7" on errors with IOL,
+ * instead we receive nothing
+ */
+ if (strstr(intf->name, "lan") != NULL) {
+ no_rsp++;
+ if (no_rsp < FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT) {
+ *pInBufLength -= 1;
+ continue;
+ }
+ lprintf(LOG_ERR,
+ "Error, too many commands without response.");
+ *pInBufLength = 0;
+ break;
+ } /* For other interface keep trying */
+ } else if (rsp->ccode != 0) {
+ if (rsp->ccode == 0xc0) {
+ sleep(1);
+ } else if ((rsp->ccode == 0xc7)
+ || ((rsp->ccode == 0xc3)
+ && (sequenceNumber == 0))) {
+ *pInBufLength -= 1;
+ retry = 1;
+ } else if (rsp->ccode == 0x82) {
+ /* Double sent, continue */
+ rc = 0;
+ break;
+ } else if (rsp->ccode == 0x83) {
+ if (retry == 0) {
+ retry = 1;
+ continue;
+ }
+ rc = (-1);
+ break;
+ } else if (rsp->ccode == 0xcf) {
+ /* Ok if receive duplicated request */
+ retry = 1;
+ } else if (rsp->ccode == 0xc3) {
+ if (retry == 0) {
+ retry = 1;
+ continue;
+ }
+ rc = (-1);
+ break;
+ } else {
+ lprintf(LOG_ERR,
+ "FWUM Firmware Save Firmware Image Download returned %x",
+ rsp->ccode);
+ rc = (-1);
+ break;
+ }
+ } else {
+ break;
+ }
+ } while (1);
+ return rc;
+}
+
+int
+KfwumFinishFirmwareImage(struct ipmi_intf *intf, tKFWUM_InFirmwareInfo firmInfo)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct KfwumFinishFirmwareDownloadReq thisReq;
+
+ thisReq.versionMaj = firmInfo.versMajor;
+ thisReq.versionMinSub = ((firmInfo.versMinor <<4)
+ | firmInfo.versSubMinor);
+ thisReq.versionSdr = firmInfo.sdrRev;
+ thisReq.reserved = 0;
+ /* Byte 4 reserved, write 0 */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE;
+ req.msg.data = (unsigned char *)&thisReq;
+ req.msg.data_len = 4;
+ /* Infinite loop if BMC doesn't reply or replies 0xc0 every time. */
+ do {
+ rsp = intf->sendrecv(intf, &req);
+ } while (rsp == NULL || rsp->ccode == 0xc0);
+ if (!rsp) {
+ lprintf(LOG_ERR,
+ "Error in FWUM Firmware Finish Firmware Image Download Command.");
+ return (-1);
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR,
+ "FWUM Firmware Finish Firmware Image Download returned %x",
+ rsp->ccode);
+ return (-1);
+ }
+ return 0;
+}
+
+int
+KfwumUploadFirmware(struct ipmi_intf *intf, unsigned char *pBuffer,
+ unsigned long totalSize)
+{
+ int rc = (-1);
+ unsigned long address = 0x0;
+ unsigned char writeSize;
+ unsigned char oldWriteSize;
+ unsigned long lastAddress = 0;
+ unsigned char sequenceNumber = 0;
+ unsigned char retry = FWUM_MAX_UPLOAD_RETRY;
+ unsigned char isLengthValid = 1;
+ do {
+ writeSize = save_fw_nfo.bufferSize - save_fw_nfo.overheadSize;
+ /* Reach the end */
+ if (address + writeSize > totalSize) {
+ writeSize = (totalSize - address);
+ } else if (((address % KFWUM_PAGE_SIZE)
+ + writeSize) > KFWUM_PAGE_SIZE) {
+ /* Reach boundary end */
+ writeSize = (KFWUM_PAGE_SIZE - (address % KFWUM_PAGE_SIZE));
+ }
+ oldWriteSize = writeSize;
+ rc = KfwumSaveFirmwareImage(intf, sequenceNumber,
+ address, &pBuffer[address], &writeSize);
+ if ((rc != 0) && (retry-- != 0)) {
+ address = lastAddress;
+ rc = 0;
+ } else if ( writeSize == 0) {
+ rc = (-1);
+ } else {
+ if (writeSize != oldWriteSize) {
+ printf("Adjusting length to %d bytes \n",
+ writeSize);
+ save_fw_nfo.bufferSize -= (oldWriteSize - writeSize);
+ }
+ retry = FWUM_MAX_UPLOAD_RETRY;
+ lastAddress = address;
+ address+= writeSize;
+ }
+ if (rc == 0) {
+ if ((address % 1024) == 0) {
+ KfwumShowProgress("Writting Firmware in Flash",
+ address, totalSize);
+ }
+ sequenceNumber++;
+ }
+ } while ((rc == 0) && (address < totalSize));
+ if (rc == 0) {
+ KfwumShowProgress("Writting Firmware in Flash",
+ 100, 100);
+ }
+ return rc;
+}
+
+int
+KfwumStartFirmwareUpgrade(struct ipmi_intf *intf)
+{
+ int rc = 0;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ /* Upgrade type, wait BMC shutdown */
+ unsigned char upgType = 0 ;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_UPDATE;
+ req.msg.data = (unsigned char *) &upgType;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Error in FWUM Firmware Start Firmware Upgrade Command");
+ rc = (-1);
+ } else if (rsp->ccode) {
+ if (rsp->ccode == 0xd5) {
+ lprintf(LOG_ERR,
+ "No firmware available for upgrade. Download Firmware first.");
+ } else {
+ lprintf(LOG_ERR,
+ "FWUM Firmware Start Firmware Upgrade returned %x",
+ rsp->ccode);
+ }
+ rc = (-1);
+ }
+ return rc;
+}
+
+int
+KfwumGetTraceLog(struct ipmi_intf *intf)
+{
+ int rc = 0;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ unsigned char chunkIdx;
+ unsigned char cmdIdx;
+ if (verbose) {
+ printf(" Getting Trace Log!\n");
+ }
+ for (chunkIdx = 0;
+ (chunkIdx < TRACE_LOG_CHUNK_COUNT)
+ && (rc == 0);
+ chunkIdx++) {
+ /* Retreive each log chunk and print it */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_FIRMWARE;
+ req.msg.cmd = KFWUM_CMD_ID_GET_TRACE_LOG;
+ req.msg.data = &chunkIdx;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Error in FWUM Firmware Get Trace Log Command");
+ rc = (-1);
+ break;
+ } else if (rsp->ccode) {
+ lprintf(LOG_ERR,
+ "FWUM Firmware Get Trace Log returned %x",
+ rsp->ccode);
+ rc = (-1);
+ break;
+ }
+ for (cmdIdx=0; cmdIdx < TRACE_LOG_CHUNK_SIZE; cmdIdx++) {
+ /* Don't diplay commands with an invalid state */
+ if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0)
+ && (rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD)) {
+ printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n",
+ CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx]],
+ CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]],
+ rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]);
+ } else if ((rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1] != 0)
+ && (rsp->data[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD)) {
+ printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n",
+ EXT_CMD_ID_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD],
+ CMD_STATE_STRING[rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 1]],
+ rsp->data[TRACE_LOG_ATT_COUNT * cmdIdx + 2]);
+ }
+ }
+ }
+ printf("\n");
+ return rc;
+}
+
+int
+KfwumGetInfoFromFirmware(unsigned char *pBuf, unsigned long bufSize,
+ tKFWUM_InFirmwareInfo *pInfo)
+{
+ unsigned long offset = 0;
+ if (bufSize < (IN_FIRMWARE_INFO_OFFSET_LOCATION + IN_FIRMWARE_INFO_SIZE)) {
+ return (-1);
+ }
+ offset = IN_FIRMWARE_INFO_OFFSET_LOCATION;
+
+ /* Now, fill the structure with read informations */
+ pInfo->checksum = (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + 0 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM ) << 8;
+
+ pInfo->checksum|= (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + 1 + IN_FIRMWARE_INFO_OFFSET_CHECKSUM);
+
+ pInfo->sumToRemoveFromChecksum = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM);
+
+ pInfo->sumToRemoveFromChecksum+= KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_CHECKSUM + 1);
+
+ pInfo->fileSize = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 0) << 24;
+
+ pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 1) << 16;
+
+ pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 2) << 8;
+
+ pInfo->fileSize|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_FILE_SIZE + 3);
+
+ pInfo->boardId = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 0) << 8;
+
+ pInfo->boardId|= KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_BOARD_ID + 1);
+
+ pInfo->deviceId = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_DEVICE_ID);
+
+ pInfo->tableVers = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION);
+
+ pInfo->implRev = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV);
+
+ pInfo->versMajor = (KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset
+ + IN_FIRMWARE_INFO_OFFSET_VER_MAJOROR)) & 0x0f;
+
+ pInfo->versMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset
+ + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB) >> 4) & 0x0f;
+
+ pInfo->versSubMinor = (KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_VER_MINORSUB)) & 0x0f;
+
+ pInfo->sdrRev = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_SDR_REV);
+
+ pInfo->iana = KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_IANA2) << 16;
+
+ pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_IANA1) << 8;
+
+ pInfo->iana|= (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf,
+ offset + IN_FIRMWARE_INFO_OFFSET_IANA0);
+
+ KfwumFixTableVersionForOldFirmware(pInfo);
+ return 0;
+}
+
+void
+KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo)
+{
+ switch(pInfo->boardId) {
+ case KFWUM_BOARD_KONTRON_UNKNOWN:
+ pInfo->tableVers = 0xff;
+ break;
+ default:
+ /* pInfo->tableVers is already set for
+ * the right version
+ */
+ break;
+ }
+}
+
+/* ipmi_kfwum_checkfwcompat - check whether firmware we're about to upload is
+ * compatible with board.
+ *
+ * @boardInfo:
+ * @firmInfo:
+ *
+ * returns 0 if compatible, otherwise (-1)
+ */
+int
+ipmi_kfwum_checkfwcompat(tKFWUM_BoardInfo boardInfo,
+ tKFWUM_InFirmwareInfo firmInfo)
+{
+ int compatible = 0;
+ if (boardInfo.iana != firmInfo.iana) {
+ lprintf(LOG_ERR,
+ "Board IANA does not match firmware IANA.");
+ compatible = (-1);
+ }
+ if (boardInfo.boardId != firmInfo.boardId) {
+ lprintf(LOG_ERR,
+ "Board IANA does not match firmware IANA.");
+ compatible = (-1);
+ }
+ if (compatible != 0) {
+ lprintf(LOG_ERR,
+ "Firmware invalid for target board. Download of upgrade aborted.");
+ }
+ return compatible;
+}
+
+void
+printf_kfwum_info(tKFWUM_BoardInfo boardInfo, tKFWUM_InFirmwareInfo firmInfo)
+{
+ printf(
+"Target Board Id : %u\n", boardInfo.boardId);
+ printf(
+"Target IANA number : %u\n", boardInfo.iana);
+ printf(
+"File Size : %lu bytes\n", firmInfo.fileSize);
+ printf(
+"Firmware Version : %d.%d%d SDR %d\n", firmInfo.versMajor,
+firmInfo.versMinor, firmInfo.versSubMinor, firmInfo.sdrRev);
+}
diff --git a/lib/ipmi_gendev.c b/lib/ipmi_gendev.c
new file mode 100644
index 0000000..7a4cf08
--- /dev/null
+++ b/lib/ipmi_gendev.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) 2003 Kontron Canada, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_gendev.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_entity.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_raw.h>
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+extern int verbose;
+
+
+#define GENDEV_RETRY_COUNT 5
+#define GENDEV_MAX_SIZE 16
+
+typedef struct gendev_eeprom_info
+{
+ uint32_t size;
+ uint16_t page_size;
+ uint8_t address_span;
+ uint8_t address_length;
+}t_gendev_eeprom_info;
+
+
+static int
+ipmi_gendev_get_eeprom_size(
+ struct ipmi_intf *intf,
+ struct sdr_record_generic_locator *dev,
+ t_gendev_eeprom_info *info
+ )
+{
+ int eeprom_size = 0;
+ /*
+ lprintf(LOG_ERR, "Gen Device : %s", dev->id_string);
+ lprintf(LOG_ERR, "Access Addr: %x", dev->dev_access_addr);
+ lprintf(LOG_ERR, "Slave Addr : %x", dev->dev_slave_addr);
+ lprintf(LOG_ERR, "Channel Num: %x", dev->channel_num);
+ lprintf(LOG_ERR, "Lun : %x", dev->lun);
+ lprintf(LOG_ERR, "Bus : %x", dev->bus);
+ lprintf(LOG_ERR, "Addr Span : %x", dev->addr_span);
+ lprintf(LOG_ERR, "DevType : %x", dev->dev_type);
+ lprintf(LOG_ERR, "DevType Mod: %x", dev->dev_type_modifier);
+ */
+ if( info != NULL)
+ {
+ switch(dev->dev_type)
+ {
+ case 0x08: // 24C01
+ info->size = 128;
+ info->page_size = 8;
+ info->address_span = dev->addr_span;
+ info->address_length = 1;
+ break;
+ case 0x09: // 24C02
+ info->size = 256;
+ info->page_size = 8;
+ info->address_span = dev->addr_span;
+ info->address_length = 1;
+ break;
+ case 0x0A: // 24C04
+ info->size = 512;
+ info->page_size = 8;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0x0B: // 24C08
+ info->size = 1024;
+ info->page_size = 8;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0x0C: // 24C16
+ info->size = 2048;
+ info->page_size = 256;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0x0D: // 24C17
+ info->size = 2048;
+ info->page_size = 256;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0x0E: // 24C32
+ info->size = 4096;
+ info->page_size = 8;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0x0F: // 24C64
+ info->size = 8192;
+ info->page_size = 32;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0xC0: // Proposed OEM Code for 24C128
+ info->size = 16384;
+ info->page_size = 64;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0xC1: // Proposed OEM Code for 24C256
+ info->size = 32748;
+ info->page_size = 64;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0xC2: // Proposed OEM Code for 24C512
+ info->size = 65536;
+ info->page_size = 128;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ case 0xC3: // Proposed OEM Code for 24C1024
+ info->size = 131072;
+ info->page_size = 128;
+ info->address_span = dev->addr_span;
+ info->address_length = 2;
+ break;
+ /* Please reserved up to CFh for future update */
+ default: // Not a eeprom, return size = 0;
+ info->size = 0;
+ info->page_size = 0;
+ info->address_span = 0;
+ info->address_length = 0;
+ break;
+ }
+
+ eeprom_size = info->size;
+ }
+
+ return eeprom_size;
+}
+
+
+
+static int
+ipmi_gendev_read_file(
+ struct ipmi_intf *intf,
+ struct sdr_record_generic_locator *dev,
+ const char *ofile
+ )
+{
+ int rc = 0;
+ int eeprom_size;
+ t_gendev_eeprom_info eeprom_info;
+
+ eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info);
+
+ if(eeprom_size > 0)
+ {
+ FILE *fp;
+
+ /* now write to file */
+ fp = ipmi_open_file_write(ofile);
+
+ if(fp)
+ {
+ struct ipmi_rs *rsp;
+ int numWrite;
+ uint32_t counter;
+ uint8_t msize;
+ uint8_t channel = dev->channel_num;
+ uint8_t i2cbus = dev->bus;
+ uint8_t i2caddr = dev->dev_slave_addr;
+ uint8_t privatebus = 1;
+ uint32_t address_span_size;
+ uint8_t percentCompleted = 0;
+
+
+ /* Handle Address Span */
+ if( eeprom_info.address_span != 0)
+ {
+ address_span_size =
+ (eeprom_info.size / (eeprom_info.address_span+1));
+ }
+ else
+ {
+ address_span_size = eeprom_info.size;
+ }
+
+ /* Setup read/write size */
+ if( eeprom_info.page_size < GENDEV_MAX_SIZE)
+ {
+ msize = eeprom_info.page_size;
+ }
+ else
+ {
+ msize = GENDEV_MAX_SIZE;
+ // All eeprom with page higher than 32 is on the
+ // 16 bytes boundary
+ }
+
+ /* Setup i2c bus byte */
+ i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus;
+
+/*
+ lprintf(LOG_ERR, "Generic device: %s", dev->id_string);
+ lprintf(LOG_ERR, "I2C Chnl: %x", channel);
+ lprintf(LOG_ERR, "I2C Bus : %x", i2cbus);
+ lprintf(LOG_ERR, "I2C Addr: %x", i2caddr); */
+
+ for (
+ counter = 0;
+ (counter < (eeprom_info.size)) && (rc == 0);
+ counter+= msize
+ )
+ {
+ uint8_t retryCounter;
+
+ for(
+ retryCounter = 0;
+ retryCounter<GENDEV_RETRY_COUNT;
+ retryCounter ++
+ )
+ {
+ uint8_t wrByte[GENDEV_MAX_SIZE+2];
+
+ wrByte[0] = (uint8_t) (counter>>0);
+ if(eeprom_info.address_length > 1)
+ {
+ wrByte[1] = (uint8_t) (counter>>8);
+ }
+
+ i2caddr+= (((eeprom_info.size) % address_span_size) * 2);
+
+ rsp = ipmi_master_write_read(
+ intf,
+ i2cbus,
+ i2caddr,
+ (uint8_t *) wrByte,
+ eeprom_info.address_length,
+ msize
+ );
+
+ if (rsp != NULL)
+ {
+ retryCounter = GENDEV_RETRY_COUNT;
+ rc = 0;
+ }
+ else if(retryCounter < GENDEV_RETRY_COUNT)
+ {
+ retryCounter ++;
+ lprintf(LOG_ERR, "Retry");
+ sleep(1);
+ rc = -1;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
+ rc = -1;
+ }
+ }
+
+ if( rc == 0 )
+ {
+ static uint8_t previousCompleted = 101;
+ numWrite = fwrite(rsp->data, 1, msize, fp);
+ if (numWrite != msize)
+ {
+ lprintf(LOG_ERR, "Error writing file %s", ofile);
+ rc = -1;
+ break;
+ }
+
+ percentCompleted = ((counter * 100) / eeprom_info.size );
+
+ if(percentCompleted != previousCompleted)
+ {
+ printf("\r%i percent completed", percentCompleted);
+ previousCompleted = percentCompleted;
+ }
+
+
+ }
+ }
+ if(counter == (eeprom_info.size))
+ {
+ printf("\r%%100 percent completed\n");
+ }
+ else
+ {
+ printf("\rError: %i percent completed, read not completed \n", percentCompleted);
+ }
+
+ fclose(fp);
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "The selected generic device is not an eeprom");
+ }
+
+ return rc;
+}
+
+
+/* ipmi_gendev_write_file - Read raw SDR from binary file
+ *
+ * used for writing generic locator device Eeprom type
+ *
+ * @intf: ipmi interface
+ * @dev: generic device to read
+ * @ofile: output filename
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_gendev_write_file(
+ struct ipmi_intf *intf,
+ struct sdr_record_generic_locator *dev,
+ const char *ofile
+ )
+{
+ int rc = 0;
+ int eeprom_size;
+ t_gendev_eeprom_info eeprom_info;
+
+ eeprom_size = ipmi_gendev_get_eeprom_size(intf, dev, &eeprom_info);
+
+ if(eeprom_size > 0)
+ {
+ FILE *fp;
+ uint32_t fileLength = 0;
+
+ /* now write to file */
+ fp = ipmi_open_file_read(ofile);
+
+ if(fp)
+ {
+ /* Retreive file length, check if it's fits the Eeprom Size */
+ fseek(fp, 0 ,SEEK_END);
+ fileLength = ftell(fp);
+
+ lprintf(LOG_ERR, "File Size: %i", fileLength);
+ lprintf(LOG_ERR, "Eeprom Size: %i", eeprom_size);
+ if(fileLength != eeprom_size)
+ {
+ lprintf(LOG_ERR, "File size does not fit Eeprom Size");
+ fclose(fp);
+ fp = NULL;
+ }
+ else
+ {
+ fseek(fp, 0 ,SEEK_SET);
+ }
+ }
+
+ if(fp)
+ {
+ struct ipmi_rs *rsp;
+ int numRead;
+ uint32_t counter;
+ uint8_t msize;
+ uint8_t channel = dev->channel_num;
+ uint8_t i2cbus = dev->bus;
+ uint8_t i2caddr = dev->dev_slave_addr;
+ uint8_t privatebus = 1;
+ uint32_t address_span_size;
+ uint8_t percentCompleted = 0;
+
+
+ /* Handle Address Span */
+ if( eeprom_info.address_span != 0)
+ {
+ address_span_size =
+ (eeprom_info.size / (eeprom_info.address_span+1));
+ }
+ else
+ {
+ address_span_size = eeprom_info.size;
+ }
+
+ /* Setup read/write size */
+ if( eeprom_info.page_size < GENDEV_MAX_SIZE)
+ {
+ msize = eeprom_info.page_size;
+ }
+ else
+ {
+ msize = GENDEV_MAX_SIZE;
+ // All eeprom with page higher than 32 is on the
+ // 16 bytes boundary
+ }
+
+ /* Setup i2c bus byte */
+ i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | privatebus;
+
+/*
+ lprintf(LOG_ERR, "Generic device: %s", dev->id_string);
+ lprintf(LOG_ERR, "I2C Chnl: %x", channel);
+ lprintf(LOG_ERR, "I2C Bus : %x", i2cbus);
+ lprintf(LOG_ERR, "I2C Addr: %x", i2caddr); */
+
+ for (
+ counter = 0;
+ (counter < (eeprom_info.size)) && (rc == 0);
+ counter+= msize
+ )
+ {
+ uint8_t retryCounter;
+ uint8_t readByte[GENDEV_MAX_SIZE];
+
+ numRead = fread(readByte, 1, msize, fp);
+ if (numRead != msize)
+ {
+ lprintf(LOG_ERR, "Error reading file %s", ofile);
+ rc = -1;
+ break;
+ }
+
+
+
+ for(
+ retryCounter = 0;
+ retryCounter<GENDEV_RETRY_COUNT;
+ retryCounter ++
+ )
+ {
+ uint8_t wrByte[GENDEV_MAX_SIZE+2];
+ wrByte[0] = (uint8_t) (counter>>0);
+ if(eeprom_info.address_length > 1)
+ {
+ wrByte[1] = (uint8_t) (counter>>8);
+ }
+ memcpy(&wrByte[eeprom_info.address_length], readByte, msize);
+
+ i2caddr+= (((eeprom_info.size) % address_span_size) * 2);
+
+ rsp = ipmi_master_write_read(intf, i2cbus, i2caddr, (uint8_t *) wrByte, eeprom_info.address_length+msize, 0);
+ if (rsp != NULL)
+ {
+ retryCounter = GENDEV_RETRY_COUNT;
+ rc = 0;
+ }
+ else if(retryCounter < GENDEV_RETRY_COUNT)
+ {
+ retryCounter ++;
+ lprintf(LOG_ERR, "Retry");
+ sleep(1);
+ rc = -1;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
+ rc = -1;
+ }
+ }
+
+ if( rc == 0 )
+ {
+ static uint8_t previousCompleted = 101;
+ percentCompleted = ((counter * 100) / eeprom_info.size );
+
+ if(percentCompleted != previousCompleted)
+ {
+ printf("\r%i percent completed", percentCompleted);
+ previousCompleted = percentCompleted;
+ }
+
+ }
+ }
+ if(counter == (eeprom_info.size))
+ {
+ printf("\r%%100 percent completed\n");
+ }
+ else
+ {
+ printf("\rError: %i percent completed, read not completed \n", percentCompleted);
+ }
+
+ fclose(fp);
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "The selected generic device is not an eeprom");
+ }
+
+ return rc;
+}
+
+
+/* ipmi_gendev_main - top-level handler for generic device
+ *
+ * @intf: ipmi interface
+ * @argc: number of arguments
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_gendev_main(struct ipmi_intf *intf, int argc, char **argv)
+{
+ int rc = 0;
+
+ /* initialize random numbers used later */
+ srand(time(NULL));
+
+ lprintf(LOG_ERR, "Rx gendev command: %s", argv[0]);
+
+ if (
+ (argc == 0)
+ ||
+ (strncmp(argv[0], "help", 4) == 0)
+ )
+ {
+ lprintf(LOG_ERR,
+ "SDR Commands: list read write");
+ lprintf(LOG_ERR,
+ " list List All Generic Device Locators");
+ lprintf(LOG_ERR,
+ " read <sdr name> <file> Read to file eeprom specify by Generic Device Locators");
+ lprintf(LOG_ERR,
+ " write <sdr name> <file> Write from file eeprom specify by Generic Device Locators");
+ }
+ else if ( strncmp(argv[0], "list", 4) == 0)
+ {
+ rc = ipmi_sdr_print_sdr(intf,
+ SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
+ }
+ else if (strncmp(argv[0], "read", 4) == 0)
+ {
+ if (argc < 3)
+ lprintf(LOG_ERR, "usage: gendev read <gendev> <filename>");
+ else
+ {
+ struct sdr_record_list *sdr;
+
+ lprintf(LOG_ERR, "Gendev read sdr name : %s", argv[1]);
+
+ printf("Locating sensor record '%s'...\n", argv[1]);
+
+ /* lookup by sensor name */
+ sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]);
+ if (sdr == NULL)
+ {
+ lprintf(LOG_ERR, "Sensor data record not found!");
+ return -1;
+ }
+
+ if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ {
+ lprintf(LOG_ERR, "Target SDR is not a generic device locator");
+ return -1;
+ }
+
+ lprintf(LOG_ERR, "Gendev read file name: %s", argv[2]);
+ ipmi_gendev_read_file(intf, sdr->record.genloc, argv[2]);
+
+ }
+ }
+ else if (strncmp(argv[0], "write", 5) == 0)
+ {
+ if (argc < 3)
+ lprintf(LOG_ERR, "usage: gendev write <gendev> <filename>");
+ else
+ {
+ struct sdr_record_list *sdr;
+
+ lprintf(LOG_ERR, "Gendev write sdr name : %s", argv[1]);
+
+ printf("Locating sensor record '%s'...\n", argv[1]);
+
+ /* lookup by sensor name */
+ sdr = ipmi_sdr_find_sdr_byid(intf, argv[1]);
+ if (sdr == NULL)
+ {
+ lprintf(LOG_ERR, "Sensor data record not found!");
+ return -1;
+ }
+
+ if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ {
+ lprintf(LOG_ERR, "Target SDR is not a generic device locator");
+ return -1;
+ }
+
+ lprintf(LOG_ERR, "Gendev write file name: %s", argv[2]);
+ ipmi_gendev_write_file(intf, sdr->record.genloc, argv[2]);
+
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Invalid gendev command: %s", argv[0]);
+ rc = -1;
+ }
+
+ return rc;
+}
diff --git a/lib/ipmi_hpmfwupg.c b/lib/ipmi_hpmfwupg.c
new file mode 100644
index 0000000..69950b7
--- /dev/null
+++ b/lib/ipmi_hpmfwupg.c
@@ -0,0 +1,2624 @@
+/*
+ * Copyright (c) 2006 Kontron Canada, Inc. All Rights Reserved.
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_hpmfwupg.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/log.h>
+#include "../src/plugins/lan/md5.h"
+#include <stdio.h>
+#include <time.h>
+#include <sys/param.h>
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+extern int verbose;
+
+int HpmfwupgUpgrade(struct ipmi_intf *intf, char *imageFilename,
+ int activate, int, int);
+int HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx *pFwupgCtx);
+int HpmfwupgPreparationStage(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option);
+int HpmfwupgUpgradeStage(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option);
+int HpmfwupgActivationStage(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx);
+int HpmfwupgGetTargetUpgCapabilities(struct ipmi_intf *intf,
+ struct HpmfwupgGetTargetUpgCapabilitiesCtx *pCtx);
+int HpmfwupgGetComponentProperties(struct ipmi_intf *intf,
+ struct HpmfwupgGetComponentPropertiesCtx *pCtx);
+int HpmfwupgQuerySelftestResult(struct ipmi_intf *intf,
+ struct HpmfwupgQuerySelftestResultCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx);
+int HpmfwupgQueryRollbackStatus(struct ipmi_intf *intf,
+ struct HpmfwupgQueryRollbackStatusCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx);
+int HpmfwupgAbortUpgrade(struct ipmi_intf *intf,
+ struct HpmfwupgAbortUpgradeCtx *pCtx);
+int HpmfwupgInitiateUpgradeAction(struct ipmi_intf *intf,
+ struct HpmfwupgInitiateUpgradeActionCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx);
+int HpmfwupgUploadFirmwareBlock(struct ipmi_intf *intf,
+ struct HpmfwupgUploadFirmwareBlockCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int count,
+ unsigned int *pOffset, unsigned int *blockLen);
+int HpmfwupgFinishFirmwareUpload(struct ipmi_intf *intf,
+ struct HpmfwupgFinishFirmwareUploadCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option);
+int HpmfwupgActivateFirmware(struct ipmi_intf *intf,
+ struct HpmfwupgActivateFirmwareCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx);
+int HpmfwupgGetUpgradeStatus(struct ipmi_intf *intf,
+ struct HpmfwupgGetUpgradeStatusCtx *pCtxstruct,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int silent);
+int HpmfwupgManualFirmwareRollback(struct ipmi_intf *intf,
+ struct HpmfwupgManualFirmwareRollbackCtx *pCtx);
+void HpmfwupgPrintUsage(void);
+unsigned char HpmfwupgCalculateChecksum(unsigned char *pData,
+ unsigned int length);
+int HpmfwupgGetDeviceId(struct ipmi_intf *intf,
+ struct ipm_devid_rsp *pGetDevId);
+int HpmfwupgGetBufferFromFile(char *imageFilename,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx);
+int HpmfwupgWaitLongDurationCmd(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx);
+struct ipmi_rs *HpmfwupgSendCmd(struct ipmi_intf *intf,
+ struct ipmi_rq req, struct HpmfwupgUpgradeCtx* pFwupgCtx);
+
+
+int HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
+ struct HpmfwupgUpgradeCtx* pFwupgCtx,
+ unsigned char **pImagePtr,
+ struct ipmi_intf *intf,
+ int option,
+ int *pFlagColdReset);
+
+/* HpmGetuserInput - get input from user
+ *
+ * returns TRUE if its Yes or FALSE if its No
+ */
+int
+HpmGetUserInput(char *str)
+{
+ char userInput[2];
+ int ret;
+
+ printf("%s", str);
+ ret = scanf("%s", userInput);
+ if (!ret) {
+ return 1;
+ }
+ if (toupper(userInput[0]) == 'Y') {
+ return 1;
+ }
+ return 0;
+}
+
+/* HpmDisplayLine - display the line with the given character
+ */
+void
+HpmDisplayLine(char *s, int n)
+{
+ while (n--) {
+ printf ("%c", *s);
+ }
+ printf("\n");
+}
+
+/* HpmDisplayUpgradeHeader - display the Upgrade header information
+ */
+void
+HpmDisplayUpgradeHeader(void)
+{
+ printf("\n");
+ HpmDisplayLine("-", 79);
+ printf(
+"|ID | Name | Versions | %% |\n");
+ printf(
+"| | | Active | Backup | File | |\n");
+ printf(
+"|----|-------------|-----------------|-----------------|-----------------|----|\n");
+}
+
+/* HpmDisplayUpgrade - display the progress of the upgrade; prints the "."
+ * for every 5% of its completion.
+ */
+void
+HpmDisplayUpgrade(int skip, unsigned int totalSent,
+ unsigned int displayFWLength, time_t timeElapsed)
+{
+ int percent;
+ static int old_percent = -1;
+ if (skip) {
+ printf("Skip|\n");
+ return;
+ }
+ fflush(stdout);
+
+ percent = ((float)totalSent / displayFWLength) * 100;
+ if (percent != old_percent) {
+ if (old_percent != -1) {
+ printf("\b\b\b\b\b");
+ }
+ printf("%3d%%|", percent);
+ old_percent = percent;
+ }
+ if (totalSent == displayFWLength) {
+ /* Display the time taken to complete the upgrade */
+ printf(
+"\n| |Upload Time: %02ld:%02ld | Image Size: %7d bytes |\n",
+ timeElapsed / 60, timeElapsed % 60, totalSent);
+ old_percent = -1;
+ }
+}
+
+/* HpmDisplayVersionHeader - display the information about version header
+ */
+void
+HpmDisplayVersionHeader(int mode)
+{
+ if (mode & IMAGE_VER) {
+ HpmDisplayLine("-", 74);
+ printf(
+"|ID | Name | Versions |\n");
+ printf(
+"| | | Active | Backup | File |\n");
+ HpmDisplayLine("-", 74);
+ } else {
+ HpmDisplayLine("-",74 );
+ printf(
+"|ID | Name | Versions |\n");
+ printf(
+"| | | Active | Backup | Deferred |\n");
+ HpmDisplayLine("-", 74);
+ }
+}
+
+/* HpmDisplayVersion - display the version of the image and target
+ */
+void
+HpmDisplayVersion(int mode, VERSIONINFO *pVersion, int upgradable)
+{
+ /*
+ * If the cold reset is required then we can display * on it
+ * so that user is aware that he needs to do payload power
+ * cycle after upgrade
+ */
+ printf("|%c%c%2d|%-13s|",
+ pVersion->coldResetRequired ? '*' : ' ',
+ upgradable ? '^' : ' ',
+ pVersion->componentId, pVersion->descString);
+
+ if (mode & TARGET_VER) {
+ if ((pVersion->targetMajor == 0xFF
+ || (pVersion->targetMajor == 0x7F))
+ && pVersion->targetMinor == 0xFF) {
+ printf(" ---.-- -------- |");
+ } else {
+ printf(" %3d.%02x %02X%02X%02X%02X |",
+ pVersion->targetMajor,
+ pVersion->targetMinor,
+ pVersion->targetAux[0],
+ pVersion->targetAux[1],
+ pVersion->targetAux[2],
+ pVersion->targetAux[3]);
+ }
+ if (mode & ROLLBACK_VER) {
+ if ((pVersion->rollbackMajor == 0xFF
+ || (pVersion->rollbackMajor == 0x7F))
+ && pVersion->rollbackMinor == 0xFF) {
+ printf(" ---.-- -------- |");
+ } else {
+ printf(" %3d.%02x %02X%02X%02X%02X |",
+ pVersion->rollbackMajor,
+ pVersion->rollbackMinor,
+ pVersion->rollbackAux[0],
+ pVersion->rollbackAux[1],
+ pVersion->rollbackAux[2],
+ pVersion->rollbackAux[3]);
+ }
+ } else {
+ printf(" ---.-- -------- |");
+ }
+ }
+ if (mode & IMAGE_VER) {
+ if ((pVersion->imageMajor == 0xFF
+ || (pVersion->imageMajor == 0x7F))
+ && pVersion->imageMinor == 0xFF) {
+ printf(" ---.-- |");
+ } else {
+ printf(" %3d.%02x %02X%02X%02X%02X |",
+ pVersion->imageMajor,
+ pVersion->imageMinor,
+ pVersion->imageAux[0],
+ pVersion->imageAux[1],
+ pVersion->imageAux[2],
+ pVersion->imageAux[3]);
+ }
+ } else {
+ if ((pVersion->deferredMajor == 0xFF
+ || (pVersion->deferredMajor == 0x7F))
+ && pVersion->deferredMinor == 0xFF) {
+ printf(" ---.-- -------- |");
+ } else {
+ printf(" %3d.%02x %02X%02X%02X%02X |",
+ pVersion->deferredMajor,
+ pVersion->deferredMinor,
+ pVersion->deferredAux[0],
+ pVersion->deferredAux[1],
+ pVersion->deferredAux[2],
+ pVersion->deferredAux[3]);
+ }
+ }
+}
+
+/* HpmfwupgTargerCheck - get target information and displays it on the screen
+ */
+int
+HpmfwupgTargetCheck(struct ipmi_intf *intf, int option)
+{
+ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
+ int rc = HPMFWUPG_SUCCESS;
+ int componentId = 0;
+ int flagColdReset = FALSE;
+ struct ipm_devid_rsp devIdrsp;
+ struct HpmfwupgGetComponentPropertiesCtx getCompProp;
+ int mode = 0;
+ rc = HpmfwupgGetDeviceId(intf, &devIdrsp);
+ if (rc != HPMFWUPG_SUCCESS) {
+ lprintf(LOG_NOTICE,
+ "Verify whether the Target board is present \n");
+ return HPMFWUPG_ERROR;
+ }
+ rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd);
+ if (rc != HPMFWUPG_SUCCESS) {
+ /* That indicates the target is not responding to the command
+ * May be that there is no HPM support
+ */
+ lprintf(LOG_NOTICE,
+ "Board might not be supporting the HPM.1 Standards\n");
+ return rc;
+ }
+ if (option & VIEW_MODE) {
+ lprintf(LOG_NOTICE, "-------Target Information-------");
+ lprintf(LOG_NOTICE, "Device Id : 0x%x",
+ devIdrsp.device_id);
+ lprintf(LOG_NOTICE, "Device Revision : 0x%x",
+ devIdrsp.device_revision);
+ lprintf(LOG_NOTICE, "Product Id : 0x%04x",
+ buf2short(devIdrsp.product_id));
+ lprintf(LOG_NOTICE, "Manufacturer Id : 0x%04x (%s)\n\n",
+ buf2short(devIdrsp.manufacturer_id),
+ val2str(buf2short(devIdrsp.manufacturer_id),ipmi_oem_info));
+ HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER);
+ }
+ for (componentId = HPMFWUPG_COMPONENT_ID_0;
+ componentId < HPMFWUPG_COMPONENT_ID_MAX;
+ componentId++ ) {
+ /* If the component is supported */
+ if (((1 << componentId) & targetCapCmd.resp.componentsPresent.ComponentBits.byte)) {
+ memset((PVERSIONINFO)&gVersionInfo[componentId], 0x00, sizeof(VERSIONINFO));
+ getCompProp.req.componentId = componentId;
+ getCompProp.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES;
+ rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
+ if (rc != HPMFWUPG_SUCCESS) {
+ lprintf(LOG_NOTICE, "Get CompGenProp Failed for component Id %d\n",
+ componentId);
+ return rc;
+ }
+ gVersionInfo[componentId].rollbackSupported = getCompProp.resp.Response.
+ generalPropResp.GeneralCompProperties.bitfield.rollbackBackup;
+ gVersionInfo[componentId].coldResetRequired = getCompProp.resp.Response.
+ generalPropResp.GeneralCompProperties.bitfield.payloadColdReset;
+ getCompProp.req.selector = HPMFWUPG_COMP_DESCRIPTION_STRING;
+ rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
+ if (rc != HPMFWUPG_SUCCESS) {
+ lprintf(LOG_NOTICE,
+ "Get CompDescString Failed for component Id %d\n",
+ componentId);
+ return rc;
+ }
+ memcpy(gVersionInfo[componentId].descString,
+ getCompProp.resp.Response.descStringResp.descString,
+ HPMFWUPG_DESC_STRING_LENGTH);
+ gVersionInfo[componentId].descString[HPMFWUPG_DESC_STRING_LENGTH] = '\0';
+ getCompProp.req.selector = HPMFWUPG_COMP_CURRENT_VERSION;
+ rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
+ if (rc != HPMFWUPG_SUCCESS) {
+ lprintf(LOG_NOTICE,
+ "Get CompCurrentVersion Failed for component Id %d\n",
+ componentId);
+ return rc;
+ }
+ gVersionInfo[componentId].componentId = componentId;
+ gVersionInfo[componentId].targetMajor = getCompProp.resp.Response.
+ currentVersionResp.currentVersion[0];
+ gVersionInfo[componentId].targetMinor = getCompProp.resp.Response.
+ currentVersionResp.currentVersion[1];
+ gVersionInfo[componentId].targetAux[0] = getCompProp.resp.Response.
+ currentVersionResp.currentVersion[2];
+ gVersionInfo[componentId].targetAux[1] = getCompProp.resp.Response.
+ currentVersionResp.currentVersion[3];
+ gVersionInfo[componentId].targetAux[2] = getCompProp.resp.Response.
+ currentVersionResp.currentVersion[4];
+ gVersionInfo[componentId].targetAux[3] = getCompProp.resp.Response.
+ currentVersionResp.currentVersion[5];
+ mode = TARGET_VER;
+ if (gVersionInfo[componentId].rollbackSupported) {
+ getCompProp.req.selector = HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION;
+ rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
+ if (rc != HPMFWUPG_SUCCESS) {
+ lprintf(LOG_NOTICE,
+ "Get CompRollbackVersion Failed for component Id %d\n",
+ componentId);
+ } else {
+ gVersionInfo[componentId].rollbackMajor = getCompProp.resp
+ .Response.rollbackFwVersionResp.rollbackFwVersion[0];
+ gVersionInfo[componentId].rollbackMinor = getCompProp.resp
+ .Response.rollbackFwVersionResp.rollbackFwVersion[1];
+ gVersionInfo[componentId].rollbackAux[0] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[2];
+ gVersionInfo[componentId].rollbackAux[1] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[3];
+ gVersionInfo[componentId].rollbackAux[2] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[4];
+ gVersionInfo[componentId].rollbackAux[3] = getCompProp.resp.Response.rollbackFwVersionResp.rollbackFwVersion[5];
+ }
+ getCompProp.req.selector = HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION;
+ rc = HpmfwupgGetComponentProperties(intf, &getCompProp);
+ if (rc != HPMFWUPG_SUCCESS) {
+ lprintf(LOG_NOTICE,
+ "Get CompRollbackVersion Failed for component Id %d\n",
+ componentId);
+ } else {
+ gVersionInfo[componentId].deferredMajor = getCompProp.resp
+ .Response.deferredFwVersionResp.deferredFwVersion[0];
+ gVersionInfo[componentId].deferredMinor = getCompProp.resp
+ .Response.deferredFwVersionResp.deferredFwVersion[1];
+ gVersionInfo[componentId].deferredAux[0] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[2];
+ gVersionInfo[componentId].deferredAux[1] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[3];
+ gVersionInfo[componentId].deferredAux[2] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[4];
+ gVersionInfo[componentId].deferredAux[3] = getCompProp.resp.Response.deferredFwVersionResp.deferredFwVersion[5];
+ }
+ mode |= ROLLBACK_VER;
+ } else {
+ gVersionInfo[componentId].rollbackMajor = 0xff;
+ gVersionInfo[componentId].rollbackMinor = 0xff;
+ gVersionInfo[componentId].rollbackAux[0] = 0xff;
+ gVersionInfo[componentId].rollbackAux[1] = 0xff;
+ gVersionInfo[componentId].rollbackAux[2] = 0xff;
+ gVersionInfo[componentId].rollbackAux[3] = 0xff;
+ gVersionInfo[componentId].deferredMajor = 0xff;
+ gVersionInfo[componentId].deferredMinor = 0xff;
+ gVersionInfo[componentId].deferredAux[0] = 0xff;
+ gVersionInfo[componentId].deferredAux[1] = 0xff;
+ gVersionInfo[componentId].deferredAux[2] = 0xff;
+ gVersionInfo[componentId].deferredAux[3] = 0xff;
+ }
+ if (gVersionInfo[componentId].coldResetRequired) {
+ /*
+ * If any of the component indicates that the Payload Cold reset is required
+ * then set the flag
+ */
+ flagColdReset = TRUE;
+ }
+ if (option & VIEW_MODE) {
+ HpmDisplayVersion(mode,
+ &gVersionInfo[componentId],
+ 0);
+ printf("\n");
+ }
+ }
+ }
+ if (option & VIEW_MODE) {
+ HpmDisplayLine("-",74 );
+ fflush(stdout);
+ lprintf(LOG_NOTICE,
+ "(*) Component requires Payload Cold Reset");
+ printf("\n\n");
+ }
+ return HPMFWUPG_SUCCESS;
+}
+
+/* HpmfwupgUpgrade - perform the HPM.1 firmware upgrade procedure as defined
+ * the IPM Controller Firmware Upgrade Specification version 1.0
+ */
+int
+HpmfwupgUpgrade(struct ipmi_intf *intf, char *imageFilename, int activate,
+ int componentMask, int option)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct HpmfwupgUpgradeCtx fwupgCtx;
+ /* INITIALIZE UPGRADE CONTEXT */
+ memset(&fwupgCtx, 0, sizeof (fwupgCtx));
+ /* GET IMAGE BUFFER FROM FILE */
+ rc = HpmfwupgGetBufferFromFile(imageFilename, &fwupgCtx);
+ /* VALIDATE IMAGE INTEGRITY */
+ if (rc == HPMFWUPG_SUCCESS) {
+ printf("Validating firmware image integrity...");
+ fflush(stdout);
+ rc = HpmfwupgValidateImageIntegrity(&fwupgCtx);
+ if (rc == HPMFWUPG_SUCCESS) {
+ printf("OK\n");
+ fflush(stdout);
+ }
+ }
+ /* PREPARATION STAGE */
+ if (rc == HPMFWUPG_SUCCESS) {
+ printf("Performing preparation stage...");
+ fflush(stdout);
+ rc = HpmfwupgPreparationStage(intf, &fwupgCtx, option);
+ if (rc == HPMFWUPG_SUCCESS) {
+ printf("OK\n");
+ fflush(stdout);
+ }
+ }
+ /* UPGRADE STAGE */
+ if (rc == HPMFWUPG_SUCCESS) {
+ if (option & VIEW_MODE) {
+ lprintf(LOG_NOTICE,
+ "\nComparing Target & Image File version");
+ } else if (option & COMPARE_MODE) {
+ lprintf(LOG_NOTICE,
+ "\nPerforming upload for compare stage:");
+ } else {
+ lprintf(LOG_NOTICE, "\nPerforming upgrade stage:");
+ }
+ if (option & VIEW_MODE) {
+ rc = HpmfwupgPreUpgradeCheck(intf,
+ &fwupgCtx,componentMask, VIEW_MODE);
+ } else {
+ rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,
+ componentMask, option);
+ if (rc == HPMFWUPG_SUCCESS) {
+ if (verbose) {
+ printf("Component update mask : 0x%02x\n",
+ fwupgCtx.compUpdateMask.ComponentBits.byte);
+ }
+ rc = HpmfwupgUpgradeStage(intf, &fwupgCtx, option);
+ }
+ }
+ }
+ /* ACTIVATION STAGE */
+ if (rc == HPMFWUPG_SUCCESS && activate) {
+ /* check if upgrade components mask is non-zero */
+ if (fwupgCtx.compUpdateMask.ComponentBits.byte) {
+ lprintf(LOG_NOTICE, "Performing activation stage: ");
+ rc = HpmfwupgActivationStage(intf, &fwupgCtx);
+ } else {
+ lprintf(LOG_NOTICE,
+ "No components updated. Skipping activation stage.\n");
+ }
+ }
+ if (rc == HPMFWUPG_SUCCESS) {
+ if (option & VIEW_MODE) {
+ /* Dont display anything here in case we are just viewing it */
+ lprintf(LOG_NOTICE," ");
+ } else if (option & COMPARE_MODE) {
+ lprintf(LOG_NOTICE,
+ "\nFirmware comparison procedure complete\n");
+ } else {
+ lprintf(LOG_NOTICE,
+ "\nFirmware upgrade procedure successful\n");
+ }
+ } else if (option & VIEW_MODE) {
+ /* Dont display anything here in case we are just viewing it */
+ lprintf(LOG_NOTICE," ");
+ } else if (option & COMPARE_MODE) {
+ lprintf(LOG_NOTICE,
+ "Firmware comparison procedure failed\n");
+ } else {
+ lprintf(LOG_NOTICE, "Firmware upgrade procedure failed\n");
+ }
+ if (fwupgCtx.pImageData) {
+ free(fwupgCtx.pImageData);
+ fwupgCtx.pImageData = NULL;
+ }
+ return rc;
+}
+
+/* HpmfwupgValidateImageIntegrity - validate a HPM.1 firmware image file as
+ * defined in section 4 of the IPM Controller Firmware Upgrade Specification
+ * version 1.0
+ */
+int
+HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData;
+ md5_state_t ctx;
+ static unsigned char md[HPMFWUPG_MD5_SIGNATURE_LENGTH];
+ unsigned char *pMd5Sig = pFwupgCtx->pImageData
+ + (pFwupgCtx->imageSize - HPMFWUPG_MD5_SIGNATURE_LENGTH);
+ /* Validate MD5 checksum */
+ memset(md, 0, HPMFWUPG_MD5_SIGNATURE_LENGTH);
+ memset(&ctx, 0, sizeof(md5_state_t));
+ md5_init(&ctx);
+ md5_append(&ctx, pFwupgCtx->pImageData,
+ pFwupgCtx->imageSize - HPMFWUPG_MD5_SIGNATURE_LENGTH);
+ md5_finish(&ctx, md);
+ if (memcmp(md, pMd5Sig, HPMFWUPG_MD5_SIGNATURE_LENGTH) != 0) {
+ lprintf(LOG_NOTICE, "\n Invalid MD5 signature");
+ return HPMFWUPG_ERROR;
+ }
+ /* Validate Header signature */
+ if(strncmp(pImageHeader->signature,
+ HPMFWUPG_IMAGE_SIGNATURE,
+ HPMFWUPG_HEADER_SIGNATURE_LENGTH) != 0) {
+ lprintf(LOG_NOTICE,"\n Invalid image signature");
+ return HPMFWUPG_ERROR;
+ }
+ /* Validate Header image format version */
+ if (pImageHeader->formatVersion != HPMFWUPG_IMAGE_HEADER_VERSION) {
+ lprintf(LOG_NOTICE,"\n Unrecognized image version");
+ return HPMFWUPG_ERROR;
+ }
+ /* Validate header checksum */
+ if (HpmfwupgCalculateChecksum((unsigned char*)pImageHeader,
+ sizeof(struct HpmfwupgImageHeader)
+ + pImageHeader->oemDataLength
+ + sizeof(unsigned char)/*checksum*/) != 0) {
+ lprintf(LOG_NOTICE,"\n Invalid header checksum");
+ return HPMFWUPG_ERROR;
+ }
+ return HPMFWUPG_SUCCESS;
+}
+
+/* HpmfwupgPreparationStage - prepere stage of a firmware upgrade procedure as
+ * defined in section 3.2 of the IPM Controller Firmware Upgrade Specification
+ * version 1.0
+ */
+int
+HpmfwupgPreparationStage(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option)
+{
+ int componentId;
+ int rc = HPMFWUPG_SUCCESS;
+ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
+ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
+ pFwupgCtx->pImageData;
+ /* Get device ID */
+ rc = HpmfwupgGetDeviceId(intf, &pFwupgCtx->devId);
+ /* Match current IPMC IDs with upgrade image */
+ if (rc != HPMFWUPG_SUCCESS) {
+ return HPMFWUPG_ERROR;
+ }
+ /* Validate device ID */
+ if (pImageHeader->deviceId == pFwupgCtx->devId.device_id) {
+ /* Validate product ID */
+ if (memcmp(pImageHeader->prodId,
+ pFwupgCtx->devId.product_id,
+ HPMFWUPG_PRODUCT_ID_LENGTH ) == 0) {
+ /* Validate man ID */
+ if (memcmp(pImageHeader->manId,
+ pFwupgCtx->devId.manufacturer_id,
+ HPMFWUPG_MANUFATURER_ID_LENGTH) != 0) {
+ lprintf(LOG_NOTICE,
+ "\n Invalid image file for manufacturer %u",
+ buf2short(pFwupgCtx->devId.manufacturer_id));
+ rc = HPMFWUPG_ERROR;
+ }
+ } else {
+ lprintf(LOG_NOTICE,
+ "\n Invalid image file for product %u",
+ buf2short(pFwupgCtx->devId.product_id));
+ rc = HPMFWUPG_ERROR;
+ }
+ } else {
+ lprintf(LOG_NOTICE, "\n Invalid device ID %x",
+ pFwupgCtx->devId.device_id);
+ rc = HPMFWUPG_ERROR;
+ }
+ if (rc != HPMFWUPG_SUCCESS) {
+ /* Giving one more chance to user to check whether its OK to continue even if the
+ * product ID does not match. This is helpful as sometimes we just want to update
+ * and dont care whether we have a different product Id. If the user says NO then
+ * we need to just bail out from here
+ */
+ if (!((option & FORCE_MODE) || (option & VIEW_MODE))) {
+ printf("\n\n Use \"force\" option for copying all the components\n");
+ return HPMFWUPG_ERROR;
+ }
+ printf("\n Image Information");
+ printf("\n Device Id : 0x%x", pImageHeader->deviceId);
+ printf("\n Prod Id : 0x%02x%02x",
+ pImageHeader->prodId[1], pImageHeader->prodId[0]);
+ printf("\n Manuf Id : 0x%02x%02x%02x",
+ pImageHeader->manId[2],
+ pImageHeader->manId[1],
+ pImageHeader->manId[0]);
+ printf("\n Board Information");
+ printf("\n Device Id : 0x%x", pFwupgCtx->devId.device_id);
+ printf("\n Prod Id : 0x%02x%02x",
+ pFwupgCtx->devId.product_id[1], pFwupgCtx->devId.product_id[0]);
+ printf("\n Manuf Id : 0x%02x%02x%02x",
+ pFwupgCtx->devId.manufacturer_id[2],
+ pFwupgCtx->devId.manufacturer_id[1],
+ pFwupgCtx->devId.manufacturer_id[0]);
+ if (HpmGetUserInput("\n Continue ignoring DeviceID/ProductID/ManufacturingID (Y/N): ")) {
+ rc = HPMFWUPG_SUCCESS;
+ } else {
+ return HPMFWUPG_ERROR;
+ }
+ }
+ /* Validate earliest compatible revision */
+ /* Validate major & minor revision */
+ if (pImageHeader->compRevision[0] > pFwupgCtx->devId.fw_rev1
+ || (pImageHeader->compRevision[0] == pFwupgCtx->devId.fw_rev1
+ && pImageHeader->compRevision[1] > pFwupgCtx->devId.fw_rev2)) {
+ /* Version not compatible for upgrade */
+ lprintf(LOG_NOTICE, "\n Version: Major: %d", pImageHeader->compRevision[0]);
+ lprintf(LOG_NOTICE, " Minor: %x", pImageHeader->compRevision[1]);
+ lprintf(LOG_NOTICE, " Not compatible with ");
+ lprintf(LOG_NOTICE, " Version: Major: %d", pFwupgCtx->devId.fw_rev1);
+ lprintf(LOG_NOTICE, " Minor: %x", pFwupgCtx->devId.fw_rev2);
+ /* Confirming it once again */
+ if (!((option & FORCE_MODE) || (option & VIEW_MODE))) {
+ return HPMFWUPG_ERROR;
+ }
+ if (HpmGetUserInput("\n Continue IGNORING Earliest compatibility (Y/N): ")) {
+ rc = HPMFWUPG_SUCCESS;
+ } else {
+ return HPMFWUPG_ERROR;
+ }
+ }
+ /* Get target upgrade capabilities */
+ rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd);
+ if (rc != HPMFWUPG_SUCCESS) {
+ return HPMFWUPG_ERROR;
+ }
+ /* Copy response to context */
+ memcpy(&pFwupgCtx->targetCap,
+ &targetCapCmd.resp,
+ sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp));
+ if (option & VIEW_MODE) {
+ /* do nothing */
+ } else {
+ /* Make sure all component IDs defined in the
+ * upgrade image are supported by the IPMC
+ */
+ if ((pImageHeader->components.ComponentBits.byte &
+ pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte) !=
+ pImageHeader->components.ComponentBits.byte) {
+ lprintf(LOG_NOTICE,
+ "\n Some components present in the image file are not supported by the IPMC");
+ return HPMFWUPG_ERROR;
+ }
+ /* Make sure the upgrade is desirable rigth now */
+ if (pFwupgCtx->targetCap.GlobalCapabilities.bitField.fwUpgUndesirable == 1) {
+ lprintf(LOG_NOTICE, "\n Upgrade undesirable at this moment");
+ return HPMFWUPG_ERROR;
+ }
+ /* Get confimation from the user if he wants to continue when
+ * service affected during upgrade
+ */
+ if (!(option & COMPARE_MODE)
+ && (pFwupgCtx->targetCap.GlobalCapabilities.bitField.servAffectDuringUpg == 1
+ || pImageHeader->imageCapabilities.bitField.servAffected == 1)) {
+ if (HpmGetUserInput("\nServices may be affected during upgrade. Do you wish to continue? (y/n): ")) {
+ rc = HPMFWUPG_SUCCESS;
+ } else {
+ return HPMFWUPG_ERROR;
+ }
+ }
+ }
+ /* Get the general properties of each component present in image */
+ for (componentId = HPMFWUPG_COMPONENT_ID_0;
+ componentId < HPMFWUPG_COMPONENT_ID_MAX;
+ componentId++) {
+ /* Reset component properties */
+ memset(&pFwupgCtx->genCompProp[componentId], 0,
+ sizeof (struct HpmfwupgGetGeneralPropResp));
+ if ((1 << componentId & pImageHeader->components.ComponentBits.byte)) {
+ struct HpmfwupgGetComponentPropertiesCtx getCompPropCmd;
+ /* Get general component properties */
+ getCompPropCmd.req.componentId = componentId;
+ getCompPropCmd.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES;
+ rc = HpmfwupgGetComponentProperties(intf, &getCompPropCmd);
+ if (rc == HPMFWUPG_SUCCESS) {
+ /* Copy response to context */
+ memcpy(&pFwupgCtx->genCompProp[componentId],
+ &getCompPropCmd.resp,
+ sizeof(struct HpmfwupgGetGeneralPropResp));
+ }
+ }
+ }
+ return rc;
+}
+
+int
+image_version_upgradable(VERSIONINFO *pVersionInfo)
+{
+ /* If the image and active target versions are different, then
+ * upgrade */
+ if ((pVersionInfo->imageMajor != pVersionInfo->targetMajor)
+ || (pVersionInfo->imageMinor != pVersionInfo->targetMinor)
+ || (pVersionInfo->imageAux[0] != pVersionInfo->targetAux[0])
+ || (pVersionInfo->imageAux[1] != pVersionInfo->targetAux[1])
+ || (pVersionInfo->imageAux[2] != pVersionInfo->targetAux[2])
+ || (pVersionInfo->imageAux[3] != pVersionInfo->targetAux[3])) {
+ return (1);
+ }
+ /* If the image and active target versions are the same and rollback
+ * is not supported, then there's nothing to do, skip the upgrade
+ */
+ if (!pVersionInfo->rollbackSupported) {
+ return (0);
+ }
+ /* If the image and rollback target versions are different, then
+ * go ahead and upgrade
+ */
+ if ((pVersionInfo->imageMajor != pVersionInfo->rollbackMajor)
+ || (pVersionInfo->imageMinor != pVersionInfo->rollbackMinor)
+ || (pVersionInfo->imageAux[0] != pVersionInfo->rollbackAux[0])
+ || (pVersionInfo->imageAux[1] != pVersionInfo->rollbackAux[1])
+ || (pVersionInfo->imageAux[2] != pVersionInfo->rollbackAux[2])
+ || (pVersionInfo->imageAux[3] != pVersionInfo->rollbackAux[3])) {
+ return (1);
+ }
+ /* Image and rollback target versions are the same too, skip it */
+ return (0);
+}
+
+/* HpmfwupgValidateActionRecordChecksum - validate checksum of the specified
+ * action record header.
+ */
+int
+HpmfwupgValidateActionRecordChecksum(struct HpmfwupgActionRecord *pActionRecord)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ /* Validate action record checksum */
+ if (HpmfwupgCalculateChecksum((unsigned char*)pActionRecord,
+ sizeof(struct HpmfwupgActionRecord)) != 0) {
+ /* Due to ambiguity in the HPM.1 specification, for the case of
+ * the Upload Firmware Image action type, the record header length
+ * might be thought as either the first 3 bytes, or the first 34 bytes
+ * which precede the firmware image data.
+ * For the latter case we re-calculate the Upload Firmware Image
+ * record checksum for the 34 byte header length.
+ */
+ if (pActionRecord->actionType != HPMFWUPG_ACTION_UPLOAD_FIRMWARE
+ || HpmfwupgCalculateChecksum((unsigned char*)pActionRecord,
+ sizeof(struct HpmfwupgActionRecord)
+ + sizeof(struct HpmfwupgFirmwareImage))) {
+ lprintf(LOG_NOTICE, " Invalid Action record.");
+ rc = HPMFWUPG_ERROR;
+ }
+ }
+ return rc;
+}
+
+/* HpmfwupgPreUpgradeCheck - make pre-Upgrade check, this mainly helps in
+ * checking which all version upgrade is skippable because the image version
+ * is same as target version.
+ */
+int
+HpmfwupgPreUpgradeCheck(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx,
+ int componentMask, int option)
+{
+ unsigned char *pImagePtr;
+ struct HpmfwupgActionRecord *pActionRecord;
+ struct HpmfwupgImageHeader *pImageHeader;
+ int componentId;
+ pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData;
+ /* Put pointer after image header */
+ pImagePtr = (unsigned char*)(pFwupgCtx->pImageData
+ + sizeof(struct HpmfwupgImageHeader)
+ + pImageHeader->oemDataLength
+ + sizeof(unsigned char)/*chksum*/);
+ if (option & VIEW_MODE) {
+ HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER|IMAGE_VER);
+ }
+ /* Perform actions defined in the image */
+ while (pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize
+ - HPMFWUPG_MD5_SIGNATURE_LENGTH)) {
+ /* Get action record */
+ pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr;
+ /* Validate action record checksum */
+ if (HpmfwupgValidateActionRecordChecksum(pActionRecord) != HPMFWUPG_SUCCESS) {
+ return HPMFWUPG_ERROR;
+ }
+ /* Validate affected components */
+ if (pActionRecord->components.ComponentBits.byte
+ && !pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte) {
+ lprintf(LOG_NOTICE,
+ " Invalid action record. One or more affected components is not supported");
+ return HPMFWUPG_ERROR;
+ }
+ switch (pActionRecord->actionType) {
+ case HPMFWUPG_ACTION_BACKUP_COMPONENTS:
+ {
+ /* Make sure every component specified by
+ * this action record
+ * supports the backup operation
+ */
+ for (componentId = HPMFWUPG_COMPONENT_ID_0;
+ componentId < HPMFWUPG_COMPONENT_ID_MAX;
+ componentId++) {
+ if (((1 << componentId) & pActionRecord->components.ComponentBits.byte)
+ && pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.rollbackBackup == 0) {
+ lprintf(LOG_NOTICE,
+ " Component ID %d does not support backup",
+ componentId);
+ return HPMFWUPG_ERROR;
+ }
+ }
+ pImagePtr += sizeof(struct HpmfwupgActionRecord);
+ }
+ break;
+ case HPMFWUPG_ACTION_PREPARE_COMPONENTS:
+ {
+ /* Make sure every components specified by
+ * this action
+ * supports the prepare operation
+ */
+ for (componentId = HPMFWUPG_COMPONENT_ID_0;
+ componentId < HPMFWUPG_COMPONENT_ID_MAX;
+ componentId++) {
+ if (((1 << componentId) & pActionRecord->components.ComponentBits.byte)
+ && pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.preparationSupport == 0) {
+ lprintf(LOG_NOTICE,
+ " Component ID %d does not support preparation",
+ componentId);
+ return HPMFWUPG_ERROR;
+ }
+ }
+ pImagePtr += sizeof(struct HpmfwupgActionRecord);
+ }
+ break;
+ case HPMFWUPG_ACTION_UPLOAD_FIRMWARE:
+ /* Upload all firmware blocks */
+ {
+ struct HpmfwupgFirmwareImage *pFwImage;
+ unsigned char *pData;
+ unsigned int firmwareLength;
+ unsigned char mode;
+ unsigned char componentId;
+ unsigned char componentIdByte;
+ unsigned int upgrade_comp;
+ VERSIONINFO *pVersionInfo;
+ /* Save component ID on which the upload is done */
+ componentIdByte = pActionRecord->components.ComponentBits.byte;
+ componentId = 0;
+ while ((componentIdByte >>= 1) != 0) {
+ componentId++;
+ }
+ pFwImage = (struct HpmfwupgFirmwareImage*)(pImagePtr
+ + sizeof(struct HpmfwupgActionRecord));
+ pData = ((unsigned char*)pFwImage
+ + sizeof(struct HpmfwupgFirmwareImage));
+ /* Get firmware length */
+ firmwareLength = pFwImage->length[0];
+ firmwareLength |= (pFwImage->length[1] << 8) & 0xff00;
+ firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000;
+ firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000;
+
+ pVersionInfo = &gVersionInfo[componentId];
+
+ pVersionInfo->imageMajor = pFwImage->version[0];
+ pVersionInfo->imageMinor = pFwImage->version[1];
+ pVersionInfo->imageAux[0] = pFwImage->version[2];
+ pVersionInfo->imageAux[1] = pFwImage->version[3];
+ pVersionInfo->imageAux[2] = pFwImage->version[4];
+ pVersionInfo->imageAux[3] = pFwImage->version[5];
+
+ mode = TARGET_VER | IMAGE_VER;
+ /* check if component is selected for upgrade */
+ upgrade_comp = !componentMask
+ || (componentMask & pActionRecord->components.ComponentBits.byte);
+ /* check if current component version requires upgrade */
+ if (upgrade_comp && !(option & (FORCE_MODE|COMPARE_MODE))) {
+ upgrade_comp = image_version_upgradable(pVersionInfo);
+ }
+ if (verbose) {
+ lprintf(LOG_NOTICE,
+ "%s component %d",
+ (upgrade_comp ? "Updating" : "Skipping"),
+ componentId);
+ }
+ if (upgrade_comp) {
+ pFwupgCtx->compUpdateMask.ComponentBits.byte|= 1 << componentId;
+ }
+ if (option & VIEW_MODE) {
+ if (pVersionInfo->rollbackSupported) {
+ mode|= ROLLBACK_VER;
+ }
+ HpmDisplayVersion(mode,pVersionInfo, upgrade_comp);
+ printf("\n");
+ }
+ pImagePtr = pData + firmwareLength;
+ }
+ break;
+ default:
+ lprintf(LOG_NOTICE,
+ " Invalid Action type. Cannot continue");
+ return HPMFWUPG_ERROR;
+ break;
+ }
+ }
+ if (option & VIEW_MODE) {
+ HpmDisplayLine("-",74);
+ fflush(stdout);
+ lprintf(LOG_NOTICE,
+ "(*) Component requires Payload Cold Reset");
+ lprintf(LOG_NOTICE,
+ "(^) Indicates component would be upgraded");
+ }
+ return HPMFWUPG_SUCCESS;
+}
+
+/* HpmfwupgUpgradeStage - upgrade stage of a firmware upgrade procedure as
+ * defined in section 3.3 of the IPM Controller Firmware Upgrade Specification
+ * version 1.0
+ */
+int
+HpmfwupgUpgradeStage(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option)
+{
+ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
+ pFwupgCtx->pImageData;
+ struct HpmfwupgActionRecord* pActionRecord;
+ int rc = HPMFWUPG_SUCCESS;
+ unsigned char *pImagePtr;
+ unsigned int actionsSize;
+ int flagColdReset = FALSE;
+ time_t start,end;
+ /* Put pointer after image header */
+ pImagePtr = (unsigned char*)
+ (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) +
+ pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/);
+ /* Deternime actions size */
+ actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader);
+ if (!(option & VIEW_MODE)) {
+ HpmDisplayUpgradeHeader();
+ }
+ /* Perform actions defined in the image */
+ while (( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize -
+ HPMFWUPG_MD5_SIGNATURE_LENGTH))
+ && (rc == HPMFWUPG_SUCCESS)) {
+ /* Get action record */
+ pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr;
+ /* Validate action record checksum */
+ rc = HpmfwupgValidateActionRecordChecksum(pActionRecord);
+ if (rc != HPMFWUPG_SUCCESS) {
+ continue;
+ }
+ switch(pActionRecord->actionType) {
+ case HPMFWUPG_ACTION_BACKUP_COMPONENTS:
+ {
+ if (!(option & COMPARE_MODE)) {
+ /* Send Upgrade Action command */
+ struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd;
+ /* Affect only selected components */
+ initUpgActionCmd.req.componentsMask.ComponentBits.byte =
+ pFwupgCtx->compUpdateMask.ComponentBits.byte &
+ pActionRecord->components.ComponentBits.byte;
+ /* Action is prepare components */
+ if (initUpgActionCmd.req.componentsMask.ComponentBits.byte) {
+ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_BACKUP;
+ rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx);
+ }
+ }
+ pImagePtr+= sizeof(struct HpmfwupgActionRecord);
+ }
+ break;
+ case HPMFWUPG_ACTION_PREPARE_COMPONENTS:
+ {
+ if (!(option & COMPARE_MODE)) {
+ /* Send prepare components command */
+ struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd;
+ /* Affect only selected components */
+ initUpgActionCmd.req.componentsMask.ComponentBits.byte =
+ pFwupgCtx->compUpdateMask.ComponentBits.byte &
+ pActionRecord->components.ComponentBits.byte;
+ if (initUpgActionCmd.req.componentsMask.ComponentBits.byte) {
+ /* Action is prepare components */
+ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_PREPARE;
+ rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx);
+ }
+ }
+ pImagePtr+= sizeof(struct HpmfwupgActionRecord);
+ }
+ break;
+ case HPMFWUPG_ACTION_UPLOAD_FIRMWARE:
+ /* Upload all firmware blocks */
+ rc = HpmFwupgActionUploadFirmware(pActionRecord->components,
+ pFwupgCtx,
+ &pImagePtr,
+ intf,
+ option,
+ &flagColdReset);
+ break;
+ default:
+ lprintf(LOG_NOTICE, " Invalid Action type. Cannot continue");
+ rc = HPMFWUPG_ERROR;
+ break;
+ }
+ }
+ HpmDisplayLine("-", 79);
+ fflush(stdout);
+ lprintf(LOG_NOTICE, "(*) Component requires Payload Cold Reset");
+ return rc;
+}
+
+int
+HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx,
+ unsigned char **pImagePtr,
+ struct ipmi_intf *intf,
+ int option,
+ int *pFlagColdReset)
+{
+ struct HpmfwupgFirmwareImage *pFwImage;
+ struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd;
+ struct HpmfwupgUploadFirmwareBlockCtx uploadCmd;
+ struct HpmfwupgFinishFirmwareUploadCtx finishCmd;
+ VERSIONINFO *pVersionInfo;
+ time_t start,end;
+
+ int rc = HPMFWUPG_SUCCESS;
+ int skip = TRUE;
+ unsigned char *pData, *pDataInitial;
+ unsigned short count;
+ unsigned int totalSent = 0;
+ unsigned short bufLength = 0;
+ unsigned short bufLengthIsSet = 0;
+ unsigned int firmwareLength = 0;
+
+ unsigned int displayFWLength = 0;
+ unsigned char *pDataTemp;
+ unsigned int imageOffset = 0x00;
+ unsigned int blockLength = 0x00;
+ unsigned int lengthOfBlock = 0x00;
+ unsigned int numTxPkts = 0;
+ unsigned int numRxPkts = 0;
+ unsigned char mode = 0;
+ unsigned char componentId = 0x00;
+ unsigned char componentIdByte = 0x00;
+ uint16_t max_rq_size;
+
+ /* Save component ID on which the upload is done */
+ componentIdByte = components.ComponentBits.byte;
+ while ((componentIdByte>>= 1) != 0) {
+ componentId++;
+ }
+ pFwupgCtx->componentId = componentId;
+ pVersionInfo = (VERSIONINFO *)&gVersionInfo[componentId];
+ pFwImage = (struct HpmfwupgFirmwareImage*)((*pImagePtr)
+ + sizeof(struct HpmfwupgActionRecord));
+ pDataInitial = ((unsigned char *)pFwImage
+ + sizeof(struct HpmfwupgFirmwareImage));
+ pData = pDataInitial;
+
+ /* Find max buffer length according the connection parameters */
+ max_rq_size = ipmi_intf_get_max_request_data_size(intf);
+
+ /* validate lower bound of max request size */
+ if (max_rq_size <= sizeof(struct HpmfwupgUploadFirmwareBlockReq)) {
+ lprintf(LOG_ERROR, "Maximum request size is too small to "
+ "send a upload request.");
+ return HPMFWUPG_ERROR;
+ }
+
+ bufLength = max_rq_size - sizeof(struct HpmfwupgUploadFirmwareBlockReq);
+
+ /* Get firmware length */
+ firmwareLength = pFwImage->length[0];
+ firmwareLength|= (pFwImage->length[1] << 8) & 0xff00;
+ firmwareLength|= (pFwImage->length[2] << 16) & 0xff0000;
+ firmwareLength|= (pFwImage->length[3] << 24) & 0xff000000;
+ mode = TARGET_VER | IMAGE_VER;
+ if (pVersionInfo->rollbackSupported) {
+ mode |= ROLLBACK_VER;
+ }
+ if ((option & DEBUG_MODE)) {
+ printf("\n\n Comp ID : %d [%-20s]\n",
+ pVersionInfo->componentId,
+ pFwImage->desc);
+ } else {
+ HpmDisplayVersion(mode, pVersionInfo, 0);
+ }
+ if ((1 << componentId) & pFwupgCtx->compUpdateMask.ComponentBits.byte) {
+ if (verbose) {
+ lprintf(LOG_NOTICE, "Do not skip %d",
+ componentId);
+ }
+ skip = FALSE;
+ }
+ if (!skip) {
+ HpmDisplayUpgrade(0,0,1,0);
+ /* Initialize parameters */
+ uploadCmd.req = malloc(max_rq_size);
+ if (!uploadCmd.req) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return HPMFWUPG_ERROR;
+ }
+ uploadCmd.req->blockNumber = 0;
+ /* Send Initiate Upgrade Action */
+ initUpgActionCmd.req.componentsMask = components;
+ if (option & COMPARE_MODE) {
+ /* Action is compare */
+ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_COMPARE;
+ } else {
+ /* Action is upgrade */
+ initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_UPGRADE;
+ }
+ rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx);
+ if (rc != HPMFWUPG_SUCCESS) {
+ skip = TRUE;
+ }
+ if ((pVersionInfo->coldResetRequired) && (!skip)) {
+ *pFlagColdReset = TRUE;
+ }
+ /* pDataInitial is the starting pointer of the image data */
+ /* pDataTemp is one which we will move across */
+ pData = pDataInitial;
+ pDataTemp = pDataInitial;
+ lengthOfBlock = firmwareLength;
+ totalSent = 0x00;
+ displayFWLength= firmwareLength;
+ time(&start);
+ while ((pData < (pDataTemp+lengthOfBlock)) && (rc == HPMFWUPG_SUCCESS)) {
+ if ((pData+bufLength) <= (pDataTemp+lengthOfBlock)) {
+ count = bufLength;
+ } else {
+ count = (unsigned short)((pDataTemp+lengthOfBlock) - pData);
+ }
+ memcpy(&uploadCmd.req->data, pData, bufLength);
+ imageOffset = 0x00;
+ blockLength = 0x00;
+ numTxPkts++;
+ rc = HpmfwupgUploadFirmwareBlock(intf, &uploadCmd,
+ pFwupgCtx, count, &imageOffset,&blockLength);
+ numRxPkts++;
+ if (rc != HPMFWUPG_SUCCESS) {
+ if (rc == HPMFWUPG_UPLOAD_BLOCK_LENGTH && !bufLengthIsSet) {
+ rc = HPMFWUPG_SUCCESS;
+ /* Retry with a smaller buffer length */
+ if (strstr(intf->name,"lan") != NULL && bufLength > 8) {
+ bufLength-= 8;
+ lprintf(LOG_INFO,
+ "Trying reduced buffer length: %d",
+ bufLength);
+ } else if (bufLength) {
+ bufLength-= 1;
+ lprintf(LOG_INFO,
+ "Trying reduced buffer length: %d",
+ bufLength);
+ } else {
+ rc = HPMFWUPG_ERROR;
+ }
+ } else if (rc == HPMFWUPG_UPLOAD_RETRY) {
+ rc = HPMFWUPG_SUCCESS;
+ } else {
+ fflush(stdout);
+ lprintf(LOG_NOTICE,
+ "\n Error in Upload FIRMWARE command [rc=%d]\n",
+ rc);
+ lprintf(LOG_NOTICE,
+ "\n TotalSent:0x%x ",
+ totalSent);
+ /* Exiting from the function */
+ rc = HPMFWUPG_ERROR;
+ }
+ } else {
+ /* success, buf length is valid */
+ bufLengthIsSet = 1;
+ if (blockLength > firmwareLength) {
+ /*
+ * blockLength is the remaining length of the firmware to upload so
+ * if its greater than the firmware length then its kind of error
+ */
+ lprintf(LOG_NOTICE,
+ "\n Error in Upload FIRMWARE command [rc=%d]\n",
+ rc);
+ lprintf(LOG_NOTICE,
+ "\n TotalSent:0x%x Img offset:0x%x Blk length:0x%x Fwlen:0x%x\n",
+ totalSent,imageOffset,blockLength,firmwareLength);
+ rc = HPMFWUPG_ERROR;
+ }
+ totalSent += count;
+ if (imageOffset != 0x00) {
+ /* block Length is valid */
+ lengthOfBlock = blockLength;
+ pDataTemp = pDataInitial + imageOffset;
+ pData = pDataTemp;
+ if (displayFWLength == firmwareLength) {
+ /* This is basically used only to make sure that we display uptil 100% */
+ displayFWLength = blockLength + totalSent;
+ }
+ } else {
+ pData += count;
+ }
+ time(&end);
+ /*
+ * Just added debug mode in case we need to see exactly how many bytes have
+ * gone through - Its a hidden option used mainly should be used for debugging
+ */
+ if (option & DEBUG_MODE) {
+ fflush(stdout);
+ printf(" Blk Num : %02x Bytes : %05x ",
+ uploadCmd.req->blockNumber,totalSent);
+ if (imageOffset || blockLength) {
+ printf("\n--> ImgOff : %x BlkLen : %x\n",
+ imageOffset,blockLength);
+ }
+ if (displayFWLength == totalSent) {
+ printf("\n Time Taken %02ld:%02ld",
+ (end-start)/60, (end-start)%60);
+ printf("\n\n");
+ }
+ } else {
+ HpmDisplayUpgrade(0, totalSent,
+ displayFWLength, (end-start));
+ }
+ uploadCmd.req->blockNumber++;
+ }
+ }
+ /* free buffer */
+ free(uploadCmd.req);
+ uploadCmd.req = NULL;
+ }
+ if (skip) {
+ HpmDisplayUpgrade(1,0,0,0);
+ if ((option & COMPARE_MODE)
+ && !pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.comparisonSupport) {
+ printf("| |Comparison isn't supported for given compenent. |\n");
+ }
+ *pImagePtr = pDataInitial + firmwareLength;
+ }
+ if (rc == HPMFWUPG_SUCCESS && !skip) {
+ /* Send finish component */
+ /* Set image length */
+ finishCmd.req.componentId = componentId;
+ /* We need to send the actual data that is sent
+ * not the comlete firmware image length
+ */
+ finishCmd.req.imageLength[0] = totalSent & 0xFF;
+ finishCmd.req.imageLength[1] = (totalSent >> 8) & 0xFF;
+ finishCmd.req.imageLength[2] = (totalSent >> 16) & 0xFF;
+ finishCmd.req.imageLength[3] = (totalSent >> 24) & 0xFF;
+ rc = HpmfwupgFinishFirmwareUpload(intf, &finishCmd,
+ pFwupgCtx, option);
+ *pImagePtr = pDataInitial + firmwareLength;
+ }
+ return rc;
+}
+
+/* HpmfwupgActivationStage - validate stage of a firmware upgrade procedure as
+ * defined in section 3.4 of the IPM Controller Firmware Upgrade Specification
+ * version 1.0
+ */
+int
+HpmfwupgActivationStage(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct HpmfwupgActivateFirmwareCtx activateCmd;
+ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
+ pFwupgCtx->pImageData;
+ /* Print out stuf...*/
+ printf(" ");
+ fflush(stdout);
+ /* Activate new firmware */
+ activateCmd.req.rollback_override = 0;
+ rc = HpmfwupgActivateFirmware(intf, &activateCmd, pFwupgCtx);
+ if (rc == HPMFWUPG_SUCCESS) {
+ /* Query self test result if supported by target and new image */
+ if ((pFwupgCtx->targetCap.GlobalCapabilities.bitField.ipmcSelftestCap == 1)
+ || (pImageHeader->imageCapabilities.bitField.imageSelfTest == 1)) {
+ struct HpmfwupgQuerySelftestResultCtx selfTestCmd;
+ rc = HpmfwupgQuerySelftestResult(intf, &selfTestCmd,
+ pFwupgCtx);
+ if (rc == HPMFWUPG_SUCCESS) {
+ /* Get the self test result */
+ if (selfTestCmd.resp.result1 != 0x55) {
+ /* Perform manual rollback if necessary */
+ /* BACKUP/ MANUAL ROLLBACK not supported by this UA */
+ lprintf(LOG_NOTICE, " Self test failed:");
+ lprintf(LOG_NOTICE, " Result1 = %x",
+ selfTestCmd.resp.result1);
+ lprintf(LOG_NOTICE, " Result2 = %x",
+ selfTestCmd.resp.result2);
+ rc = HPMFWUPG_ERROR;
+ }
+ } else {
+ /* Perform manual rollback if necessary */
+ /* BACKUP / MANUAL ROLLBACK not supported by this UA */
+ lprintf(LOG_NOTICE," Self test failed.");
+ }
+ }
+ }
+ /* If activation / self test failed, query rollback
+ * status if automatic rollback supported
+ */
+ if (rc == HPMFWUPG_ERROR) {
+ if ((pFwupgCtx->targetCap.GlobalCapabilities.bitField.autRollback == 1)
+ && (pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.rollbackBackup != 0x00)) {
+ struct HpmfwupgQueryRollbackStatusCtx rollCmd;
+ lprintf(LOG_NOTICE," Getting rollback status...");
+ fflush(stdout);
+ rc = HpmfwupgQueryRollbackStatus(intf,
+ &rollCmd, pFwupgCtx);
+ }
+ }
+ return rc;
+}
+
+int
+HpmfwupgGetBufferFromFile(char *imageFilename,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ int ret = 0;
+ FILE *pImageFile = fopen(imageFilename, "rb");
+ if (pImageFile == NULL) {
+ lprintf(LOG_ERR, "Cannot open image file '%s'",
+ imageFilename);
+ return HPMFWUPG_ERROR;
+ }
+ /* Get the raw data in file */
+ fseek(pImageFile, 0, SEEK_END);
+ pFwupgCtx->imageSize = ftell(pImageFile);
+ pFwupgCtx->pImageData = malloc(sizeof(unsigned char)*pFwupgCtx->imageSize);
+ if (pFwupgCtx->pImageData == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ fclose(pImageFile);
+ return HPMFWUPG_ERROR;
+ }
+ rewind(pImageFile);
+ ret = fread(pFwupgCtx->pImageData,
+ sizeof(unsigned char),
+ pFwupgCtx->imageSize,
+ pImageFile);
+ if (ret != pFwupgCtx->imageSize) {
+ lprintf(LOG_ERR,
+ "Failed to read file %s size %d",
+ imageFilename,
+ pFwupgCtx->imageSize);
+ rc = HPMFWUPG_ERROR;
+ }
+ fclose(pImageFile);
+ return rc;
+}
+
+int
+HpmfwupgGetDeviceId(struct ipmi_intf *intf, struct ipm_devid_rsp *pGetDevId)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data_len = 0;
+ rsp = HpmfwupgSendCmd(intf, req, NULL);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error getting device ID.");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode != 0x00) {
+ lprintf(LOG_ERR, "Error getting device ID.");
+ lprintf(LOG_ERR, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ return HPMFWUPG_ERROR;
+ }
+ memcpy(pGetDevId, rsp->data, sizeof(struct ipm_devid_rsp));
+ return HPMFWUPG_SUCCESS;
+}
+
+int
+HpmfwupgGetTargetUpgCapabilities(struct ipmi_intf *intf,
+ struct HpmfwupgGetTargetUpgCapabilitiesCtx *pCtx)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_GET_TARGET_UPG_CAPABILITIES;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgGetTargetUpgCapabilitiesReq);
+ rsp = HpmfwupgSendCmd(intf, req, NULL);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Error getting target upgrade capabilities.");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode != 0x00) {
+ lprintf(LOG_ERR,
+ "Error getting target upgrade capabilities, ccode: 0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ return HPMFWUPG_ERROR;
+ }
+ memcpy(&pCtx->resp, rsp->data,
+ sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp));
+ if (verbose) {
+ lprintf(LOG_NOTICE, "TARGET UPGRADE CAPABILITIES");
+ lprintf(LOG_NOTICE, "-------------------------------");
+ lprintf(LOG_NOTICE, "HPM.1 version............%d ",
+ pCtx->resp.hpmVersion);
+ lprintf(LOG_NOTICE, "Component 0 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component0 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Component 1 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component1 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Component 2 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component2 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Component 3 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component3 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Component 4 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component4 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Component 5 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component5 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Component 6 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component6 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Component 7 presence....[%c] ",
+ pCtx->resp.componentsPresent.ComponentBits.bitField.component7 ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Upgrade undesirable.....[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.fwUpgUndesirable ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Aut rollback override...[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.autRollbackOverride ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "IPMC degraded...........[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.ipmcDegradedDurinUpg ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Defered activation......[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.deferActivation ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Service affected........[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.servAffectDuringUpg ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Manual rollback.........[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.manualRollback ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Automatic rollback......[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.autRollback ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Self test...............[%c] ",
+ pCtx->resp.GlobalCapabilities.bitField.ipmcSelftestCap ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Upgrade timeout.........[%d sec] ",
+ pCtx->resp.upgradeTimeout*5);
+ lprintf(LOG_NOTICE, "Self test timeout.......[%d sec] ",
+ pCtx->resp.selftestTimeout*5);
+ lprintf(LOG_NOTICE, "Rollback timeout........[%d sec] ",
+ pCtx->resp.rollbackTimeout*5);
+ lprintf(LOG_NOTICE, "Inaccessibility timeout.[%d sec] \n",
+ pCtx->resp.inaccessTimeout*5);
+ }
+ return HPMFWUPG_SUCCESS;
+}
+
+int
+HpmfwupgGetComponentProperties(struct ipmi_intf *intf,
+ struct HpmfwupgGetComponentPropertiesCtx *pCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_GET_COMPONENT_PROPERTIES;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgGetComponentPropertiesReq);
+ rsp = HpmfwupgSendCmd(intf, req, NULL);
+ if (rsp == NULL) {
+ lprintf(LOG_NOTICE,
+ "Error getting component properties\n");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode != 0x00) {
+ lprintf(LOG_NOTICE,
+ "Error getting component properties");
+ lprintf(LOG_NOTICE,
+ "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ return HPMFWUPG_ERROR;
+ }
+ switch (pCtx->req.selector) {
+ case HPMFWUPG_COMP_GEN_PROPERTIES:
+ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetGeneralPropResp));
+ if (verbose) {
+ lprintf(LOG_NOTICE, "GENERAL PROPERTIES");
+ lprintf(LOG_NOTICE, "-------------------------------");
+ lprintf(LOG_NOTICE, "Payload cold reset req....[%c] ",
+ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.payloadColdReset ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Def. activation supported.[%c] ",
+ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.deferredActivation ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Comparison supported......[%c] ",
+ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.comparisonSupport ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Preparation supported.....[%c] ",
+ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.preparationSupport ? 'y' : 'n');
+ lprintf(LOG_NOTICE, "Rollback supported........[%c] \n",
+ pCtx->resp.Response.generalPropResp.GeneralCompProperties.bitfield.rollbackBackup ? 'y' : 'n');
+ }
+ break;
+ case HPMFWUPG_COMP_CURRENT_VERSION:
+ memcpy(&pCtx->resp, rsp->data,
+ sizeof(struct HpmfwupgGetCurrentVersionResp));
+ if (verbose) {
+ lprintf(LOG_NOTICE, "Current Version: ");
+ lprintf(LOG_NOTICE, " Major: %d",
+ pCtx->resp.Response.currentVersionResp.currentVersion[0]);
+ lprintf(LOG_NOTICE, " Minor: %x",
+ pCtx->resp.Response.currentVersionResp.currentVersion[1]);
+ lprintf(LOG_NOTICE, " Aux : %03d %03d %03d %03d\n",
+ pCtx->resp.Response.currentVersionResp.currentVersion[2],
+ pCtx->resp.Response.currentVersionResp.currentVersion[3],
+ pCtx->resp.Response.currentVersionResp.currentVersion[4],
+ pCtx->resp.Response.currentVersionResp.currentVersion[5]);
+ }
+ break;
+ case HPMFWUPG_COMP_DESCRIPTION_STRING:
+ memcpy(&pCtx->resp, rsp->data,
+ sizeof(struct HpmfwupgGetDescStringResp));
+ if (verbose) {
+ char descString[HPMFWUPG_DESC_STRING_LENGTH + 1];
+ memcpy(descString,
+ pCtx->resp.Response.descStringResp.descString,
+ HPMFWUPG_DESC_STRING_LENGTH);
+ descString[HPMFWUPG_DESC_STRING_LENGTH] = '\0';
+ lprintf(LOG_NOTICE,
+ "Description string: %s\n",
+ descString);
+ }
+ break;
+ case HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION:
+ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetRollbackFwVersionResp));
+ if (verbose) {
+ lprintf(LOG_NOTICE, "Rollback FW Version: ");
+ lprintf(LOG_NOTICE, " Major: %d",
+ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[0]);
+ lprintf(LOG_NOTICE, " Minor: %x",
+ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[1]);
+ lprintf(LOG_NOTICE, " Aux : %03d %03d %03d %03d\n",
+ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[2],
+ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[3],
+ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[4],
+ pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]);
+ }
+ break;
+ case HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION:
+ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDeferredFwVersionResp));
+ if (verbose) {
+ lprintf(LOG_NOTICE, "Deferred FW Version: ");
+ lprintf(LOG_NOTICE, " Major: %d",
+ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[0]);
+ lprintf(LOG_NOTICE, " Minor: %x",
+ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[1]);
+ lprintf(LOG_NOTICE, " Aux : %03d %03d %03d %03d\n",
+ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[2],
+ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[3],
+ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[4],
+ pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[5]);
+ }
+ break;
+ case HPMFWUPG_COMP_OEM_PROPERTIES:
+ /* OEM Properties command */
+ memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetOemProperties));
+ if (verbose) {
+ unsigned char i = 0;
+ lprintf(LOG_NOTICE,"OEM Properties: ");
+ for (i=0; i < HPMFWUPG_OEM_LENGTH; i++) {
+ lprintf(LOG_NOTICE, " 0x%x ",
+ pCtx->resp.Response.oemProperties.oemRspData[i]);
+ }
+ }
+ break;
+ default:
+ lprintf(LOG_NOTICE,"Unsupported component selector");
+ rc = HPMFWUPG_ERROR;
+ break;
+ }
+ return rc;
+}
+
+int
+HpmfwupgAbortUpgrade(struct ipmi_intf *intf,
+ struct HpmfwupgAbortUpgradeCtx *pCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_ABORT_UPGRADE;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgAbortUpgradeReq);
+ rsp = HpmfwupgSendCmd(intf, req, NULL);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error - aborting upgrade.");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode != 0x00) {
+ lprintf(LOG_ERR, "Error aborting upgrade");
+ lprintf(LOG_ERR, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+int
+HpmfwupgInitiateUpgradeAction(struct ipmi_intf *intf,
+ struct HpmfwupgInitiateUpgradeActionCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_INITIATE_UPGRADE_ACTION;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgInitiateUpgradeActionReq);
+ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error initiating upgrade action.");
+ return HPMFWUPG_ERROR;
+ }
+ /* Long duration command handling */
+ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
+ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
+ } else if (rsp->ccode != 0x00) {
+ lprintf(LOG_NOTICE,"Error initiating upgrade action");
+ lprintf(LOG_NOTICE, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+int
+HpmfwupgUploadFirmwareBlock(struct ipmi_intf *intf,
+ struct HpmfwupgUploadFirmwareBlockCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int count,
+ unsigned int *imageOffset, unsigned int *blockLength)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ pCtx->req->picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_UPLOAD_FIRMWARE_BLOCK;
+ req.msg.data = (unsigned char *)pCtx->req;
+ /* 2 is the size of the upload struct - data */
+ req.msg.data_len = 2 + count;
+ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
+ if (rsp == NULL) {
+ lprintf(LOG_NOTICE, "Error uploading firmware block.");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS
+ || rsp->ccode == 0x00) {
+ /*
+ * We need to check if the response also contains the next upload firmware offset
+ * and the firmware length in its response - These are optional but very vital
+ */
+ if (rsp->data_len > 1) {
+ /*
+ * If the response data length is greater than 1 it should contain both the
+ * the Section offset and section length. Because we cannot just have
+ * Section offset without section length so the length should be 9
+ */
+ if (rsp->data_len == 9) {
+ /* rsp->data[1] - LSB rsp->data[2] - rsp->data[3] = MSB */
+ *imageOffset = (rsp->data[4] << 24) + (rsp->data[3] << 16) + (rsp->data[2] << 8) + rsp->data[1];
+ *blockLength = (rsp->data[8] << 24) + (rsp->data[7] << 16) + (rsp->data[6] << 8) + rsp->data[5];
+ } else {
+ /*
+ * The Spec does not say much for this kind of errors where the
+ * firmware returned only offset and length so currently returning it
+ * as 0x82 - Internal CheckSum Error
+ */
+ lprintf(LOG_NOTICE,
+ "Error wrong rsp->datalen %d for Upload Firmware block command\n",
+ rsp->data_len);
+ rsp->ccode = HPMFWUPG_INT_CHECKSUM_ERROR;
+ }
+ }
+ }
+ /* Long duration command handling */
+ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
+ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
+ } else if (rsp->ccode != 0x00) {
+ /* PATCH --> This validation is to handle retryables errors codes on IPMB bus.
+ * This will be fixed in the next release of open ipmi and this
+ * check will have to be removed. (Buggy version = 39)
+ */
+ if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
+ lprintf(LOG_DEBUG, "HPM: [PATCH]Retryable error detected");
+ rc = HPMFWUPG_UPLOAD_RETRY;
+ } else if (rsp->ccode == IPMI_CC_REQ_DATA_INV_LENGTH ||
+ rsp->ccode == IPMI_CC_REQ_DATA_FIELD_EXCEED) {
+ /* If completion code = 0xc7(0xc8), we will retry with a reduced buffer length.
+ * Do not print error.
+ */
+ rc = HPMFWUPG_UPLOAD_BLOCK_LENGTH;
+ } else {
+ lprintf(LOG_ERR, "Error uploading firmware block");
+ lprintf(LOG_ERR, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode,
+ completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ }
+ return rc;
+}
+
+int
+HpmfwupgFinishFirmwareUpload(struct ipmi_intf *intf,
+ struct HpmfwupgFinishFirmwareUploadCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx, int option)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_FINISH_FIRMWARE_UPLOAD;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgFinishFirmwareUploadReq);
+ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error fininshing firmware upload.");
+ return HPMFWUPG_ERROR;
+ }
+ /* Long duration command handling */
+ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
+ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
+ } else if ((option & COMPARE_MODE) && rsp->ccode == 0x83) {
+ printf("| |Component's active copy doesn't match the upgrade image |\n");
+ } else if ((option & COMPARE_MODE) && rsp->ccode == IPMI_CC_OK) {
+ printf("| |Comparison passed |\n");
+ } else if ( rsp->ccode != IPMI_CC_OK ) {
+ lprintf(LOG_ERR, "Error finishing firmware upload");
+ lprintf(LOG_ERR, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+int
+HpmfwupgActivateFirmware(struct ipmi_intf *intf,
+ struct HpmfwupgActivateFirmwareCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_ACTIVATE_FIRMWARE;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgActivateFirmwareReq)
+ - (!pCtx->req.rollback_override ? 1 : 0);
+ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error activating firmware.");
+ return HPMFWUPG_ERROR;
+ }
+ /* Long duration command handling */
+ if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
+ printf("Waiting firmware activation...");
+ fflush(stdout);
+ rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx);
+ if (rc == HPMFWUPG_SUCCESS) {
+ lprintf(LOG_NOTICE, "OK");
+ } else {
+ lprintf(LOG_NOTICE, "Failed");
+ }
+ } else if (rsp->ccode != IPMI_CC_OK) {
+ lprintf(LOG_ERR, "Error activating firmware");
+ lprintf(LOG_ERR, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+int
+HpmfwupgGetUpgradeStatus(struct ipmi_intf *intf,
+ struct HpmfwupgGetUpgradeStatusCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx,
+ int silent)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_GET_UPGRADE_STATUS;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgGetUpgradeStatusReq);
+ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
+ if (!rsp) {
+ lprintf(LOG_NOTICE,
+ "Error getting upgrade status. Failed to get response.");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode == 0x00) {
+ memcpy(&pCtx->resp, rsp->data,
+ sizeof(struct HpmfwupgGetUpgradeStatusResp));
+ if (!silent) {
+ lprintf(LOG_NOTICE, "Upgrade status:");
+ lprintf(LOG_NOTICE,
+ " Command in progress: %x",
+ pCtx->resp.cmdInProcess);
+ lprintf(LOG_NOTICE,
+ " Last command completion code: %x",
+ pCtx->resp.lastCmdCompCode);
+ }
+ } else if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
+ /* PATCH --> This validation is to handle retryable errors
+ * codes on the IPMB bus.
+ * This will be fixed in the next release of
+ * open ipmi and this check can be removed.
+ * (Buggy version = 39)
+ */
+ if (!silent) {
+ lprintf(LOG_DEBUG, "HPM: Retryable error detected");
+ }
+ pCtx->resp.lastCmdCompCode = HPMFWUPG_COMMAND_IN_PROGRESS;
+ } else {
+ lprintf(LOG_NOTICE, "Error getting upgrade status");
+ lprintf(LOG_NOTICE, "compcode=0x%x: %s", rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ return HPMFWUPG_ERROR;
+ }
+ return HPMFWUPG_SUCCESS;
+}
+
+int
+HpmfwupgManualFirmwareRollback(struct ipmi_intf *intf,
+ struct HpmfwupgManualFirmwareRollbackCtx *pCtx)
+{
+ struct HpmfwupgUpgradeCtx fwupgCtx;
+ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ /* prepare fake upgrade context */
+ memset(&fwupgCtx, 0, sizeof (fwupgCtx));
+ verbose--;
+ rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd);
+ verbose++;
+ if (rc != HPMFWUPG_SUCCESS) {
+ return rc;
+ }
+ memcpy(&fwupgCtx.targetCap, &targetCapCmd.resp, sizeof(targetCapCmd.resp));
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgManualFirmwareRollbackReq);
+ rsp = HpmfwupgSendCmd(intf, req, &fwupgCtx);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error sending manual rollback.");
+ return HPMFWUPG_ERROR;
+ }
+ /* Long duration command handling */
+ if (rsp->ccode == IPMI_CC_OK
+ || rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) {
+ struct HpmfwupgQueryRollbackStatusCtx resCmd;
+ printf("Waiting firmware rollback...");
+ fflush(stdout);
+ rc = HpmfwupgQueryRollbackStatus(intf, &resCmd, &fwupgCtx);
+ } else if ( rsp->ccode != 0x00 ) {
+ lprintf(LOG_ERR, "Error sending manual rollback");
+ lprintf(LOG_ERR, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+int
+HpmfwupgQueryRollbackStatus(struct ipmi_intf *intf,
+ struct HpmfwupgQueryRollbackStatusCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ unsigned int rollbackTimeout = 0;
+ unsigned int timeoutSec1, timeoutSec2;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_QUERY_ROLLBACK_STATUS;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgQueryRollbackStatusReq);
+ /* If we are not in upgrade context, we use default timeout values */
+ if (pFwupgCtx != NULL) {
+ struct HpmfwupgImageHeader *pImageHeader;
+ if (pFwupgCtx->pImageData) {
+ pImageHeader = (struct HpmfwupgImageHeader*)pFwupgCtx->pImageData;
+ rollbackTimeout = pImageHeader->rollbackTimeout;
+ } else {
+ rollbackTimeout = 0;
+ }
+ /* Use the greater of the two timeouts (header and target caps) */
+ rollbackTimeout = MAX(rollbackTimeout,
+ pFwupgCtx->targetCap.rollbackTimeout) * 5;
+ } else {
+ rollbackTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
+ }
+ /* Poll rollback status until completion or timeout */
+ timeoutSec1 = time(NULL);
+ timeoutSec2 = time(NULL);
+ do {
+ /* Must wait at least 100 ms between status requests */
+ usleep(100000);
+ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
+ /* PATCH --> This validation is to handle retryables errors codes on IPMB bus.
+ * This will be fixed in the next release of open ipmi and this
+ * check will have to be removed. (Buggy version = 39)
+ */
+ if (rsp) {
+ if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
+ lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected");
+ rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS;
+ }
+ }
+ timeoutSec2 = time(NULL);
+ } while (rsp
+ && ((rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS)
+ || (rsp->ccode == IPMI_CC_TIMEOUT))
+ && (timeoutSec2 - timeoutSec1 < rollbackTimeout));
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error getting upgrade status.");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode == 0x00) {
+ memcpy(&pCtx->resp, rsp->data,
+ sizeof(struct HpmfwupgQueryRollbackStatusResp));
+ if (pCtx->resp.rollbackComp.ComponentBits.byte != 0) {
+ /* Rollback occured */
+ lprintf(LOG_NOTICE,
+ "Rollback occured on component mask: 0x%02x",
+ pCtx->resp.rollbackComp.ComponentBits.byte);
+ } else {
+ lprintf(LOG_NOTICE,
+ "No Firmware rollback occured");
+ }
+ } else if (rsp->ccode == 0x81) {
+ lprintf(LOG_ERR,
+ "Rollback failed on component mask: 0x%02x",
+ pCtx->resp.rollbackComp.ComponentBits.byte);
+ rc = HPMFWUPG_ERROR;
+ } else {
+ lprintf(LOG_ERR,
+ "Error getting rollback status");
+ lprintf(LOG_ERR,
+ "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+int
+HpmfwupgQuerySelftestResult(struct ipmi_intf *intf, struct HpmfwupgQuerySelftestResultCtx *pCtx,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ unsigned char selfTestTimeout = 0;
+ unsigned int timeoutSec1, timeoutSec2;
+ pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER;
+ /* If we are not in upgrade context, we use default timeout values */
+ if (pFwupgCtx != NULL) {
+ /* Getting selftest timeout from new image */
+ struct HpmfwupgImageHeader *pImageHeader = (struct HpmfwupgImageHeader*)
+ pFwupgCtx->pImageData;
+ selfTestTimeout = MAX(pImageHeader->selfTestTimeout,
+ pFwupgCtx->targetCap.selftestTimeout) * 5;
+ } else {
+ selfTestTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
+ }
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPMFWUPG_QUERY_SELFTEST_RESULT;
+ req.msg.data = (unsigned char*)&pCtx->req;
+ req.msg.data_len = sizeof(struct HpmfwupgQuerySelftestResultReq);
+ /* Poll rollback status until completion or timeout */
+ timeoutSec1 = time(NULL);
+ timeoutSec2 = time(NULL);
+ do {
+ /* Must wait at least 100 ms between status requests */
+ usleep(100000);
+ rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx);
+ /* PATCH --> This validation is to handle retryables errors codes on IPMB bus.
+ * This will be fixed in the next release of open ipmi and this
+ * check will have to be removed. (Buggy version = 39)
+ */
+ if (rsp) {
+ if (HPMFWUPG_IS_RETRYABLE(rsp->ccode)) {
+ lprintf(LOG_DEBUG,
+ "HPM: [PATCH]Retryable error detected");
+ rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS;
+ }
+ }
+ timeoutSec2 = time(NULL);
+ } while (rsp
+ && (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS)
+ && (timeoutSec2 - timeoutSec1 < selfTestTimeout));
+ if (rsp == NULL) {
+ lprintf(LOG_NOTICE, "Error getting upgrade status\n");
+ return HPMFWUPG_ERROR;
+ }
+ if (rsp->ccode == 0x00) {
+ memcpy(&pCtx->resp, rsp->data,
+ sizeof(struct HpmfwupgQuerySelftestResultResp));
+ if (verbose) {
+ lprintf(LOG_NOTICE, "Self test results:");
+ lprintf(LOG_NOTICE, "Result1 = %x",
+ pCtx->resp.result1);
+ lprintf(LOG_NOTICE, "Result2 = %x",
+ pCtx->resp.result2);
+ }
+ } else {
+ lprintf(LOG_NOTICE, "Error getting self test results");
+ lprintf(LOG_NOTICE, "compcode=0x%x: %s",
+ rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+struct ipmi_rs *
+HpmfwupgSendCmd(struct ipmi_intf *intf, struct ipmi_rq req,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ struct ipmi_rs *rsp;
+ unsigned int inaccessTimeout = 0, inaccessTimeoutCounter = 0;
+ unsigned int upgradeTimeout = 0, upgradeTimeoutCounter = 0;
+ unsigned int timeoutSec1, timeoutSec2;
+ unsigned char retry = 0;
+ /* If we are not in upgrade context, we use default timeout values */
+ if (pFwupgCtx != NULL) {
+ inaccessTimeout = pFwupgCtx->targetCap.inaccessTimeout*5;
+ upgradeTimeout = pFwupgCtx->targetCap.upgradeTimeout*5;
+ } else {
+ /* keeping the inaccessTimeout to 60 seconds results in almost 2900 retries
+ * So if the target is not available it will be retrying the command for 2900
+ * times which is not effecient -So reducing the Timout to 5 seconds which is
+ * almost 200 retries if it continuously recieves 0xC3 as completion code.
+ */
+ inaccessTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
+ upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
+ }
+ timeoutSec1 = time(NULL);
+ do {
+ static unsigned char isValidSize = FALSE;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ #define HPM_LAN_PACKET_RESIZE_LIMIT 6
+ /* also covers lanplus */
+ if (strstr(intf->name, "lan") != NULL) {
+ static int errorCount=0;
+ static struct ipmi_rs fakeRsp;
+ lprintf(LOG_DEBUG,
+ "HPM: no response available");
+ lprintf(LOG_DEBUG,
+ "HPM: the command may be rejected for security reasons");
+ if (req.msg.netfn == IPMI_NETFN_PICMG
+ && req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK
+ && errorCount < HPM_LAN_PACKET_RESIZE_LIMIT
+ && (!isValidSize)) {
+ lprintf(LOG_DEBUG,
+ "HPM: upload firmware block API called");
+ lprintf(LOG_DEBUG,
+ "HPM: returning length error to force resize");
+ fakeRsp.ccode = IPMI_CC_REQ_DATA_INV_LENGTH;
+ rsp = &fakeRsp;
+ errorCount++;
+ } else if (req.msg.netfn == IPMI_NETFN_PICMG
+ && (req.msg.cmd == HPMFWUPG_ACTIVATE_FIRMWARE
+ || req.msg.cmd == HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK)) {
+ /*
+ * rsp == NULL and command activate firmware or manual firmware
+ * rollback most likely occurs when we have sent a firmware activation
+ * request. Fake a command in progress response.
+ */
+ lprintf(LOG_DEBUG,
+ "HPM: activate/rollback firmware API called");
+ lprintf(LOG_DEBUG,
+ "HPM: returning in progress to handle IOL session lost");
+ fakeRsp.ccode = HPMFWUPG_COMMAND_IN_PROGRESS;
+ rsp = &fakeRsp;
+ } else if (req.msg.netfn == IPMI_NETFN_PICMG
+ && (req.msg.cmd == HPMFWUPG_QUERY_ROLLBACK_STATUS
+ || req.msg.cmd == HPMFWUPG_GET_UPGRADE_STATUS
+ || req.msg.cmd == HPMFWUPG_QUERY_SELFTEST_RESULT)
+ && ( !intf->target_addr || intf->target_addr == intf->my_addr)) {
+ /* reopen session only if target IPMC is directly accessed */
+ /*
+ * rsp == NULL and command get upgrade status or query rollback
+ * status most likely occurs when we are waiting for firmware
+ * activation. Try to re-open the IOL session (re-open will work
+ * once the IPMC recovers from firmware activation.
+ */
+ lprintf(LOG_DEBUG, "HPM: upg/rollback status firmware API called");
+ lprintf(LOG_DEBUG, "HPM: try to re-open IOL session");
+ {
+ /* force session re-open */
+ intf->opened = 0;
+ intf->session->authtype = IPMI_SESSION_AUTHTYPE_NONE;
+ intf->session->session_id = 0;
+ intf->session->in_seq = 0;
+ intf->session->out_seq = 0;
+ intf->session->active = 0;
+ intf->session->retry = 10;
+ while (intf->open(intf) == HPMFWUPG_ERROR
+ && inaccessTimeoutCounter < inaccessTimeout) {
+ inaccessTimeoutCounter += (time(NULL) - timeoutSec1);
+ timeoutSec1 = time(NULL);
+ }
+ /* Fake timeout to retry command */
+ fakeRsp.ccode = 0xc3;
+ rsp = &fakeRsp;
+ }
+ }
+ }
+ }
+ /* Handle inaccessibility timeout (rsp = NULL if IOL) */
+ if (rsp == NULL || rsp->ccode == 0xff || rsp->ccode == 0xc3 || rsp->ccode == 0xd3) {
+ if (inaccessTimeoutCounter < inaccessTimeout) {
+ timeoutSec2 = time(NULL);
+ if (timeoutSec2 > timeoutSec1) {
+ inaccessTimeoutCounter += timeoutSec2 - timeoutSec1;
+ timeoutSec1 = time(NULL);
+ }
+ usleep(100000);
+ retry = 1;
+ } else {
+ retry = 0;
+ }
+ } else if ( rsp->ccode == 0xc0 ) {
+ /* Handle node busy timeout */
+ if (upgradeTimeoutCounter < upgradeTimeout) {
+ timeoutSec2 = time(NULL);
+ if (timeoutSec2 > timeoutSec1) {
+ timeoutSec1 = time(NULL);
+ upgradeTimeoutCounter += timeoutSec2 - timeoutSec1;
+ }
+ usleep(100000);
+ retry = 1;
+ } else {
+ retry = 0;
+ }
+ } else {
+# ifdef ENABLE_OPENIPMI_V39_PATCH
+ if (rsp->ccode == IPMI_CC_OK) {
+ errorCount = 0 ;
+ }
+# endif
+ retry = 0;
+ if (req.msg.netfn == IPMI_NETFN_PICMG
+ && req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK
+ && (!isValidSize)) {
+ lprintf(LOG_INFO,
+ "Buffer length is now considered valid");
+ isValidSize = TRUE;
+ }
+ }
+ } while (retry);
+ return rsp;
+}
+
+int
+HpmfwupgWaitLongDurationCmd(struct ipmi_intf *intf,
+ struct HpmfwupgUpgradeCtx *pFwupgCtx)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ unsigned int upgradeTimeout = 0;
+ unsigned int timeoutSec1, timeoutSec2;
+ struct HpmfwupgGetUpgradeStatusCtx upgStatusCmd;
+ /* If we are not in upgrade context, we use default timeout values */
+ if (pFwupgCtx != NULL) {
+ upgradeTimeout = (unsigned int)(pFwupgCtx->targetCap.upgradeTimeout*5);
+ if (verbose) {
+ printf("Use File Upgrade Capabilities: %i seconds\n",
+ upgradeTimeout);
+ }
+ } else {
+ /* Try to retreive from Caps */
+ struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd;
+ if(HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd) != HPMFWUPG_SUCCESS) {
+ upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT;
+ if (verbose) {
+ printf("Use default timeout: %i seconds\n",
+ upgradeTimeout);
+ }
+ } else {
+ upgradeTimeout = (unsigned int)(targetCapCmd.resp.upgradeTimeout * 5);
+ if (verbose) {
+ printf("Use Command Upgrade Capabilities Timeout: %i seconds\n",
+ upgradeTimeout);
+ }
+ }
+ }
+ if (rc == HPMFWUPG_SUCCESS) {
+ /* Poll upgrade status until completion or timeout*/
+ timeoutSec1 = time(NULL);
+ timeoutSec2 = time(NULL);
+ rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd,
+ pFwupgCtx, 1);
+ }
+ while (
+ /* With KCS: Cover the case where we sometime
+ * receive d5 (on the first get status) from
+ * the ipmi driver.
+ */
+ (upgStatusCmd.resp.lastCmdCompCode != 0x00 )
+ && ((timeoutSec2 - timeoutSec1) < upgradeTimeout )
+ && (rc == HPMFWUPG_SUCCESS)) {
+ /* Must wait at least 1000 ms between status requests */
+ usleep(1000000);
+ timeoutSec2 = time(NULL);
+ rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx, 1);
+/*
+ * printf("Get Status: %x - %x = %x _ %x [%x]\n",
+ ( timeoutSec2, timeoutSec1,
+ * (timeoutSec2 - timeoutSec1),
+ * upgradeTimeout, rc);
+ */
+ }
+ if (upgStatusCmd.resp.lastCmdCompCode != 0x00) {
+ if (verbose) {
+ lprintf(LOG_NOTICE,
+ "Error waiting for command %x, compcode = %x",
+ upgStatusCmd.resp.cmdInProcess,
+ upgStatusCmd.resp.lastCmdCompCode);
+ }
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
+unsigned char
+HpmfwupgCalculateChecksum(unsigned char *pData, unsigned int length)
+{
+ unsigned char checksum = 0;
+ int dataIdx = 0;
+ for (dataIdx = 0; dataIdx < length; dataIdx++) {
+ checksum += pData[dataIdx];
+ }
+ return checksum;
+}
+
+void
+HpmfwupgPrintUsage(void)
+{
+ lprintf(LOG_NOTICE,
+"help - This help menu.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"check - Check the target information.");
+ lprintf(LOG_NOTICE,
+"check <file> - If the user is unsure of what update is going to be ");
+ lprintf(LOG_NOTICE,
+" This will display the existing target version and");
+ lprintf(LOG_NOTICE,
+" image version on the screen");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"upgrade <file> [component x...] [force] [activate]");
+ lprintf(LOG_NOTICE,
+" - Copies components from a valid HPM.1 image to the target.");
+ lprintf(LOG_NOTICE,
+" If one or more components specified by \"component\",");
+ lprintf(LOG_NOTICE,
+" only the specified components are copied.");
+ lprintf(LOG_NOTICE,
+" Otherwise, all the image components are copied.");
+ lprintf(LOG_NOTICE,
+" Before copy, each image component undergoes a version check");
+ lprintf(LOG_NOTICE,
+" and can be skipped if the target component version");
+ lprintf(LOG_NOTICE,
+" is the same or more recent.");
+ lprintf(LOG_NOTICE,
+" Use \"force\" to bypass the version check results.");
+ lprintf(LOG_NOTICE,
+" Make sure to check the versions first using the");
+ lprintf(LOG_NOTICE,
+" \"check <file>\" command.");
+ lprintf(LOG_NOTICE,
+" If \"activate\" is specified, the newly uploaded firmware");
+ lprintf(LOG_NOTICE,
+" is activated.");
+ lprintf(LOG_NOTICE,
+"upgstatus - Returns the status of the last long duration command.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"compare <file> - Perform \"Comparison of the Active Copy\" action for all the");
+ lprintf(LOG_NOTICE,
+" components present in the file.");
+ lprintf(LOG_NOTICE,
+"compare <file> component x - Compare only component <x> from the given <file>");
+ lprintf(LOG_NOTICE,
+"activate - Activate the newly uploaded firmware.");
+ lprintf(LOG_NOTICE,
+"activate norollback - Activate the newly uploaded firmware but inform");
+ lprintf(LOG_NOTICE,
+" the target to not automatically rollback if ");
+ lprintf(LOG_NOTICE,
+" the upgrade fails.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"targetcap - Get the target upgrade capabilities.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"compprop <id> <prop> - Get specified component properties from the target.");
+ lprintf(LOG_NOTICE,
+" Valid component <id>: 0-7 ");
+ lprintf(LOG_NOTICE,
+" Properties <prop> can be one of the following: ");
+ lprintf(LOG_NOTICE,
+" 0- General properties");
+ lprintf(LOG_NOTICE,
+" 1- Current firmware version");
+ lprintf(LOG_NOTICE,
+" 2- Description string");
+ lprintf(LOG_NOTICE,
+" 3- Rollback firmware version");
+ lprintf(LOG_NOTICE,
+" 4- Deferred firmware version");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"abort - Abort the on-going firmware upgrade.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"rollback - Performs a manual rollback on the IPM Controller.");
+ lprintf(LOG_NOTICE,
+" firmware");
+ lprintf(LOG_NOTICE,
+"rollbackstatus - Query the rollback status.");
+ lprintf(LOG_NOTICE,
+"");
+ lprintf(LOG_NOTICE,
+"selftestresult - Query the self test results.\n");
+}
+
+int
+ipmi_hpmfwupg_main(struct ipmi_intf *intf, int argc, char **argv)
+{
+ int rc = HPMFWUPG_SUCCESS;
+ int activateFlag = 0x00;
+ int componentMask = 0;
+ int componentId = 0;
+ int option = 0;
+
+ lprintf(LOG_DEBUG,"ipmi_hpmfwupg_main()");
+ lprintf(LOG_NOTICE, "\nPICMG HPM.1 Upgrade Agent %d.%d.%d: \n",
+ HPMFWUPG_VERSION_MAJOR, HPMFWUPG_VERSION_MINOR,
+ HPMFWUPG_VERSION_SUBMINOR);
+ if (argc < 1) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ HpmfwupgPrintUsage();
+ return HPMFWUPG_ERROR;
+ }
+ if (strcmp(argv[0], "help") == 0) {
+ HpmfwupgPrintUsage();
+ return HPMFWUPG_SUCCESS;
+ } else if ((strcmp(argv[0], "check") == 0)) {
+ /* hpm check */
+ if (argv[1] == NULL) {
+ rc = HpmfwupgTargetCheck(intf,VIEW_MODE);
+ } else {
+ /* hpm check <filename> */
+ rc = HpmfwupgTargetCheck(intf,0);
+ if (rc == HPMFWUPG_SUCCESS) {
+ rc = HpmfwupgUpgrade(intf, argv[1], 0,
+ 0, VIEW_MODE);
+ }
+ }
+ } else if (strcmp(argv[0], "upgrade") == 0) {
+ int i =0;
+ for (i=1; i< argc ; i++) {
+ if (strcmp(argv[i],"activate") == 0) {
+ activateFlag = 1;
+ }
+ /* hpm upgrade <filename> force */
+ if (strcmp(argv[i],"force") == 0) {
+ option |= FORCE_MODE;
+ }
+ /* hpm upgrade <filename> component <comp Id> */
+ if (strcmp(argv[i],"component") == 0) {
+ if (i+1 < argc) {
+ /* Error Checking */
+ if (str2int(argv[i+1], &componentId) != 0
+ || componentId < 0
+ || componentId > HPMFWUPG_COMPONENT_ID_MAX) {
+ lprintf(LOG_ERR,
+ "Given Component ID '%s' is invalid.",
+ argv[i+1]);
+ lprintf(LOG_ERR,
+ "Valid Compoment ID is: <0..7>");
+ return HPMFWUPG_ERROR;
+ }
+ if( verbose ) {
+ lprintf(LOG_NOTICE,
+ "Component Id %d provided",
+ componentId );
+ }
+ componentMask |= 1 << componentId;
+ } else {
+ /* That indicates the user has
+ * given component on console but
+ * not given any ID
+ */
+ lprintf(LOG_NOTICE,
+ "No component Id provided\n");
+ return HPMFWUPG_ERROR;
+ }
+ }
+ if (strcmp(argv[i],"debug") == 0) {
+ option |= DEBUG_MODE;
+ }
+ }
+ rc = HpmfwupgTargetCheck(intf, 0);
+ if (rc == HPMFWUPG_SUCCESS) {
+ /* Call the Upgrade function to start the upgrade */
+ rc = HpmfwupgUpgrade(intf, argv[1], activateFlag,
+ componentMask, option);
+ }
+ } else if (strcmp(argv[0], "compare") == 0) {
+ int i = 0;
+ for (i=1; i< argc; i++) {
+ /* hpm compare <file> [component x...] */
+ if (strcmp(argv[i],"component") == 0) {
+ if (i+1 < argc) {
+ /* Error Checking */
+ if (str2int(argv[i+1], &componentId) != 0
+ || componentId < 0
+ || componentId > HPMFWUPG_COMPONENT_ID_MAX) {
+ lprintf(LOG_ERR,
+ "Given Component ID '%s' is invalid.",
+ argv[i+1]);
+ lprintf(LOG_ERR,
+ "Valid Compoment ID is: <0..7>");
+ return HPMFWUPG_ERROR;
+ }
+ if( verbose ) {
+ lprintf(LOG_NOTICE,
+ "Component Id %d provided",
+ componentId);
+ }
+ componentMask|= 1 << componentId;
+ } else {
+ /* That indicates the user
+ * has given component on
+ * console but not
+ * given any ID
+ */
+ lprintf(LOG_NOTICE,
+ "No component Id provided\n");
+ return HPMFWUPG_ERROR;
+ }
+ } else if (strcmp(argv[i],"debug") == 0) {
+ option|= DEBUG_MODE;
+ }
+ }
+ option|= (COMPARE_MODE);
+ rc = HpmfwupgTargetCheck(intf, 0);
+ if (rc == HPMFWUPG_SUCCESS) {
+ rc = HpmfwupgUpgrade(intf, argv[1], 0,
+ componentMask, option);
+ }
+ } else if ((argc >= 1) && (strcmp(argv[0], "activate") == 0)) {
+ struct HpmfwupgActivateFirmwareCtx cmdCtx;
+ if ((argc == 2) && (strcmp(argv[1], "norollback") == 0)) {
+ cmdCtx.req.rollback_override = 1;
+ } else {
+ cmdCtx.req.rollback_override = 0;
+ }
+ rc = HpmfwupgActivateFirmware(intf, &cmdCtx, NULL);
+ } else if ((argc == 1) && (strcmp(argv[0], "targetcap") == 0)) {
+ struct HpmfwupgGetTargetUpgCapabilitiesCtx cmdCtx;
+ verbose++;
+ rc = HpmfwupgGetTargetUpgCapabilities(intf, &cmdCtx);
+ } else if ((argc == 3) && (strcmp(argv[0], "compprop") == 0)) {
+ struct HpmfwupgGetComponentPropertiesCtx cmdCtx;
+ if (str2uchar(argv[1], &(cmdCtx.req.componentId)) != 0
+ || cmdCtx.req.componentId > 7) {
+ lprintf(LOG_ERR,
+ "Given Component ID '%s' is invalid.",
+ argv[1]);
+ lprintf(LOG_ERR,
+ "Valid Compoment ID is: <0..7>");
+ return (-1);
+ }
+ if (str2uchar(argv[2], &(cmdCtx.req.selector)) != 0
+ || cmdCtx.req.selector > 4) {
+ lprintf(LOG_ERR,
+ "Given Properties selector '%s' is invalid.",
+ argv[2]);
+ lprintf(LOG_ERR,
+ "Valid Properties selector is: <0..4>");
+ return (-1);
+ }
+ verbose++;
+ rc = HpmfwupgGetComponentProperties(intf, &cmdCtx);
+ } else if ((argc == 1) && (strcmp(argv[0], "abort") == 0)) {
+ struct HpmfwupgAbortUpgradeCtx cmdCtx;
+ verbose++;
+ rc = HpmfwupgAbortUpgrade(intf, &cmdCtx);
+ } else if ((argc == 1) && (strcmp(argv[0], "upgstatus") == 0)) {
+ struct HpmfwupgGetUpgradeStatusCtx cmdCtx;
+ verbose++;
+ rc = HpmfwupgGetUpgradeStatus(intf, &cmdCtx, NULL, 0);
+ } else if ((argc == 1) && (strcmp(argv[0], "rollback") == 0)) {
+ struct HpmfwupgManualFirmwareRollbackCtx cmdCtx;
+ verbose++;
+ rc = HpmfwupgManualFirmwareRollback(intf, &cmdCtx);
+ } else if ((argc == 1) && (strcmp(argv[0], "rollbackstatus") == 0)) {
+ struct HpmfwupgQueryRollbackStatusCtx cmdCtx;
+ verbose++;
+ rc = HpmfwupgQueryRollbackStatus(intf, &cmdCtx, NULL);
+ } else if ((argc == 1) && (strcmp(argv[0], "selftestresult") == 0)) {
+ struct HpmfwupgQuerySelftestResultCtx cmdCtx;
+ verbose++;
+ rc = HpmfwupgQuerySelftestResult(intf, &cmdCtx, NULL);
+ } else {
+ lprintf(LOG_ERR, "Invalid HPM command: %s", argv[0]);
+ HpmfwupgPrintUsage();
+ rc = HPMFWUPG_ERROR;
+ }
+ return rc;
+}
+
diff --git a/lib/ipmi_ime.c b/lib/ipmi_ime.c
new file mode 100755
index 0000000..b520ce5
--- /dev/null
+++ b/lib/ipmi_ime.c
@@ -0,0 +1,1044 @@
+/*
+ * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved.
+ *
+ * Base on code from
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/****************************************************************************
+*
+* Copyright (c) 2009 Kontron Canada, Inc. All Rights Reserved.
+*
+* IME
+* Intel Manageability Engine
+* Firmware Update Agent
+*
+* The ME is an IPMI-enabled component included in Intel(R) Next Generation
+* Server Chipset Nehalem-EP platforms.
+*
+* These are a few synonyms for the ME :
+*
+* - Dynamic Power Node Manager
+* - Intelligent Power Node Manager
+*
+* Consult Intel litterature for more information on this technology.
+*
+* The ME firmware resides on the platform boot flash and contains read only
+* boot code for the ME as well as boot image redundancy support.
+*
+* This module implements an Upgrade Agent for the ME firwmare. Because the ME
+* implements IPMI command handling, the agent speaks directly to the ME. In other
+* words, in order the reach the ME, the BMC must implement IPMB bridging.
+*
+* The update is done through IPMI (this is IPMITOOL right !), not HECI.
+*
+* Example: ME available at address 0x88 on IPMI channel 8:
+* ipmitool -m 0x20 -t 0x88 -b 8 ime info
+*
+* !! WARNING - You MUST use an image provided by your board vendor. - WARNING !!
+*
+* author:
+* Jean-Michel.Audet@ca.kontron.com
+* Francois.Isabelle@ca.kontron.com
+*
+*****************************************************************************/
+/*
+ * HISTORY
+ * ===========================================================================
+ * 2009-04-20
+ *
+ * First public release of Kontron
+ *
+*/
+#include <ipmitool/ipmi_ime.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_strings.h>
+
+
+#undef OUTPUT_DEBUG
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+static const int IME_SUCCESS = 0;
+static const int IME_ERROR = -1;
+static const int IME_RESTART = -2;
+
+#define IME_UPGRADE_BUFFER_SIZE 22
+#define IME_RETRY_COUNT 5
+
+typedef struct ImeUpdateImageCtx
+{
+ uint32_t size;
+ uint8_t * pData;
+ uint8_t crc8;
+}tImeUpdateImageCtx;
+
+typedef enum eImeState
+{
+ IME_STATE_IDLE = 0,
+ IME_STATE_UPDATE_REQUESTED = 1,
+ IME_STATE_UPDATE_IN_PROGRESS = 2,
+ IME_STATE_SUCCESS = 3,
+ IME_STATE_FAILED = 4,
+ IME_STATE_ROLLED_BACK = 5,
+ IME_STATE_ABORTED = 6,
+ IME_STATE_INIT_FAILED = 7
+} tImeStateEnum;
+
+
+typedef enum tImeUpdateType
+{
+ IME_UPDTYPE_NORMAL = 1,
+ IME_UPDTYPE_MANUAL_ROLLBACK = 3,
+ IME_UPDTYPE_ABORT = 4
+} tImeUpdateType;
+
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+typedef struct sImeStatus {
+ uint8_t image_status;
+ tImeStateEnum update_state;
+ uint8_t update_attempt_status;
+ uint8_t rollback_attempt_status;
+ uint8_t update_type;
+ uint8_t dependent_flag;
+ uint8_t free_area_size[4];
+} ATTRIBUTE_PACKING tImeStatus ;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(0)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+typedef struct sImeCaps {
+ uint8_t area_supported;
+ uint8_t special_caps;
+} ATTRIBUTE_PACKING tImeCaps ;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(0)
+#endif
+
+
+static void ImePrintUsage(void);
+static int ImeGetInfo(struct ipmi_intf *intf);
+static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename);
+static int ImeManualRollback(struct ipmi_intf *intf);
+static int ImeUpdatePrepare(struct ipmi_intf *intf);
+static int ImeUpdateOpenArea(struct ipmi_intf *intf);
+static int ImeUpdateWriteArea(
+ struct ipmi_intf *intf,
+ uint8_t sequence,
+ uint8_t length,
+ uint8_t * pBuf
+ );
+static int ImeUpdateCloseArea(
+ struct ipmi_intf *intf,
+ uint32_t size,
+ uint16_t checksum
+ );
+
+static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus);
+static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps );
+static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type);
+
+static int ImeImageCtxFromFile(
+ char * imageFilename,
+ tImeUpdateImageCtx * pImageCtx);
+static int ImeUpdateShowStatus(struct ipmi_intf *intf);
+
+static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf );
+
+
+static int ImeGetInfo(struct ipmi_intf *intf)
+{
+ int rc = IME_ERROR;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct ipm_devid_rsp *devid;
+ const char *product=NULL;
+ tImeStatus status;
+ tImeCaps caps;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Device ID command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Device ID command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ devid = (struct ipm_devid_rsp *) rsp->data;
+
+ lprintf(LOG_DEBUG,"Device ID : %i", devid->device_id);
+ lprintf(LOG_DEBUG,"Device Revision : %i",
+ devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK);
+
+ if(
+ (devid->device_id == 0)
+ &&
+ ((devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK) == 0)
+ &&
+ (
+ (devid->manufacturer_id[0] == 0x57) // Intel
+ &&
+ (devid->manufacturer_id[1] == 0x01) // Intel
+ &&
+ (devid->manufacturer_id[2] == 0x00) // Intel
+ )
+ &&
+ (
+ (devid->product_id[1] == 0x0b)
+ &&
+ (devid->product_id[0] == 0x00)
+ )
+ )
+ {
+ rc = IME_SUCCESS;
+ printf("Manufacturer Name : %s\n",
+ val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
+ ipmi_oem_info) );
+
+ printf("Product ID : %u (0x%02x%02x)\n",
+ buf2short((uint8_t *)(devid->product_id)),
+ devid->product_id[1], devid->product_id[0]);
+
+ product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
+ (devid->product_id[1]<<8)+devid->product_id[0],
+ ipmi_oem_product_info);
+
+ if (product!=NULL)
+ {
+ printf("Product Name : %s\n", product);
+ }
+
+ printf("Intel ME Firmware Revision : %x.%02x.%02x.%x%x%x.%x\n",
+ ((devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK ) ),
+ ((devid->fw_rev2 ) >> 4),
+ ((devid->fw_rev2 ) & 0x0f),
+ ((devid->aux_fw_rev[1] ) >> 4),
+ ((devid->aux_fw_rev[1] ) & 0x0f),
+ ((devid->aux_fw_rev[2] ) >> 4),
+ ((devid->aux_fw_rev[2] ) & 0x0f)
+ );
+
+ printf("SPS FW IPMI cmd version : %x.%x\n",
+ devid->aux_fw_rev[0] >> 4,
+ devid->aux_fw_rev[0] & 0x0f);
+
+ lprintf(LOG_DEBUG,"Flags: %xh", devid->aux_fw_rev[3]);
+
+ printf("Current Image Type : ");
+ switch( (devid->aux_fw_rev[3] & 0x03) )
+ {
+ case 0:
+ printf("Recovery\n");
+ break;
+
+ case 1:
+ printf("Operational Image 1\n");
+ break;
+
+ case 2:
+ printf("Operational Image 2\n");
+ break;
+
+ case 3:
+ default:
+ printf("Unknown\n");
+ break;
+ }
+ }
+ else
+ {
+ printf("Supported ME not found\n");
+ }
+
+ if(rc == IME_SUCCESS)
+ {
+ rc = ImeUpdateGetStatus(intf, &status);
+
+ if(rc == IME_SUCCESS)
+ {
+ rc = ImeUpdateGetCapabilities(intf, &caps);
+ }
+
+ }
+
+ if(rc == IME_SUCCESS)
+ {
+ uint8_t newImage = ((status.image_status >> 1) & 0x01);
+ uint8_t rollImage = ((status.image_status >> 2) & 0x01);
+ uint8_t runArea = ((status.image_status >> 3) & 0x03);
+ uint8_t rollSup = ((caps.special_caps >> 0) & 0x01);
+ uint8_t recovSup = ((caps.special_caps >> 1) & 0x01);
+
+ uint8_t operSup = ((caps.area_supported >> 1) & 0x01);
+ uint8_t piaSup = ((caps.area_supported >> 2) & 0x01);
+ uint8_t sdrSup = ((caps.area_supported >> 3) & 0x01);
+
+ printf("\nSupported Area\n");
+ printf(" Operation Code : %s\n", (operSup ? "Supported" : "Unsupported"));
+ printf(" PIA : %s\n", (piaSup ? "Supported" : "Unsupported"));
+ printf(" SDR : %s\n", (sdrSup ? "Supported" : "Unsupported"));
+
+ printf("\nSpecial Capabilities\n");
+ printf(" Rollback : %s\n", (rollSup ? "Supported" : "Unsupported"));
+ printf(" Recovery : %s\n", (recovSup ? "Supported" : "Unsupported"));
+
+ printf("\nImage Status\n");
+ printf(" Staging (new) : %s\n", (newImage ? "Valid" : "Invalid"));
+ printf(" Rollback : %s\n", (rollImage ? "Valid" : "Invalid"));
+ if(runArea == 0)
+ printf(" Running Image Area : CODE\n");
+ else
+ printf(" Running Image Area : CODE%d\n", runArea);
+
+ }
+
+ return rc;
+}
+
+
+static int ImeUpgrade(struct ipmi_intf *intf, char* imageFilename)
+{
+ int rc = IME_SUCCESS;
+ tImeUpdateImageCtx imgCtx;
+ tImeStatus imeStatus;
+ time_t start,end,current;
+
+ time(&start);
+
+ memset(&imgCtx, 0, sizeof(tImeUpdateImageCtx));
+
+ rc = ImeImageCtxFromFile(imageFilename, &imgCtx);
+
+ if(
+ (rc == IME_ERROR) ||
+ (imgCtx.pData == NULL) ||
+ (imgCtx.size == 0)
+ )
+ {
+ return IME_ERROR;
+ }
+
+ ImeUpdateGetStatus(intf,&imeStatus);
+
+ if(rc == IME_SUCCESS)
+ {
+ rc = ImeUpdatePrepare(intf);
+ ImeUpdateGetStatus(intf,&imeStatus);
+ }
+
+ if(
+ (rc == IME_SUCCESS) &&
+ (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED)
+ )
+ {
+ rc = ImeUpdateOpenArea(intf);
+ ImeUpdateGetStatus(intf,&imeStatus);
+ }
+ else if(rc == IME_SUCCESS)
+ {
+ lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state);
+ rc = IME_ERROR;
+ }
+
+
+ if(
+ (rc == IME_SUCCESS) &&
+ (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS)
+ )
+ {
+ uint8_t sequence = 0;
+ uint32_t counter = 0;
+ uint8_t retry = 0;
+ uint8_t shownPercent = 0xff;
+
+ while(
+ (counter < imgCtx.size) &&
+ (rc == IME_SUCCESS) &&
+ (retry < IME_RETRY_COUNT)
+ )
+ {
+ uint8_t length = IME_UPGRADE_BUFFER_SIZE;
+ uint8_t currentPercent;
+
+ if( (imgCtx.size - counter) < IME_UPGRADE_BUFFER_SIZE )
+ {
+ length = (imgCtx.size - counter);
+ }
+
+ rc = ImeUpdateWriteArea(intf,sequence,length,&imgCtx.pData[counter]);
+
+ /*
+ As per the flowchart Intel Dynamic Power Node Manager 1.5 IPMI Iface
+ page 65
+ We shall send the GetStatus command each time following a write area
+ but this add too much time to the upgrade
+ */
+ /* ImeUpdateGetStatus(intf,&imeStatus); */
+ counter += length;
+ sequence ++;
+
+
+ currentPercent = ((float)counter/imgCtx.size)*100;
+
+ if(currentPercent != shownPercent)
+ {
+ uint16_t timeElapsedSecond;
+ uint16_t timeRemainingSecond;
+ shownPercent = currentPercent;
+ printf("Percent: %02i, ", shownPercent);
+ time(&current);
+ timeElapsedSecond = (current-start) + ((current-start)%60);
+ printf("Elapsed time %02ld:%02ld\r",((current-start)/60), ((current-start)%60));
+ fflush(stdout);
+
+ }
+ }
+ ImeUpdateGetStatus(intf,&imeStatus);
+ printf("\n");
+ }
+ else if(rc == IME_SUCCESS)
+ {
+ lprintf(LOG_ERROR,"ME state error (%i), aborting", imeStatus.update_state);
+ rc = IME_ERROR;
+ }
+
+ if(
+ (rc == IME_SUCCESS) &&
+ (imeStatus.update_state == IME_STATE_UPDATE_IN_PROGRESS)
+ )
+ {
+ rc = ImeUpdateCloseArea(intf, imgCtx.size, imgCtx.crc8);
+ ImeUpdateGetStatus(intf,&imeStatus);
+ }
+ else if(rc == IME_SUCCESS)
+ {
+ lprintf(LOG_ERROR,"ME state error, aborting");
+ rc = IME_ERROR;
+ }
+
+ if(
+ (rc == IME_SUCCESS) &&
+ (imeStatus.update_state == IME_STATE_UPDATE_REQUESTED)
+ )
+ {
+ printf("UpdateCompleted, Activate now\n");
+ rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_NORMAL);
+ ImeUpdateGetStatus(intf,&imeStatus);
+ }
+ else if(rc == IME_SUCCESS)
+ {
+ lprintf(LOG_ERROR,"ME state error, aborting");
+ rc = IME_ERROR;
+ }
+
+ if(
+ (rc == IME_SUCCESS) &&
+ (imeStatus.update_state == IME_STATE_SUCCESS)
+ )
+ {
+ time(&end);
+ printf("Update Completed in %02ld:%02ld\n",(end-start)/60, (end-start)%60);
+ }
+ else
+ {
+ time(&end);
+ printf("Update Error\n");
+ printf("\nTime Taken %02ld:%02ld\n",(end-start)/60, (end-start)%60);
+ }
+
+ return rc;
+}
+
+
+static int ImeUpdatePrepare(struct ipmi_intf *intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ #ifdef OUTPUT_DEBUG
+ printf("ImeUpdatePrepare\n");
+ #endif
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA0;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
+ return IME_SUCCESS;
+}
+
+static int ImeUpdateOpenArea(struct ipmi_intf *intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t buffer[ 2 ];
+
+ #ifdef OUTPUT_DEBUG
+ printf("ImeUpdateOpenArea\n");
+ #endif
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA1;
+
+ buffer[0] = 0x01; // Area Type : Operational code
+ buffer[1] = 0x00; // Reserved : 0
+ req.msg.data = buffer;
+
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "UpdateOpenArea command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "UpdateOpenArea command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "UpdateOpenArea command succeed");
+ return IME_SUCCESS;
+}
+
+static int ImeUpdateWriteArea(
+ struct ipmi_intf *intf,
+ uint8_t sequence,
+ uint8_t length,
+ uint8_t * pBuf
+ )
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t buffer[ IME_UPGRADE_BUFFER_SIZE + 1 ];
+
+// printf("ImeUpdateWriteArea %i\n", sequence);
+
+ if(length > IME_UPGRADE_BUFFER_SIZE)
+ return IME_ERROR;
+
+ buffer[0] = sequence;
+ memcpy(&buffer[1], pBuf, length);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA2;
+ req.msg.data = buffer;
+ req.msg.data_len = length + 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "UpdateWriteArea command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "UpdateWriteArea command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ if( rsp->ccode == 0x80) // restart operation
+ return IME_RESTART;
+ else
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "UpdateWriteArea command succeed");
+ return IME_SUCCESS;
+}
+
+static int ImeUpdateCloseArea(
+ struct ipmi_intf *intf,
+ uint32_t size,
+ uint16_t checksum
+ )
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t length = sizeof( uint32_t ) + sizeof( uint16_t );
+ uint8_t buffer[ sizeof( uint32_t ) + sizeof( uint16_t ) ];
+
+ #ifdef OUTPUT_DEBUG
+ printf( "ImeUpdateCloseArea\n");
+ #endif
+
+ buffer[0] = (uint8_t)((size & 0x000000ff) >> 0);
+ buffer[1] = (uint8_t)((size & 0x0000ff00) >> 8);
+ buffer[2] = (uint8_t)((size & 0x00ff0000) >> 16);
+ buffer[3] = (uint8_t)((size & 0xff000000) >> 24);
+
+ buffer[4] = (uint8_t)((checksum & 0x00ff) >> 0);
+ buffer[5] = (uint8_t)((checksum & 0xff00) >> 8);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA3;
+ req.msg.data = buffer;
+ req.msg.data_len = length;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "UpdateCloseArea command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "UpdateCloseArea command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "UpdateCloseArea command succeed");
+ return IME_SUCCESS;
+}
+
+static int ImeUpdateGetStatus(struct ipmi_intf *intf, tImeStatus *pStatus )
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ tImeStatus *pGetStatus;
+
+ memset(pStatus, 0, sizeof(tImeStatus));
+ pStatus->update_state = IME_STATE_ABORTED;
+
+
+ #ifdef OUTPUT_DEBUG
+ printf("ImeUpdateGetStatus: ");
+ #endif
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA6;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
+
+ pGetStatus = (tImeStatus *) rsp->data;
+
+ memcpy( pStatus, pGetStatus, sizeof(tImeStatus));
+
+ #ifdef OUTPUT_DEBUG
+ printf("%x - ", pStatus->updateState);
+
+ switch( pStatus->update_state )
+ {
+ case IME_STATE_IDLE:
+ printf("IDLE\n");
+ break;
+ case IME_STATE_UPDATE_REQUESTED:
+ printf("Update Requested\n");
+ break;
+ case IME_STATE_UPDATE_IN_PROGRESS:
+ printf("Update in Progress\n");
+ break;
+ case IME_STATE_SUCCESS:
+ printf("Update Success\n");
+ break;
+ case IME_STATE_FAILED:
+ printf("Update Failed\n");
+ break;
+ case IME_STATE_ROLLED_BACK:
+ printf("Update Rolled Back\n");
+ break;
+ case IME_STATE_ABORTED:
+ printf("Update Aborted\n");
+ break;
+ case IME_STATE_INIT_FAILED:
+ printf("Update Init Failed\n");
+ break;
+ default:
+ printf("Unknown, reserved\n");
+ break;
+ }
+ #endif
+
+ return IME_SUCCESS;
+}
+
+static int ImeUpdateGetCapabilities(struct ipmi_intf *intf, tImeCaps *pCaps )
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ tImeCaps * pGetCaps;
+
+ memset(pCaps, 0, sizeof(tImeCaps));
+
+
+ #ifdef OUTPUT_DEBUG
+ printf("ImeUpdateGetStatus: ");
+ #endif
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA7;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
+
+ pGetCaps = (tImeCaps *) rsp->data;
+
+ memcpy( pCaps, pGetCaps, sizeof(tImeCaps));
+
+ return IME_SUCCESS;
+}
+
+
+static int ImeUpdateRegisterUpdate(struct ipmi_intf *intf, tImeUpdateType type)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t buffer[ 2 ];
+
+ #ifdef OUTPUT_DEBUG
+ printf( "ImeUpdateRegisterUpdate\n");
+ #endif
+
+ buffer[0] = type; // Normal Update
+ buffer[1] = 0; // Flags, reserved
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA4;
+ req.msg.data = buffer;
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "ImeUpdateRegisterUpdate command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "ImeUpdateRegisterUpdate command succeed");
+ return IME_SUCCESS;
+}
+
+
+
+
+static int ImeUpdateShowStatus(struct ipmi_intf *intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ tImeStatus *pStatus;
+
+ printf("ImeUpdateGetStatus: ");
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x30; // OEM NetFn
+ req.msg.cmd = 0xA6;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed");
+ return IME_ERROR;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "UpdatePrepare command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return IME_ERROR;
+ }
+
+ lprintf(LOG_DEBUG, "UpdatePrepare command succeed");
+
+ pStatus = (tImeStatus *) rsp->data ;
+
+
+ printf("image_status: %x - ", pStatus->image_status);
+
+ printf("update_state: %x - ", pStatus->update_state);
+
+ switch( pStatus->update_state )
+ {
+ case IME_STATE_IDLE:
+ printf("IDLE\n");
+ break;
+ case IME_STATE_UPDATE_REQUESTED:
+ printf("Update Requested\n");
+ break;
+ case IME_STATE_UPDATE_IN_PROGRESS:
+ printf("Update in Progress\n");
+ break;
+ case IME_STATE_SUCCESS:
+ printf("Update Success\n");
+ break;
+ case IME_STATE_FAILED:
+ printf("Update Failed\n");
+ break;
+ case IME_STATE_ROLLED_BACK:
+ printf("Update Rolled Back\n");
+ break;
+ case IME_STATE_ABORTED:
+ printf("Update Aborted\n");
+ break;
+ case IME_STATE_INIT_FAILED:
+ printf("Update Init Failed\n");
+ break;
+ default:
+ printf("Unknown, reserved\n");
+ break;
+ }
+ printf("update_attempt_status : %x\n", pStatus->update_attempt_status);
+ printf("rollback_attempt_status: %x\n", pStatus->rollback_attempt_status);
+ printf("update_type : %x\n", pStatus->update_type);
+ printf("dependent_flag : %x\n", pStatus->dependent_flag);
+ printf("free_area_size : %x\n", pStatus->free_area_size[0]);
+ printf(" : %x\n", pStatus->free_area_size[1]);
+ printf(" : %x\n", pStatus->free_area_size[2]);
+ printf(" : %x\n", pStatus->free_area_size[3]);
+
+ return IME_SUCCESS;
+}
+
+
+static int ImeImageCtxFromFile(
+ char* imageFilename,
+ tImeUpdateImageCtx * pImageCtx
+ )
+{
+ int rc = IME_SUCCESS;
+ FILE* pImageFile = fopen(imageFilename, "rb");
+
+ if ( pImageFile == NULL )
+ {
+ lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename);
+ rc = IME_ERROR;
+ }
+
+ if ( rc == IME_SUCCESS )
+ {
+ /* Get the raw data in file */
+ fseek(pImageFile, 0, SEEK_END);
+ pImageCtx->size = ftell(pImageFile);
+ if (pImageCtx->size <= 0) {
+ if (pImageCtx->size < 0)
+ lprintf(LOG_ERR, "Error seeking %s. %s\n", imageFilename, strerror(errno));
+ rc = IME_ERROR;
+ fclose(pImageFile);
+ return rc;
+ }
+ pImageCtx->pData = malloc(sizeof(unsigned char)*pImageCtx->size);
+ rewind(pImageFile);
+
+ if ( pImageCtx->pData != NULL )
+ {
+ if (pImageCtx->size < fread(pImageCtx->pData, sizeof(unsigned char),
+ pImageCtx->size, pImageFile))
+ rc = IME_ERROR;
+ }
+ else
+ {
+ rc = IME_ERROR;
+ }
+ }
+
+ // Calculate checksum CRC8
+ if ( rc == IME_SUCCESS )
+ {
+ pImageCtx->crc8 = ImeCrc8(pImageCtx->size, pImageCtx->pData);
+ }
+
+
+ if( pImageFile != NULL)
+ {
+ fclose(pImageFile);
+ }
+
+ return rc;
+}
+
+static uint8_t ImeCrc8( uint32_t length, uint8_t * pBuf )
+{
+ uint8_t crc = 0;
+ uint32_t bufCount;
+
+ for ( bufCount = 0; bufCount < length; bufCount++ )
+ {
+ uint8_t count;
+
+ crc = crc ^ pBuf[bufCount];
+
+ for ( count = 0; count < 8; count++ )
+ {
+ if (( crc & 0x80 ) != 0 )
+ {
+ crc <<= 1;
+ crc ^= 0x07;
+ }
+ else
+ {
+ crc <<= 1;
+ }
+ }
+ }
+
+ lprintf(LOG_DEBUG,"CRC8: %02xh\n", crc);
+ return crc;
+}
+
+
+static int ImeManualRollback(struct ipmi_intf *intf)
+{
+ int rc = IME_SUCCESS;
+ tImeStatus imeStatus;
+ time_t start,end,current;
+
+
+ rc = ImeUpdateRegisterUpdate(intf, IME_UPDTYPE_MANUAL_ROLLBACK);
+ ImeUpdateGetStatus(intf,&imeStatus);
+
+
+ if(
+ (rc == IME_SUCCESS) &&
+ (imeStatus.update_state == IME_STATE_ROLLED_BACK)
+ )
+ {
+ printf("Manual Rollback Succeed\n");
+ return IME_SUCCESS;
+ }
+ else
+ {
+ printf("Manual Rollback Completed With Error\n");
+ return IME_ERROR;
+ }
+}
+
+
+
+static void ImePrintUsage(void)
+{
+ lprintf(LOG_NOTICE,"help - This help menu");
+ lprintf(LOG_NOTICE,"info - Information about the present Intel ME");
+ lprintf(LOG_NOTICE,"update <file> - Upgrade the ME firmware from received image <file>");
+ lprintf(LOG_NOTICE,"rollback - Manual Rollback ME");
+// lprintf(LOG_NOTICE,"rollback - Rollback ME Firmware");
+}
+
+
+
+int ipmi_ime_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = IME_SUCCESS;
+
+ lprintf(LOG_DEBUG,"ipmi_ime_main()");
+
+
+ if ( (argc == 0) || (strcmp(argv[0], "help") == 0) )
+ {
+ ImePrintUsage();
+ }
+ else if ( (argc == 0) || (strcmp(argv[0], "info") == 0) )
+ {
+ rc = ImeGetInfo(intf);
+ }
+ else if ( strcmp(argv[0], "update") == 0)
+ {
+ if(argc == 2)
+ {
+ lprintf(LOG_NOTICE,"Update using file: %s", argv[1]);
+ rc = ImeUpgrade(intf, argv[1]);
+ }
+ else
+ {
+ lprintf(LOG_ERROR,"File must be provided with this option, see help\n");
+ rc = IME_ERROR;
+ }
+ }
+ else if ( (argc == 0) || (strcmp(argv[0], "rollback") == 0) )
+ {
+ rc = ImeManualRollback(intf);
+ }
+ else
+ {
+ ImePrintUsage();
+ }
+
+ return rc;
+}
+
+
+
diff --git a/lib/ipmi_isol.c b/lib/ipmi_isol.c
new file mode 100644
index 0000000..0338e36
--- /dev/null
+++ b/lib/ipmi_isol.c
@@ -0,0 +1,828 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+
+
+#include <termios.h>
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_isol.h>
+
+static struct termios _saved_tio;
+static int _in_raw_mode = 0;
+
+extern int verbose;
+
+#define ISOL_ESCAPE_CHARACTER '~'
+
+/*
+ * ipmi_get_isol_info
+ */
+static int ipmi_get_isol_info(struct ipmi_intf * intf,
+ struct isol_config_parameters * params)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char data[6];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_ISOL;
+ req.msg.cmd = GET_ISOL_CONFIG;
+ req.msg.data = data;
+ req.msg.data_len = 4;
+
+ /* GET ISOL ENABLED CONFIG */
+
+ memset(data, 0, 6);
+ data[0] = 0x00;
+ data[1] = ISOL_ENABLE_PARAM;
+ data[2] = 0x00; /* block */
+ data[3] = 0x00; /* selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in Get ISOL Config Command");
+ return -1;
+ }
+ if (rsp->ccode == 0xc1) {
+ lprintf(LOG_ERR, "IPMI v1.5 Serial Over Lan (ISOL) not supported!");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ params->enabled = rsp->data[1];
+
+ /* GET ISOL AUTHENTICATON CONFIG */
+
+ memset(data, 0, 6);
+ data[0] = 0x00;
+ data[1] = ISOL_AUTHENTICATION_PARAM;
+ data[2] = 0x00; /* block */
+ data[3] = 0x00; /* selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in Get ISOL Config Command");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ params->privilege_level = rsp->data[1];
+
+ /* GET ISOL BAUD RATE CONFIG */
+
+ memset(data, 0, 6);
+ data[0] = 0x00;
+ data[1] = ISOL_BAUD_RATE_PARAM;
+ data[2] = 0x00; /* block */
+ data[3] = 0x00; /* selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error in Get ISOL Config Command");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ params->bit_rate = rsp->data[1];
+
+ return 0;
+}
+
+static int ipmi_print_isol_info(struct ipmi_intf * intf)
+{
+ struct isol_config_parameters params = {0};
+ if (ipmi_get_isol_info(intf, &params))
+ return -1;
+
+ if (csv_output)
+ {
+ printf("%s,", (params.enabled & 0x1)?"true": "false");
+ printf("%s,",
+ val2str((params.privilege_level & 0xf), ipmi_privlvl_vals));
+ printf("%s,",
+ val2str((params.bit_rate & 0xf), ipmi_bit_rate_vals));
+ }
+ else
+ {
+ printf("Enabled : %s\n",
+ (params.enabled & 0x1)?"true": "false");
+ printf("Privilege Level : %s\n",
+ val2str((params.privilege_level & 0xf), ipmi_privlvl_vals));
+ printf("Bit Rate (kbps) : %s\n",
+ val2str((params.bit_rate & 0xf), ipmi_bit_rate_vals));
+ }
+
+ return 0;
+}
+
+static int ipmi_isol_set_param(struct ipmi_intf * intf,
+ const char *param,
+ const char *value)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char data[6];
+ struct isol_config_parameters params = {0};
+
+ /* We need other values to complete the request */
+ if (ipmi_get_isol_info(intf, &params))
+ return -1;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_ISOL;
+ req.msg.cmd = SET_ISOL_CONFIG;
+ req.msg.data = data;
+ req.msg.data_len = 3;
+
+ memset(data, 0, 6);
+
+ /*
+ * enabled
+ */
+ if (strcmp(param, "enabled") == 0)
+ {
+ data[1] = ISOL_ENABLE_PARAM;
+ if (strcmp(value, "true") == 0)
+ data[2] = 0x01;
+ else if (strcmp(value, "false") == 0)
+ data[2] = 0x00;
+ else {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ value, param);
+ lprintf(LOG_ERR, "Valid values are true and false");
+ return -1;
+ }
+ }
+
+ /*
+ * privilege-level
+ */
+ else if (strcmp(param, "privilege-level") == 0)
+ {
+ data[1] = ISOL_AUTHENTICATION_PARAM;
+ if (! strcmp(value, "user"))
+ data[2] = 0x02;
+ else if (! strcmp(value, "operator"))
+ data[2] = 0x03;
+ else if (! strcmp(value, "admin"))
+ data[2] = 0x04;
+ else if (! strcmp(value, "oem"))
+ data[2] = 0x05;
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ value, param);
+ lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem");
+ return -1;
+ }
+ /* We need to mask bit7 from the fetched value */
+ data[2] |= (params.privilege_level & 0x80) ? 0x80 : 0x00;
+ }
+
+ /*
+ * bit-rate
+ */
+ else if (strcmp(param, "bit-rate") == 0)
+ {
+ data[1] = ISOL_BAUD_RATE_PARAM;
+ if (strncmp(value, "9.6", 3) == 0) {
+ data[2] = 0x06;
+ }
+ else if (strncmp(value, "19.2", 4) == 0) {
+ data[2] = 0x07;
+ }
+ else if (strncmp(value, "38.4", 4) == 0) {
+ data[2] = 0x08;
+ }
+ else if (strncmp(value, "57.6", 4) == 0) {
+ data[2] = 0x09;
+ }
+ else if (strncmp(value, "115.2", 5) == 0) {
+ data[2] = 0x0A;
+ }
+ else {
+ lprintf(LOG_ERR, "ISOL - Unsupported baud rate: %s", value);
+ lprintf(LOG_ERR, "Valid values are 9.6, 19.2, 38.4, 57.6 and 115.2");
+ return -1;
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Error: invalid ISOL parameter %s", param);
+ return -1;
+ }
+
+
+ /*
+ * Execute the request
+ */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error setting ISOL parameter '%s'", param);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error setting ISOL parameter '%s': %s",
+ param, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+leave_raw_mode(void)
+{
+ if (!_in_raw_mode)
+ return;
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 0;
+}
+
+
+
+static void
+enter_raw_mode(void)
+{
+ struct termios tio;
+ if (tcgetattr(fileno(stdin), &tio) == -1) {
+ perror("tcgetattr");
+ return;
+ }
+ _saved_tio = tio;
+ tio.c_iflag |= IGNPAR;
+ tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF)\
+ ;
+ tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+ // #ifdef IEXTEN
+ tio.c_lflag &= ~IEXTEN;
+ // #endif
+ tio.c_oflag &= ~OPOST;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 1;
+}
+
+
+static void
+sendBreak(struct ipmi_intf * intf)
+{
+ struct ipmi_v2_payload v2_payload;
+
+ memset(&v2_payload, 0, sizeof(v2_payload));
+
+ v2_payload.payload.sol_packet.character_count = 0;
+ v2_payload.payload.sol_packet.generate_break = 1;
+
+ intf->send_sol(intf, &v2_payload);
+}
+
+/*
+ * suspendSelf
+ *
+ * Put ourself in the background
+ *
+ * param bRestoreTty specifies whether we will put our self back
+ * in raw mode when we resume
+ */
+static void
+suspendSelf(int bRestoreTty)
+{
+ leave_raw_mode();
+ kill(getpid(), SIGTSTP);
+
+ if (bRestoreTty)
+ enter_raw_mode();
+}
+
+
+
+/*
+ * printiSolEscapeSequences
+ *
+ * Send some useful documentation to the user
+ */
+static void
+printiSolEscapeSequences(void)
+{
+ printf(
+ "%c?\n\
+ Supported escape sequences:\n\
+ %c. - terminate connection\n\
+ %c^Z - suspend ipmitool\n\
+ %c^X - suspend ipmitool, but don't restore tty on restart\n\
+ %cB - send break\n\
+ %c? - this message\n\
+ %c%c - send the escape character by typing it twice\n\
+ (Note that escapes are only recognized immediately after newline.)\n",
+ ISOL_ESCAPE_CHARACTER,
+ ISOL_ESCAPE_CHARACTER,
+ ISOL_ESCAPE_CHARACTER,
+ ISOL_ESCAPE_CHARACTER,
+ ISOL_ESCAPE_CHARACTER,
+ ISOL_ESCAPE_CHARACTER,
+ ISOL_ESCAPE_CHARACTER,
+ ISOL_ESCAPE_CHARACTER);
+}
+
+
+
+/*
+ * output
+ *
+ * Send the specified data to stdout
+ */
+static void
+output(struct ipmi_rs * rsp)
+{
+ if (rsp)
+ {
+ int i;
+ for (i = 0; i < rsp->data_len; ++i)
+ putc(rsp->data[i], stdout);
+
+ fflush(stdout);
+ }
+}
+
+/*
+ * ipmi_isol_deactivate
+ */
+static int
+ipmi_isol_deactivate(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t data[6];
+ struct isol_config_parameters params;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_ISOL;
+ req.msg.cmd = ACTIVATE_ISOL;
+ req.msg.data = data;
+ req.msg.data_len = 5;
+
+ memset(data, 0, 6);
+ data[0] = 0x00; /* Deactivate */
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ data[5] = 0x00;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error deactivating ISOL");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error deactivating ISOL: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ /* response contain 4 additional bytes : 80 00 32 ff
+ Don't know what to use them for yet... */
+ return 0;
+}
+
+/*
+ * processiSolUserInput
+ *
+ * Act on user input into the ISOL session. The only reason this
+ * is complicated is that we have to process escape sequences.
+ *
+ * return 0 on success
+ * 1 if we should exit
+ * < 0 on error (BMC probably closed the session)
+ */
+static int
+processiSolUserInput(struct ipmi_intf * intf,
+ uint8_t * input,
+ uint16_t buffer_length)
+{
+ static int escape_pending = 0;
+ static int last_was_cr = 1;
+ struct ipmi_v2_payload v2_payload;
+ int length = 0;
+ int retval = 0;
+ char ch;
+ int i;
+
+ memset(&v2_payload, 0, sizeof(v2_payload));
+
+ /*
+ * Our first order of business is to check the input for escape
+ * sequences to act on.
+ */
+ for (i = 0; i < buffer_length; ++i)
+ {
+ ch = input[i];
+
+ if (escape_pending){
+ escape_pending = 0;
+
+ /*
+ * Process a possible escape sequence.
+ */
+ switch (ch) {
+ case '.':
+ printf("%c. [terminated ipmitool]\n", ISOL_ESCAPE_CHARACTER);
+ retval = 1;
+ break;
+ case 'Z' - 64:
+ printf("%c^Z [suspend ipmitool]\n", ISOL_ESCAPE_CHARACTER);
+ suspendSelf(1); /* Restore tty back to raw */
+ continue;
+
+ case 'X' - 64:
+ printf("%c^X [suspend ipmitool]\n", ISOL_ESCAPE_CHARACTER);
+ suspendSelf(0); /* Don't restore to raw mode */
+ continue;
+
+ case 'B':
+ printf("%cb [send break]\n", ISOL_ESCAPE_CHARACTER);
+ sendBreak(intf);
+ continue;
+
+ case '?':
+ printiSolEscapeSequences();
+ continue;
+ default:
+ if (ch != ISOL_ESCAPE_CHARACTER)
+ v2_payload.payload.sol_packet.data[length++] =
+ ISOL_ESCAPE_CHARACTER;
+ v2_payload.payload.sol_packet.data[length++] = ch;
+ }
+ }
+
+ else
+ {
+ if (last_was_cr && (ch == ISOL_ESCAPE_CHARACTER)) {
+ escape_pending = 1;
+ continue;
+ }
+
+ v2_payload.payload.sol_packet.data[length++] = ch;
+ }
+
+
+ /*
+ * Normal character. Record whether it was a newline.
+ */
+ last_was_cr = (ch == '\r' || ch == '\n');
+ }
+
+ /*
+ * If there is anything left to process we dispatch it to the BMC,
+ * send intf->session->sol_data.max_outbound_payload_size bytes
+ * at a time.
+ */
+ if (length)
+ {
+ struct ipmi_rs * rsp;
+
+ v2_payload.payload.sol_packet.flush_outbound = 1; /* Not sure if necessary ? */
+ v2_payload.payload.sol_packet.character_count = length;
+ rsp = intf->send_sol(intf, &v2_payload);
+
+ if (! rsp) {
+ lprintf(LOG_ERR, "Error sending SOL data");
+ retval = -1;
+ }
+
+ /* If the sequence number is set we know we have new data */
+ else if ((rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
+ (rsp->payload.sol_packet.packet_sequence_number))
+ output(rsp);
+ }
+ return retval;
+}
+
+/*
+ * ipmi_isol_red_pill
+ */
+static int
+ipmi_isol_red_pill(struct ipmi_intf * intf)
+{
+ char * buffer;
+ int numRead;
+ int bShouldExit = 0;
+ int bBmcClosedSession = 0;
+ fd_set read_fds;
+ struct timeval tv;
+ int retval;
+ int buffer_size = 255;
+ int timedout = 0;
+
+ buffer = (char*)malloc(buffer_size);
+ if (buffer == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+
+ enter_raw_mode();
+
+ while (! bShouldExit)
+ {
+ FD_ZERO(&read_fds);
+ FD_SET(0, &read_fds);
+ FD_SET(intf->fd, &read_fds);
+
+ /* Wait up to half a second */
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000;
+
+ retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv);
+
+ if (retval)
+ {
+ if (retval == -1)
+ {
+ /* ERROR */
+ perror("select");
+ return -1;
+ }
+
+ timedout = 0;
+
+ /*
+ * Process input from the user
+ */
+ if (FD_ISSET(0, &read_fds))
+ {
+ memset(buffer, 0, buffer_size);
+ numRead = read(fileno(stdin),
+ buffer,
+ buffer_size);
+
+ if (numRead > 0)
+ {
+ int rc = processiSolUserInput(intf, buffer, numRead);
+
+ if (rc)
+ {
+ if (rc < 0)
+ bShouldExit = bBmcClosedSession = 1;
+ else
+ bShouldExit = 1;
+ }
+ }
+ else
+ {
+ bShouldExit = 1;
+ }
+ }
+
+
+ /*
+ * Process input from the BMC
+ */
+ else if (FD_ISSET(intf->fd, &read_fds))
+ {
+ struct ipmi_rs * rs = intf->recv_sol(intf);
+ if (! rs)
+ {
+ bShouldExit = bBmcClosedSession = 1;
+ }
+ else
+ output(rs);
+ }
+
+
+ /*
+ * ERROR in select
+ */
+ else
+ {
+ lprintf(LOG_ERR, "Error: Select returned with nothing to read");
+ bShouldExit = 1;
+ }
+ }
+ else
+ {
+ if ((++timedout) == 20) /* Every 10 seconds we send a keepalive */
+ {
+ intf->keepalive(intf);
+ timedout = 0;
+ }
+ }
+ }
+
+ leave_raw_mode();
+
+ if (bBmcClosedSession)
+ {
+ lprintf(LOG_ERR, "SOL session closed by BMC");
+ }
+ else
+ ipmi_isol_deactivate(intf);
+
+ return 0;
+}
+
+/*
+ * ipmi_isol_activate
+ */
+static int
+ipmi_isol_activate(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t data[6];
+ struct isol_config_parameters params;
+
+ if (ipmi_get_isol_info(intf, &params))
+ return -1;
+
+ if (!(params.enabled & 0x1)) {
+ lprintf(LOG_ERR, "ISOL is not enabled!");
+ return -1;
+ }
+
+ /*
+ * Setup a callback so that the lanplus processing knows what
+ * to do with packets that come unexpectedly (while waiting for
+ * an ACK, perhaps.
+ */
+ intf->session->sol_data.sol_input_handler = output;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_ISOL;
+ req.msg.cmd = ACTIVATE_ISOL;
+ req.msg.data = data;
+ req.msg.data_len = 5;
+
+ memset(data, 0, 6);
+ data[0] = 0x01;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = 0x00;
+ data[5] = 0x00;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (NULL != rsp) {
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 4) {
+ break;
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "in ISOL activation response",
+ rsp->data_len);
+ return -1;
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: ISOL already active on another session");
+ return -1;
+ case 0x81:
+ lprintf(LOG_ERR, "Info: ISOL disabled");
+ return -1;
+ case 0x82:
+ lprintf(LOG_ERR, "Info: ISOL activation limit reached");
+ return -1;
+ default:
+ lprintf(LOG_ERR, "Error activating ISOL: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ } else {
+ lprintf(LOG_ERR, "Error: No response activating ISOL");
+ return -1;
+ }
+
+ /* response contain 4 additional bytes : 80 01 32 ff
+ Don't know what to use them for yet... */
+
+ printf("[SOL Session operational. Use %c? for help]\n",
+ ISOL_ESCAPE_CHARACTER);
+
+ /*
+ * At this point we are good to go with our SOL session. We
+ * need to listen to
+ * 1) STDIN for user input
+ * 2) The FD for incoming SOL packets
+ */
+ if (ipmi_isol_red_pill(intf)) {
+ lprintf(LOG_ERR, "Error in SOL session");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void print_isol_set_usage(void) {
+ lprintf(LOG_NOTICE, "\nISOL set parameters and values: \n");
+ lprintf(LOG_NOTICE, " enabled true | false");
+ lprintf(LOG_NOTICE, " privilege-level user | operator | admin | oem");
+ lprintf(LOG_NOTICE, " bit-rate "
+ "9.6 | 19.2 | 38.4 | 57.6 | 115.2");
+ lprintf(LOG_NOTICE, "");
+}
+
+static void print_isol_usage(void) {
+ lprintf(LOG_NOTICE, "ISOL Commands: info");
+ lprintf(LOG_NOTICE, " set <parameter> <setting>");
+ lprintf(LOG_NOTICE, " activate");
+}
+
+int ipmi_isol_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int ret = 0;
+
+ /*
+ * Help
+ */
+ if (!argc || !strncmp(argv[0], "help", 4))
+ print_isol_usage();
+
+ /*
+ * Info
+ */
+ else if (!strncmp(argv[0], "info", 4)) {
+ ret = ipmi_print_isol_info(intf);
+ }
+
+ /*
+ * Set a parameter value
+ */
+ else if (!strncmp(argv[0], "set", 3)) {
+ if (argc < 3) {
+ print_isol_set_usage();
+ return -1;
+ }
+ ret = ipmi_isol_set_param(intf, argv[1], argv[2]);
+ }
+
+ /*
+ * Activate
+ */
+ else if (!strncmp(argv[0], "activate", 8)) {
+ ret = ipmi_isol_activate(intf);
+ }
+
+ else {
+ print_isol_usage();
+ ret = -1;
+ }
+
+ return ret;
+}
diff --git a/lib/ipmi_kontronoem.c b/lib/ipmi_kontronoem.c
new file mode 100644
index 0000000..c154eda
--- /dev/null
+++ b/lib/ipmi_kontronoem.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved.
+ *
+ * Base on code from
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Tue Mar 7 14:36:12 2006
+ * <stephane.filion@ca.kontron.com>
+ *
+ * This code implements an Kontron OEM proprietary commands.
+ */
+
+
+#include <string.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_fru.h>
+
+
+extern int verbose;
+extern int read_fru_area(struct ipmi_intf * intf, struct fru_info *fru,
+ uint8_t id, uint32_t offset, uint32_t length,
+ uint8_t *frubuf);
+extern int write_fru_area(struct ipmi_intf * intf, struct fru_info *fru,
+ unsigned char id, unsigned int soffset,
+ unsigned int doffset, unsigned int length,
+ unsigned char *pFrubuf);
+
+extern char * get_fru_area_str(uint8_t * data, uint32_t * offset);
+
+
+
+static void ipmi_kontron_help(void);
+static int ipmi_kontron_set_serial_number(struct ipmi_intf * intf);
+static int ipmi_kontron_set_mfg_date (struct ipmi_intf * intf);
+
+static void ipmi_kontron_nextboot_help(void);
+static int ipmi_kontron_nextboot_set(struct ipmi_intf * intf,
+ int argc, char **argv);
+
+static int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf * intf,
+ unsigned char channel,
+ unsigned char size);
+
+int
+ipmi_kontronoem_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if (argc == 0)
+ ipmi_kontron_help();
+ else if (strncmp(argv[0], "help", 4) == 0)
+ ipmi_kontron_help();
+
+ else if (!strncmp(argv[0], "setsn", 5))
+ {
+ if(argc >= 1)
+ {
+ if(ipmi_kontron_set_serial_number(intf) > 0)
+ {
+ printf("FRU serial number setted successfully\n");
+ }
+ else
+ {
+ printf("FRU serial number set failed\n");
+ }
+ }
+ else
+ {
+ printf("fru setsn\n");
+ }
+ }
+ else if (!strncmp(argv[0], "setmfgdate", 5))
+ {
+ if(argc >= 1)
+ {
+ if(ipmi_kontron_set_mfg_date(intf) > 0)
+ {
+ printf("FRU manufacturing date setted successfully\n");
+ }
+ else
+ {
+ printf("FRU manufacturing date set failed\n");
+ }
+ }
+ else
+ {
+ printf("fru setmfgdate\n");
+ }
+ }
+ else if (!strncmp(argv[0], "nextboot", sizeof("nextboot")-1))
+ {
+ if (argc > 1)
+ {
+ if ((rc = ipmi_kontron_nextboot_set(intf, argc-1, argv+1)) == 0)
+ {
+ printf("Nextboot set successfully\n");
+ }
+ else
+ {
+ printf("Nextboot set failed\n");
+ }
+ }
+ else
+ {
+ ipmi_kontron_nextboot_help();
+ }
+ }
+
+ else
+ {
+ printf("Invalid Kontron command: %s", argv[0]);
+ ipmi_kontron_help();
+ rc = -1;
+ }
+
+ return rc;
+}
+
+
+static void ipmi_kontron_help(void)
+{
+ printf("Kontron Commands: setsn setmfgdate nextboot\n");
+}
+
+
+int ipmi_kontronoem_set_large_buffer(struct ipmi_intf * intf, unsigned char size)
+{
+ uint8_t error_occurs = 0;
+ uint32_t prev_target_addr = intf->target_addr ;
+
+ if ( intf->target_addr > 0 && (intf->target_addr != intf->my_addr) )
+ {
+ intf->target_addr = intf->my_addr;
+
+ printf("Set local big buffer\n");
+ if(ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, size ) == 0)
+ {
+ printf("Set local big buffer:success\n");
+ }
+ else
+ {
+ error_occurs = 1;
+ }
+
+ if (error_occurs == 0)
+ {
+ if(ipmi_kontronoem_send_set_large_buffer( intf, 0x00, size ) == 0)
+ {
+ printf("IPMB was set\n");
+ }
+ else
+ {
+ /* Revert back the previous set large buffer */
+ error_occurs = 1;
+ ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 );
+ }
+ }
+
+ /* Restore target address */
+ intf->target_addr = prev_target_addr;
+ }
+
+ if (error_occurs == 0)
+ {
+ if(ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, size ) == 0)
+ {
+ //printf("Set remote big buffer\n");
+ }
+ else
+ {
+ if ( intf->target_addr > 0 && (intf->target_addr != intf->my_addr) )
+ {
+ /* Error occurs revert back the previous set large buffer*/
+ intf->target_addr = intf->my_addr;
+
+ //ipmi_kontronoem_send_set_large_buffer( intf, 0x00, 0 );
+ ipmi_kontronoem_send_set_large_buffer( intf, 0x0e, 0 );
+
+ intf->target_addr = prev_target_addr;
+ }
+ }
+ }
+ return error_occurs;
+}
+
+
+int ipmi_kontronoem_send_set_large_buffer(struct ipmi_intf * intf, unsigned char channel,unsigned char size)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[2];
+ int i;
+
+ memset(msg_data, 0, sizeof(msg_data));
+ msg_data[0] = channel/*0x0e*/; // Currently running interface
+ msg_data[1] = size;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x3E; /* OEM NetFn */
+ req.msg.cmd = 0x82; /* Set Channel Buffer Length - OEM */
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ req.msg.lun = 0x00;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ printf("Cannot send large buffer command\n");
+ return(-1);
+ }
+ if (rsp->ccode > 0)
+ {
+ printf("Invalid length for the selected interface (%s) %d\n",
+ val2str(rsp->ccode, completion_code_vals), rsp->ccode);
+ return(-1);
+ }
+ return 0;
+}
+
+
+/* ipmi_fru_set_serial_number - Set the Serial Number in FRU
+ *
+ * @intf: ipmi interface
+ * @id: fru id
+ *
+ * returns -1 on error
+ * returns 1 if successful
+ */
+static int
+ipmi_kontron_set_serial_number(struct ipmi_intf * intf)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ struct fru_header header;
+ uint8_t msg_data[4];
+ char *sn;
+ uint8_t sn_size, checksum;
+ uint8_t *fru_data;
+ char *fru_area;
+ uint32_t fru_data_offset, fru_data_offset_tmp, board_sec_len, prod_sec_len, i;
+
+ sn = NULL;
+ fru_data = NULL;
+
+ memset(msg_data, 0, 4);
+ msg_data[0] = 0xb4;
+ msg_data[1] = 0x90;
+ msg_data[2] = 0x91;
+ msg_data[3] = 0x8b;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x3E;
+ req.msg.cmd = 0x0C;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+
+ /* Set Lun, necessary for this oem command */
+ req.msg.lun = 0x03;
+
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ printf(" Device not present (No Response)\n");
+ return -11;
+ }
+
+ if (rsp->ccode > 0)
+ {
+ printf(" This option is not implemented for this board\n");
+ return -1;
+ }
+
+ sn_size = rsp->data_len;
+
+ sn = malloc(sn_size + 1);
+
+ if(sn == NULL)
+ {
+ printf("Out of memory!");
+ return -1;
+ }
+
+ memset(sn, 0, sn_size + 1);
+ memcpy(sn, rsp->data, sn_size);
+
+ if(verbose >= 1)
+ {
+ printf("Original serial number is : [%s]\n", sn);
+ }
+
+
+
+ memset(msg_data, 0, 4);
+ msg_data[0] = 0;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ free(sn);
+ sn = NULL;
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ free(sn);
+ sn = NULL;
+ return(-1);
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ if (fru.size < 1) {
+ printf(" Invalid FRU size %d", fru.size);
+ free(sn);
+ sn = NULL;
+ return -1;
+ }
+
+ /*
+ * retrieve the FRU header
+ */
+ msg_data[0] = 0;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+ msg_data[3] = 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ printf(" Device not present (No Response)\n");
+ free(sn);
+ sn = NULL;
+ return(-1);
+ }
+ if (rsp->ccode > 0)
+ {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ free(sn);
+ sn = NULL;
+ return(-1);
+ }
+
+ if (verbose > 1)
+ printbuf(rsp->data, rsp->data_len, "FRU DATA");
+
+ memcpy(&header, rsp->data + 1, 8);
+
+ if (header.version != 1)
+ {
+ printf(" Unknown FRU header version 0x%02x",
+ header.version);
+ free(sn);
+ sn = NULL;
+ return(-1);
+ }
+
+ /* Set the Board Section */
+ board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
+
+
+ fru_data = malloc( fru.size);
+
+ if(fru_data == NULL)
+ {
+ printf("Out of memory!");
+ free(sn);
+ sn = NULL;
+ return(-1);
+ }
+
+ memset(fru_data, 0, fru.size);
+ if(read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data) < 0)
+ {
+ free(sn);
+ sn = NULL;
+ free(fru_data);
+ fru_data = NULL;
+ return(-1);
+ }
+
+ /*Position at Board Manufacturer*/
+ fru_data_offset = (header.offset.board * 8) + 6;
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset);
+
+ /*Position at Board Product Name*/
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset);
+
+ fru_data_offset_tmp = fru_data_offset;
+
+ /*Position at Serial Number*/
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
+
+ fru_data_offset ++;
+
+ if(strlen(fru_area) != sn_size)
+ {
+ printf("The length of the serial number in the FRU Board Area is wrong.\n");
+ free(sn);
+ sn = NULL;
+ free(fru_data);
+ fru_data = NULL;
+ return(-1);
+ }
+
+ /* Copy the new serial number in the board section saved in memory*/
+ memcpy(fru_data + fru_data_offset, sn, sn_size);
+
+ checksum = 0;
+ /* Calculate Header Checksum */
+ for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ )
+ {
+ checksum += fru_data[i];
+ }
+ checksum = (~checksum) + 1;
+
+
+ fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum;
+
+ /* Write the new FRU Board section */
+ if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0)
+ {
+ free(sn);
+ sn = NULL;
+ free(fru_data);
+ fru_data = NULL;
+ return(-1);
+ }
+
+ /* Set the Product Section */
+ prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8);
+
+ if(read_fru_area(intf ,&fru ,0 ,(header.offset.product * 8) ,prod_sec_len , fru_data) < 0)
+ {
+ free(sn);
+ sn = NULL;
+ free(fru_data);
+ fru_data = NULL;
+ return(-1);
+ }
+
+ /*Position at Product Manufacturer*/
+ fru_data_offset = (header.offset.product * 8) + 3;
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset);
+
+ /*Position at Product Name*/
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset);
+
+ /*Position at Product Part*/
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset);
+
+ /*Position at Product Version*/
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset);
+
+
+
+ fru_data_offset_tmp = fru_data_offset;
+
+ /*Position at Serial Number*/
+ fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp);
+
+ fru_data_offset ++;
+
+ if(strlen(fru_area) != sn_size)
+ {
+ free(sn);
+ sn = NULL;
+ free(fru_data);
+ fru_data = NULL;
+ printf("The length of the serial number in the FRU Product Area is wrong.\n");
+ return(-1);
+
+ }
+
+ /* Copy the new serial number in the product section saved in memory*/
+ memcpy(fru_data + fru_data_offset, sn, sn_size);
+
+ checksum = 0;
+ /* Calculate Header Checksum */
+ for( i = (header.offset.product * 8); i < (((header.offset.product * 8)+prod_sec_len) - 2) ; i ++ )
+ {
+ checksum += fru_data[i];
+ }
+ checksum = (~checksum) + 1;
+
+
+ fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum;
+
+ /* Write the new FRU Board section */
+ if(write_fru_area(intf, &fru, 0, (header.offset.product * 8), (header.offset.product * 8), prod_sec_len, fru_data) < 0)
+ {
+ free(sn);
+ sn = NULL;
+ free(fru_data);
+ fru_data = NULL;
+ return -1;
+ }
+
+ free(sn);
+ sn = NULL;
+ free(fru_data);
+ fru_data = NULL;
+
+ return(1);
+
+}
+
+
+/* ipmi_fru_set_mfg_date - Set the Manufacturing Date in FRU
+ *
+ * @intf: ipmi interface
+ * @id: fru id
+ *
+ * returns -1 on error
+ * returns 1 if successful
+ */
+static int
+ipmi_kontron_set_mfg_date (struct ipmi_intf * intf)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ struct fru_info fru;
+ struct fru_header header;
+ uint8_t msg_data[4];
+ uint8_t mfg_date[3];
+
+ uint32_t board_sec_len, i;
+ uint8_t *fru_data, checksum;
+
+
+
+
+ memset(msg_data, 0, 4);
+ msg_data[0] = 0xb4;
+ msg_data[1] = 0x90;
+ msg_data[2] = 0x91;
+ msg_data[3] = 0x8b;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x3E;
+ req.msg.cmd = 0x0E;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ /* Set Lun temporary, necessary for this oem command */
+ req.msg.lun = 0x03;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ printf("Device not present (No Response)\n");
+ return(-1);
+ }
+
+ if (rsp->ccode > 0)
+ {
+ printf("This option is not implemented for this board\n");
+ return(-1);
+ }
+
+ if(rsp->data_len != 3)
+ {
+ printf("Invalid response for the Manufacturing date\n");
+ return(-1);
+ }
+
+ memset(mfg_date, 0, 3);
+ memcpy(mfg_date, rsp->data, 3);
+
+ memset(msg_data, 0, 4);
+ msg_data[0] = 0;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_INFO;
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf(" Device not present (No Response)\n");
+ return(-1);
+ }
+ if (rsp->ccode > 0) {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return(-1);
+ }
+
+ memset(&fru, 0, sizeof(fru));
+ fru.size = (rsp->data[1] << 8) | rsp->data[0];
+ fru.access = rsp->data[2] & 0x1;
+
+ if (fru.size < 1) {
+ printf(" Invalid FRU size %d", fru.size);
+ return(-1);
+ }
+
+ /*
+ * retrieve the FRU header
+ */
+ msg_data[0] = 0;
+ msg_data[1] = 0;
+ msg_data[2] = 0;
+ msg_data[3] = 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_FRU_DATA;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ printf(" Device not present (No Response)\n");
+ return(-1);
+ }
+ if (rsp->ccode > 0)
+ {
+ printf(" Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return(-1);
+ }
+
+ if (verbose > 1)
+ printbuf(rsp->data, rsp->data_len, "FRU DATA");
+
+ memcpy(&header, rsp->data + 1, 8);
+
+ if (header.version != 1)
+ {
+ printf(" Unknown FRU header version 0x%02x",
+ header.version);
+ return(-1);
+ }
+
+
+ board_sec_len = (header.offset.product * 8) - (header.offset.board * 8);
+
+ fru_data = malloc( fru.size);
+
+ if(fru_data == NULL)
+ {
+ printf("Out of memory!");
+ return(-1);
+ }
+
+ memset(fru_data, 0, fru.size);
+ if(read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data) < 0)
+ {
+ free(fru_data);
+ fru_data = NULL;
+ return(-1);
+ }
+
+ /* Copy the new manufacturing date in the board section saved in memory*/
+ memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3);
+
+ checksum = 0;
+ /* Calculate Header Checksum */
+ for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ )
+ {
+ checksum += fru_data[i];
+ }
+ checksum = (~checksum) + 1;
+
+ fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum;
+
+ /* Write the new FRU Board section */
+ if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0)
+ {
+ free(fru_data);
+ fru_data = NULL;
+ return(-1);
+ }
+
+ free(fru_data);
+ fru_data = NULL;
+ return(1);
+}
+
+
+static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0};
+
+static void
+ipmi_kontron_nextboot_help(void)
+{
+ int i;
+ printf("nextboot <device>\n"
+ "Supported devices:\n");
+ for (i = 0; bootdev[i] != 0; i++) {
+ printf("- %s\n", bootdev[i]);
+ }
+}
+
+/* ipmi_kontron_next_boot_set - Select the next boot order on CP6012
+ *
+ * @intf: ipmi interface
+ * @id: fru id
+ *
+ * returns -1 on error
+ * returns 1 if successful
+ */
+static int
+ipmi_kontron_nextboot_set(struct ipmi_intf * intf, int argc, char **argv)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[8];
+ int i;
+
+ memset(msg_data, 0, sizeof(msg_data));
+ msg_data[0] = 0xb4;
+ msg_data[1] = 0x90;
+ msg_data[2] = 0x91;
+ msg_data[3] = 0x8b;
+ msg_data[4] = 0x9d;
+ msg_data[5] = 0xFF;
+ msg_data[6] = 0xFF; /* any */
+
+ for (i = 0; bootdev[i] != 0; i++) {
+ if (strcmp(argv[0], bootdev[i]) == 0) {
+ msg_data[5] = i;
+ break;
+ }
+ }
+
+ /* Invalid device selected? */
+ if (msg_data[5] == 0xFF) {
+ printf("Unknown boot device: %s\n", argv[0]);
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x3E;
+ req.msg.cmd = 0x02;
+ req.msg.data = msg_data;
+ req.msg.data_len = 7;
+
+ /* Set Lun temporary, necessary for this oem command */
+ req.msg.lun = 0x03;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ printf("Device not present (No Response)\n");
+ return(-1);
+ }
+ if (rsp->ccode > 0) {
+ printf("Device not present (%s)\n",
+ val2str(rsp->ccode, completion_code_vals));
+ return(-1);
+ }
+ return 0;
+}
+
diff --git a/lib/ipmi_lanp.c b/lib/ipmi_lanp.c
new file mode 100644
index 0000000..060e753
--- /dev/null
+++ b/lib/ipmi_lanp.c
@@ -0,0 +1,2352 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <netdb.h>
+#include <limits.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_lanp.h>
+#include <ipmitool/ipmi_channel.h>
+
+extern int verbose;
+
+/* is_lan_channel - Check if channel is LAN medium
+ *
+ * return 1 if channel is LAN
+ * return 0 if channel is not LAN
+ *
+ * @intf: ipmi interface handle
+ * @chan: channel number to check
+ */
+static int
+is_lan_channel(struct ipmi_intf * intf, uint8_t chan)
+{
+ uint8_t medium;
+
+ if (chan < 1 || chan > IPMI_CHANNEL_NUMBER_MAX)
+ return 0;
+
+ medium = ipmi_get_channel_medium(intf, chan);
+
+ if (medium == IPMI_CHANNEL_MEDIUM_LAN ||
+ medium == IPMI_CHANNEL_MEDIUM_LAN_OTHER)
+ return 1;
+
+ return 0;
+}
+
+/* find_lan_channel - Find first channel that is LAN
+ *
+ * return channel number if successful
+ * return 0 if no lan channel found, which is not a valid LAN channel
+ *
+ * @intf: ipmi interface handle
+ * @start: channel number to start searching from
+ */
+static uint8_t
+find_lan_channel(struct ipmi_intf * intf, uint8_t start)
+{
+ uint8_t chan = 0;
+
+ for (chan = start; chan < IPMI_CHANNEL_NUMBER_MAX; chan++) {
+ if (is_lan_channel(intf, chan)) {
+ return chan;
+ }
+ }
+ return 0;
+}
+
+/* get_lan_param_select - Query BMC for LAN parameter data
+ *
+ * return pointer to lan_param if successful
+ * if parameter not supported then
+ * return pointer to lan_param with
+ * lan_param->data == NULL and lan_param->data_len == 0
+ * return NULL on error
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ * @param: lan parameter id
+ * @select: lan parameter set selector
+ */
+static struct lan_param *
+get_lan_param_select(struct ipmi_intf * intf, uint8_t chan, int param, int select)
+{
+ struct lan_param * p = NULL;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ int i = 0;
+ uint8_t msg_data[4];
+
+ for (i = 0; ipmi_lan_params[i].cmd != (-1); i++) {
+ if (ipmi_lan_params[i].cmd == param) {
+ p = &ipmi_lan_params[i];
+ break;
+ }
+ }
+
+ if (p == NULL) {
+ lprintf(LOG_INFO, "Get LAN Parameter failed: Unknown parameter.");
+ return NULL;
+ }
+
+ msg_data[0] = chan;
+ msg_data[1] = p->cmd;
+ msg_data[2] = select;
+ msg_data[3] = 0;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_LAN_GET_CONFIG;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_INFO, "Get LAN Parameter '%s' command failed", p->desc);
+ return NULL;
+ }
+
+ switch (rsp->ccode)
+ {
+ case 0x00: /* successful */
+ break;
+
+ case 0x80: /* parameter not supported */
+ case 0xc9: /* parameter out of range */
+ case 0xcc: /* invalid data field in request */
+
+ /* these completion codes usually mean parameter not supported */
+ lprintf(LOG_INFO, "Get LAN Parameter '%s' command failed: %s",
+ p->desc, val2str(rsp->ccode, completion_code_vals));
+ p->data = NULL;
+ p->data_len = 0;
+ return p;
+
+ default:
+
+ /* other completion codes are treated as error */
+ lprintf(LOG_INFO, "Get LAN Parameter '%s' command failed: %s",
+ p->desc, val2str(rsp->ccode, completion_code_vals));
+ return NULL;
+ }
+
+ p->data = rsp->data + 1;
+ p->data_len = rsp->data_len - 1;
+
+ return p;
+}
+
+/* get_lan_param - Query BMC for LAN parameter data
+ *
+ * return pointer to lan_param if successful
+ * if parameter not supported then
+ * return pointer to lan_param with
+ * lan_param->data == NULL and lan_param->data_len == 0
+ * return NULL on error
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ * @param: lan parameter id
+ */
+static struct lan_param *
+get_lan_param(struct ipmi_intf * intf, uint8_t chan, int param)
+{
+ return get_lan_param_select(intf, chan, param, 0);
+}
+
+/* set_lan_param_wait - Wait for Set LAN Parameter command to complete
+ *
+ * On some systems this can take unusually long so we wait for the write
+ * to take effect and verify that the data was written successfully
+ * before continuing or retrying.
+ *
+ * returns 0 on success
+ * returns -1 on error
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ * @param: lan parameter id
+ * @data: lan parameter data
+ * @len: length of lan parameter data
+ */
+static int
+set_lan_param_wait(struct ipmi_intf * intf, uint8_t chan,
+ int param, uint8_t * data, int len)
+{
+ struct lan_param * p;
+ int retry = 10; /* 10 retries */
+
+ lprintf(LOG_DEBUG, "Waiting for Set LAN Parameter to complete...");
+ if (verbose > 1)
+ printbuf(data, len, "SET DATA");
+
+ for (;;) {
+ p = get_lan_param(intf, chan, param);
+ if (p == NULL) {
+ sleep(IPMI_LANP_TIMEOUT);
+ if (retry-- == 0)
+ return -1;
+ continue;
+ }
+ if (verbose > 1)
+ printbuf(p->data, p->data_len, "READ DATA");
+ if (p->data_len != len) {
+ sleep(IPMI_LANP_TIMEOUT);
+ if (retry-- == 0) {
+ lprintf(LOG_WARNING, "Mismatched data lengths: %d != %d",
+ p->data_len, len);
+ return -1;
+ }
+ continue;
+ }
+ if (memcmp(data, p->data, len) != 0) {
+ sleep(IPMI_LANP_TIMEOUT);
+ if (retry-- == 0) {
+ lprintf(LOG_WARNING, "LAN Parameter Data does not match! "
+ "Write may have failed.");
+ return -1;
+ }
+ continue;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* __set_lan_param - Write LAN Parameter data to BMC
+ *
+ * This function does the actual work of writing the LAN parameter
+ * to the BMC and calls set_lan_param_wait() if requested.
+ *
+ * returns 0 on success
+ * returns -1 on error
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ * @param: lan parameter id
+ * @data: lan parameter data
+ * @len: length of lan parameter data
+ * @wait: whether to wait for write completion
+ */
+static int
+__set_lan_param(struct ipmi_intf * intf, uint8_t chan,
+ int param, uint8_t * data, int len, int wait)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[32];
+
+ if (param < 0)
+ return -1;
+
+ msg_data[0] = chan;
+ msg_data[1] = param;
+
+ memcpy(&msg_data[2], data, len);
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_LAN_SET_CONFIG;
+ req.msg.data = msg_data;
+ req.msg.data_len = len+2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set LAN Parameter failed");
+ return -1;
+ }
+ if ((rsp->ccode > 0) && (wait != 0)) {
+ lprintf(LOG_DEBUG, "Warning: Set LAN Parameter failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ if (rsp->ccode == 0xcc) {
+ /* retry hack for invalid data field ccode */
+ int retry = 10; /* 10 retries */
+ lprintf(LOG_DEBUG, "Retrying...");
+ for (;;) {
+ if (retry-- == 0)
+ break;
+ sleep(IPMI_LANP_TIMEOUT);
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ continue;
+ if (rsp->ccode > 0)
+ continue;
+ return set_lan_param_wait(intf, chan, param, data, len);
+ }
+ }
+ else if (rsp->ccode != 0xff) {
+ /* let 0xff ccode continue */
+ return -1;
+ }
+ }
+
+ if (wait == 0)
+ return 0;
+ return set_lan_param_wait(intf, chan, param, data, len);
+}
+
+/* ipmi_lanp_lock_state - Retrieve set-in-progress status
+ *
+ * returns one of:
+ * IPMI_LANP_WRITE_UNLOCK
+ * IPMI_LANP_WRITE_LOCK
+ * IPMI_LANP_WRITE_COMMIT
+ * -1 on error/if not supported
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ */
+static int
+ipmi_lanp_lock_state(struct ipmi_intf * intf, uint8_t chan)
+{
+ struct lan_param * p;
+ p = get_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS);
+ if (p == NULL)
+ return -1;
+ if (p->data == NULL)
+ return -1;
+ return (p->data[0] & 3);
+}
+
+/* ipmi_lanp_lock - Lock set-in-progress bits for our use
+ *
+ * Write to the Set-In-Progress LAN parameter to indicate
+ * to other management software that we are modifying parameters.
+ *
+ * No meaningful return value because this is an optional
+ * requirement in IPMI spec and not found on many BMCs.
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ */
+static void
+ipmi_lanp_lock(struct ipmi_intf * intf, uint8_t chan)
+{
+ uint8_t val = IPMI_LANP_WRITE_LOCK;
+ int retry = 3;
+
+ for (;;) {
+ int state = ipmi_lanp_lock_state(intf, chan);
+ if (state == -1)
+ break;
+ if (state == val)
+ break;
+ if (retry-- == 0)
+ break;
+ __set_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS,
+ &val, 1, 0);
+ }
+}
+
+/* ipmi_lanp_unlock - Unlock set-in-progress bits
+ *
+ * Write to the Set-In-Progress LAN parameter, first with
+ * a "commit" instruction and then unlocking it.
+ *
+ * No meaningful return value because this is an optional
+ * requirement in IPMI spec and not found on many BMCs.
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ */
+static void
+ipmi_lanp_unlock(struct ipmi_intf * intf, uint8_t chan)
+{
+ uint8_t val = IPMI_LANP_WRITE_COMMIT;
+ int rc;
+
+ rc = __set_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS, &val, 1, 0);
+ if (rc < 0) {
+ lprintf(LOG_DEBUG, "LAN Parameter Commit not supported");
+ }
+
+ val = IPMI_LANP_WRITE_UNLOCK;
+ __set_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS, &val, 1, 0);
+}
+
+/* set_lan_param - Wrap LAN parameter write with set-in-progress lock
+ *
+ * Returns value from __set_lan_param()
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ * @param: lan parameter id
+ * @data: lan parameter data
+ * @len: length of lan parameter data
+ */
+static int
+set_lan_param(struct ipmi_intf * intf, uint8_t chan,
+ int param, uint8_t * data, int len)
+{
+ int rc;
+ ipmi_lanp_lock(intf, chan);
+ rc = __set_lan_param(intf, chan, param, data, len, 1);
+ ipmi_lanp_unlock(intf, chan);
+ return rc;
+}
+
+/* set_lan_param_nowait - Wrap LAN parameter write without set-in-progress lock
+ *
+ * Returns value from __set_lan_param()
+ *
+ * @intf: ipmi interface handle
+ * @chan: ipmi channel
+ * @param: lan parameter id
+ * @data: lan parameter data
+ * @len: length of lan parameter data
+ */
+static int
+set_lan_param_nowait(struct ipmi_intf * intf, uint8_t chan,
+ int param, uint8_t * data, int len)
+{
+ int rc;
+ ipmi_lanp_lock(intf, chan);
+ rc = __set_lan_param(intf, chan, param, data, len, 0);
+ ipmi_lanp_unlock(intf, chan);
+ return rc;
+}
+
+static int
+lan_set_arp_interval(struct ipmi_intf * intf, uint8_t chan, uint8_t ival)
+{
+ struct lan_param *lp;
+ uint8_t interval = 0;
+ int rc = 0;
+
+ lp = get_lan_param(intf, chan, IPMI_LANP_GRAT_ARP);
+ if (lp == NULL)
+ return -1;
+ if (lp->data == NULL)
+ return -1;
+
+ if (ival != 0) {
+ if (((UINT8_MAX - 1) / 2) < ival) {
+ lprintf(LOG_ERR, "Given ARP interval '%u' is too big.", ival);
+ return (-1);
+ }
+ interval = (ival * 2) - 1;
+ rc = set_lan_param(intf, chan, IPMI_LANP_GRAT_ARP, &interval, 1);
+ } else {
+ interval = lp->data[0];
+ }
+
+ printf("BMC-generated Gratuitous ARP interval: %.1f seconds\n",
+ (float)((interval + 1) / 2));
+
+ return rc;
+}
+
+static int
+lan_set_arp_generate(struct ipmi_intf * intf,
+ uint8_t chan, uint8_t ctl)
+{
+ struct lan_param *lp;
+ uint8_t data;
+
+ lp = get_lan_param(intf, chan, IPMI_LANP_BMC_ARP);
+ if (lp == NULL)
+ return -1;
+ if (lp->data == NULL)
+ return -1;
+ data = lp->data[0];
+
+ /* set arp generate bitflag */
+ if (ctl == 0)
+ data &= ~0x1;
+ else
+ data |= 0x1;
+
+ printf("%sabling BMC-generated Gratuitous ARPs\n", ctl ? "En" : "Dis");
+ return set_lan_param(intf, chan, IPMI_LANP_BMC_ARP, &data, 1);
+}
+
+static int
+lan_set_arp_respond(struct ipmi_intf * intf,
+ uint8_t chan, uint8_t ctl)
+{
+ struct lan_param *lp;
+ uint8_t data;
+
+ lp = get_lan_param(intf, chan, IPMI_LANP_BMC_ARP);
+ if (lp == NULL)
+ return -1;
+ if (lp->data == NULL)
+ return -1;
+ data = lp->data[0];
+
+ /* set arp response bitflag */
+ if (ctl == 0)
+ data &= ~0x2;
+ else
+ data |= 0x2;
+
+ printf("%sabling BMC-generated ARP responses\n", ctl ? "En" : "Dis");
+ return set_lan_param(intf, chan, IPMI_LANP_BMC_ARP, &data, 1);
+}
+
+
+static char priv_level_to_char(unsigned char priv_level)
+{
+ char ret = 'X';
+
+ switch (priv_level)
+ {
+ case IPMI_SESSION_PRIV_CALLBACK:
+ ret = 'c';
+ break;
+ case IPMI_SESSION_PRIV_USER:
+ ret = 'u';
+ break;
+ case IPMI_SESSION_PRIV_OPERATOR:
+ ret = 'o';
+ break;
+ case IPMI_SESSION_PRIV_ADMIN:
+ ret = 'a';
+ break;
+ case IPMI_SESSION_PRIV_OEM:
+ ret = 'O';
+ break;
+ }
+
+ return ret;
+}
+
+
+static int
+ipmi_lan_print(struct ipmi_intf * intf, uint8_t chan)
+{
+ struct lan_param * p;
+ int rc = 0;
+
+ if (chan < 1 || chan > IPMI_CHANNEL_NUMBER_MAX) {
+ lprintf(LOG_ERR, "Invalid Channel %d", chan);
+ return -1;
+ }
+
+ /* find type of channel and only accept 802.3 LAN */
+ if (!is_lan_channel(intf, chan)) {
+ lprintf(LOG_ERR, "Channel %d is not a LAN channel", chan);
+ return -1;
+ }
+
+ p = get_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL) {
+ printf("%-24s: ", p->desc);
+ p->data[0] &= 3;
+ switch (p->data[0]) {
+ case 0:
+ printf("Set Complete\n");
+ break;
+ case 1:
+ printf("Set In Progress\n");
+ break;
+ case 2:
+ printf("Commit Write\n");
+ break;
+ case 3:
+ printf("Reserved\n");
+ break;
+ default:
+ printf("Unknown\n");
+ }
+ }
+
+ p = get_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL) {
+ printf("%-24s: %s%s%s%s%s\n", p->desc,
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : "");
+ }
+
+ p = get_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE_ENABLE);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL) {
+ printf("%-24s: Callback : %s%s%s%s%s\n", p->desc,
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "",
+ (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : "");
+ printf("%-24s: User : %s%s%s%s%s\n", "",
+ (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "",
+ (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "",
+ (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "",
+ (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "",
+ (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : "");
+ printf("%-24s: Operator : %s%s%s%s%s\n", "",
+ (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "",
+ (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "",
+ (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "",
+ (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "",
+ (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : "");
+ printf("%-24s: Admin : %s%s%s%s%s\n", "",
+ (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "",
+ (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "",
+ (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "",
+ (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "",
+ (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : "");
+ printf("%-24s: OEM : %s%s%s%s%s\n", "",
+ (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "",
+ (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "",
+ (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "",
+ (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "",
+ (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : "");
+ }
+
+ p = get_lan_param(intf, chan, IPMI_LANP_IP_ADDR_SRC);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL) {
+ printf("%-24s: ", p->desc);
+ p->data[0] &= 0xf;
+ switch (p->data[0]) {
+ case 0:
+ printf("Unspecified\n");
+ break;
+ case 1:
+ printf("Static Address\n");
+ break;
+ case 2:
+ printf("DHCP Address\n");
+ break;
+ case 3:
+ printf("BIOS Assigned Address\n");
+ break;
+ default:
+ printf("Other\n");
+ break;
+ }
+ }
+
+ p = get_lan_param(intf, chan, IPMI_LANP_IP_ADDR);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %d.%d.%d.%d\n", p->desc,
+ p->data[0], p->data[1], p->data[2], p->data[3]);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_SUBNET_MASK);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %d.%d.%d.%d\n", p->desc,
+ p->data[0], p->data[1], p->data[2], p->data[3]);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_MAC_ADDR);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", p->desc,
+ p->data[0], p->data[1], p->data[2], p->data[3], p->data[4], p->data[5]);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_SNMP_STRING);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %s\n", p->desc, p->data);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_IP_HEADER);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: TTL=0x%02x Flags=0x%02x Precedence=0x%02x TOS=0x%02x\n",
+ p->desc, p->data[0], p->data[1] & 0xe0, p->data[2] & 0xe0, p->data[2] & 0x1e);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_BMC_ARP);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: ARP Responses %sabled, Gratuitous ARP %sabled\n", p->desc,
+ (p->data[0] & 2) ? "En" : "Dis", (p->data[0] & 1) ? "En" : "Dis");
+
+ p = get_lan_param(intf, chan, IPMI_LANP_GRAT_ARP);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %.1f seconds\n", p->desc, (float)((p->data[0] + 1) / 2));
+
+ p = get_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_IP);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %d.%d.%d.%d\n", p->desc,
+ p->data[0], p->data[1], p->data[2], p->data[3]);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_MAC);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", p->desc,
+ p->data[0], p->data[1], p->data[2], p->data[3], p->data[4], p->data[5]);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_IP);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %d.%d.%d.%d\n", p->desc,
+ p->data[0], p->data[1], p->data[2], p->data[3]);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_MAC);
+ if (p == NULL)
+ return -1;
+ if (p->data != NULL)
+ printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", p->desc,
+ p->data[0], p->data[1], p->data[2], p->data[3], p->data[4], p->data[5]);
+
+ p = get_lan_param(intf, chan, IPMI_LANP_VLAN_ID);
+ if (p != NULL && p->data != NULL) {
+ int id = ((p->data[1] & 0x0f) << 8) + p->data[0];
+ if (p->data[1] & 0x80)
+ printf("%-24s: %d\n", p->desc, id);
+ else
+ printf("%-24s: Disabled\n", p->desc);
+ }
+
+ p = get_lan_param(intf, chan, IPMI_LANP_VLAN_PRIORITY);
+ if (p != NULL && p->data != NULL)
+ printf("%-24s: %d\n", p->desc, p->data[0] & 0x07);
+
+ /* Determine supported Cipher Suites -- Requires two calls */
+ p = get_lan_param(intf, chan, IPMI_LANP_RMCP_CIPHER_SUPPORT);
+ if (p == NULL)
+ return -1;
+ else if (p->data != NULL)
+ {
+ unsigned char cipher_suite_count = p->data[0];
+ p = get_lan_param(intf, chan, IPMI_LANP_RMCP_CIPHERS);
+ if (p == NULL)
+ return -1;
+
+ printf("%-24s: ", p->desc);
+
+ /* Now we're dangerous. There are only 15 fixed cipher
+ suite IDs, but the spec allows for 16 in the return data.*/
+ if ((p->data != NULL) && (p->data_len <= 17))
+ {
+ unsigned int i;
+ for (i = 0; (i < 16) && (i < cipher_suite_count); ++i)
+ {
+ printf("%s%d",
+ (i > 0? ",": ""),
+ p->data[i + 1]);
+ }
+ printf("\n");
+ }
+ else
+ {
+ printf("None\n");
+ }
+ }
+
+ /* RMCP+ Messaging Cipher Suite Privilege Levels */
+ /* These are the privilege levels for the 15 fixed cipher suites */
+ p = get_lan_param(intf, chan, IPMI_LANP_RMCP_PRIV_LEVELS);
+ if (p == NULL)
+ return -1;
+ if ((p->data != NULL) && (p->data_len == 9))
+ {
+ printf("%-24s: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", p->desc,
+ priv_level_to_char(p->data[1] & 0x0F),
+ priv_level_to_char(p->data[1] >> 4),
+ priv_level_to_char(p->data[2] & 0x0F),
+ priv_level_to_char(p->data[2] >> 4),
+ priv_level_to_char(p->data[3] & 0x0F),
+ priv_level_to_char(p->data[3] >> 4),
+ priv_level_to_char(p->data[4] & 0x0F),
+ priv_level_to_char(p->data[4] >> 4),
+ priv_level_to_char(p->data[5] & 0x0F),
+ priv_level_to_char(p->data[5] >> 4),
+ priv_level_to_char(p->data[6] & 0x0F),
+ priv_level_to_char(p->data[6] >> 4),
+ priv_level_to_char(p->data[7] & 0x0F),
+ priv_level_to_char(p->data[7] >> 4),
+ priv_level_to_char(p->data[8] & 0x0F));
+
+ /* Now print a legend */
+ printf("%-24s: %s\n", "", " X=Cipher Suite Unused");
+ printf("%-24s: %s\n", "", " c=CALLBACK");
+ printf("%-24s: %s\n", "", " u=USER");
+ printf("%-24s: %s\n", "", " o=OPERATOR");
+ printf("%-24s: %s\n", "", " a=ADMIN");
+ printf("%-24s: %s\n", "", " O=OEM");
+ }
+ else
+ printf("%-24s: Not Available\n", p->desc);
+
+ return rc;
+}
+
+/* Configure Authentication Types */
+static int
+ipmi_lan_set_auth(struct ipmi_intf * intf, uint8_t chan, char * level, char * types)
+{
+ uint8_t data[5];
+ uint8_t authtype = 0;
+ char * p;
+ struct lan_param * lp;
+
+ if (level == NULL || types == NULL)
+ return -1;
+
+ lp = get_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE_ENABLE);
+ if (lp == NULL)
+ return -1;
+ if (lp->data == NULL)
+ return -1;
+
+ lprintf(LOG_DEBUG, "%-24s: callback=0x%02x user=0x%02x operator=0x%02x admin=0x%02x oem=0x%02x",
+ lp->desc, lp->data[0], lp->data[1], lp->data[2], lp->data[3], lp->data[4]);
+
+ memset(data, 0, 5);
+ memcpy(data, lp->data, 5);
+
+ p = types;
+ while (p) {
+ if (strncasecmp(p, "none", 4) == 0)
+ authtype |= 1 << IPMI_SESSION_AUTHTYPE_NONE;
+ else if (strncasecmp(p, "md2", 3) == 0)
+ authtype |= 1 << IPMI_SESSION_AUTHTYPE_MD2;
+ else if (strncasecmp(p, "md5", 3) == 0)
+ authtype |= 1 << IPMI_SESSION_AUTHTYPE_MD5;
+ else if ((strncasecmp(p, "password", 8) == 0) ||
+ (strncasecmp(p, "key", 3) == 0))
+ authtype |= 1 << IPMI_SESSION_AUTHTYPE_KEY;
+ else if (strncasecmp(p, "oem", 3) == 0)
+ authtype |= 1 << IPMI_SESSION_AUTHTYPE_OEM;
+ else
+ lprintf(LOG_WARNING, "Invalid authentication type: %s", p);
+ p = strchr(p, ',');
+ if (p)
+ p++;
+ }
+
+ p = level;
+ while (p) {
+ if (strncasecmp(p, "callback", 8) == 0)
+ data[0] = authtype;
+ else if (strncasecmp(p, "user", 4) == 0)
+ data[1] = authtype;
+ else if (strncasecmp(p, "operator", 8) == 0)
+ data[2] = authtype;
+ else if (strncasecmp(p, "admin", 5) == 0)
+ data[3] = authtype;
+ else
+ lprintf(LOG_WARNING, "Invalid authentication level: %s", p);
+ p = strchr(p, ',');
+ if (p)
+ p++;
+ }
+
+ if (verbose > 1)
+ printbuf(data, 5, "authtype data");
+
+ return set_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE_ENABLE, data, 5);
+}
+
+static int
+ipmi_lan_set_password(struct ipmi_intf * intf,
+ uint8_t userid, uint8_t * password)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t data[18];
+
+ memset(&data, 0, sizeof(data));
+ data[0] = userid & 0x3f;/* user ID */
+ data[1] = 0x02; /* set password */
+
+ if (password != NULL)
+ memcpy(data+2, password, __min(strlen((const char *)password), 16));
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x47;
+ req.msg.data = data;
+ req.msg.data_len = 18;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Set LAN Password for user %d", userid);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set LAN Password for user %d failed: %s",
+ userid, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ /* adjust our session password
+ * or we will no longer be able to communicate with BMC
+ */
+ ipmi_intf_session_set_password(intf, (char *)password);
+ printf("Password %s for user %d\n",
+ (password == NULL) ? "cleared" : "set", userid);
+
+ return 0;
+}
+
+static int
+ipmi_set_alert_enable(struct ipmi_intf * intf, uint8_t channel, uint8_t enable)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[3];
+
+ memset(&req, 0, sizeof(req));
+
+ /* update non-volatile access */
+ rqdata[0] = channel;
+ rqdata[1] = 0x40;
+
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x41;
+ req.msg.data = rqdata;
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Access for channel %d", channel);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Channel Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ /* SAVE TO NVRAM */
+ memset(rqdata, 0, 3);
+ rqdata[0] = channel & 0xf;
+ rqdata[1] = rsp->data[0];
+ if (enable != 0)
+ rqdata[1] &= ~0x20;
+ else
+ rqdata[1] |= 0x20;
+ rqdata[1] |= 0x40;
+ rqdata[2] = 0;
+
+ req.msg.cmd = 0x40;
+ req.msg.data_len = 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ /* SAVE TO CURRENT */
+ rqdata[1] &= 0xc0;
+ rqdata[1] |= 0x80;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ipmi_set_channel_access(struct ipmi_intf * intf, uint8_t channel, uint8_t enable)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[3];
+ uint8_t byteEnable;
+
+ memset(&req, 0, sizeof(req));
+
+ /* RETREIVE VALUE IN NVRAM */
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x41; /* Get Channel Access Command */
+ req.msg.data = rqdata;
+ req.msg.data_len = 2;
+
+ memset(rqdata, 0, 2);
+ rqdata[0] = channel & 0xf;
+ rqdata[1] = 0x40; /* retreive NV */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Access for channel %d", channel);
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ } else {
+ byteEnable = *(rsp->data + 0);
+ }
+
+ /* SAVE TO NVRAM */
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x40; /* Set Channel Access Command */
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ memset(rqdata, 0, 3);
+ rqdata[0] = channel & 0xf;
+ rqdata[1] = 0x40 | (byteEnable & 0x38); /* use previously set values */
+ if (enable != 0)
+ rqdata[1] |= 0x2; /* set always available if enable is set */
+ rqdata[2] = 0x44; /* set channel privilege limit to ADMIN */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel);
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ /* RETREIVE VALUE IN NVRAM */
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x41; /* Get Channel Access Command */
+ req.msg.data = rqdata;
+ req.msg.data_len = 2;
+
+ memset(rqdata, 0, 2);
+ rqdata[0] = channel & 0xf;
+ rqdata[1] = 0x80; /* retreive NV */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Get Channel Access for channel %d", channel);
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ } else {
+ byteEnable = *(rsp->data + 0);
+ }
+
+ /* SAVE TO CURRENT */
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x40; /* Set Channel Access Command */
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ memset(rqdata, 0, 3);
+ rqdata[0] = channel & 0xf;
+ rqdata[1] = 0x80 | (byteEnable & 0x38); /* use previously set values */
+ if (enable != 0)
+ rqdata[1] |= 0x2; /* set always available if enable is set */
+ rqdata[2] = 0x84; /* set channel privilege limit to ADMIN */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel);
+ return -1;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ /* can't send close session if access off so abort instead */
+ if (enable == 0)
+ intf->abort = 1;
+
+ return 0;
+}
+
+static int
+ipmi_set_user_access(struct ipmi_intf * intf, uint8_t channel, uint8_t userid)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[4];
+
+ memset(rqdata, 0, 4);
+ rqdata[0] = 0x90 | (channel & 0xf);
+ rqdata[1] = userid & 0x3f;
+ rqdata[2] = 0x4;
+ rqdata[3] = 0;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x43;
+ req.msg.data = rqdata;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to Set User Access for channel %d", channel);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set User Access for channel %d failed: %s",
+ channel, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+get_cmdline_macaddr(char * arg, uint8_t * buf)
+{
+ uint32_t m1, m2, m3, m4, m5, m6;
+ if (sscanf(arg, "%02x:%02x:%02x:%02x:%02x:%02x",
+ &m1, &m2, &m3, &m4, &m5, &m6) != 6) {
+ lprintf(LOG_ERR, "Invalid MAC address: %s", arg);
+ return -1;
+ }
+ buf[0] = (uint8_t)m1;
+ buf[1] = (uint8_t)m2;
+ buf[2] = (uint8_t)m3;
+ buf[3] = (uint8_t)m4;
+ buf[4] = (uint8_t)m5;
+ buf[5] = (uint8_t)m6;
+ return 0;
+}
+
+
+static int
+get_cmdline_cipher_suite_priv_data(char * arg, uint8_t * buf)
+{
+ int i, ret = 0;
+
+ if (strlen(arg) != 15)
+ {
+ lprintf(LOG_ERR, "Invalid privilege specification length: %d",
+ strlen(arg));
+ return -1;
+ }
+
+ /*
+ * The first byte is reserved (0). The rest of the buffer is setup
+ * so that each nibble holds the maximum privilege level available for
+ * that cipher suite number. The number of nibbles (15) matches the number
+ * of fixed cipher suite IDs. This command documentation mentions 16 IDs
+ * but table 22-19 shows that there are only 15 (0-14).
+ *
+ * data 1 - reserved
+ * data 2 - maximum priv level for first (LSN) and second (MSN) ciphers
+ * data 3 - maximum priv level for third (LSN) and fourth (MSN) ciphers
+ * data 9 - maximum priv level for 15th (LSN) cipher.
+ */
+ bzero(buf, 9);
+
+ for (i = 0; i < 15; ++i)
+ {
+ unsigned char priv_level = IPMI_SESSION_PRIV_ADMIN;
+
+ switch (arg[i])
+ {
+ case 'X':
+ priv_level = IPMI_SESSION_PRIV_UNSPECIFIED; /* 0 */
+ break;
+ case 'c':
+ priv_level = IPMI_SESSION_PRIV_CALLBACK; /* 1 */
+ break;
+ case 'u':
+ priv_level = IPMI_SESSION_PRIV_USER; /* 2 */
+ break;
+ case 'o':
+ priv_level = IPMI_SESSION_PRIV_OPERATOR; /* 3 */
+ break;
+ case 'a':
+ priv_level = IPMI_SESSION_PRIV_ADMIN; /* 4 */
+ break;
+ case 'O':
+ priv_level = IPMI_SESSION_PRIV_OEM; /* 5 */
+ break;
+ default:
+ lprintf(LOG_ERR, "Invalid privilege specification char: %c",
+ arg[i]);
+ ret = -1;
+ break;
+ }
+
+ if (ret != 0)
+ break;
+ else
+ {
+ if ((i + 1) % 2)
+ {
+ // Odd number cipher suites will be in the LSN
+ buf[1 + (i / 2)] += priv_level;
+ }
+ else
+ {
+ // Even number cipher suites will be in the MSN
+ buf[1 + (i / 2)] += (priv_level << 4);
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+static int
+get_cmdline_ipaddr(char * arg, uint8_t * buf)
+{
+ uint32_t ip1, ip2, ip3, ip4;
+ if (sscanf(arg, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4) {
+ lprintf(LOG_ERR, "Invalid IP address: %s", arg);
+ return -1;
+ }
+ buf[0] = (uint8_t)ip1;
+ buf[1] = (uint8_t)ip2;
+ buf[2] = (uint8_t)ip3;
+ buf[3] = (uint8_t)ip4;
+ return 0;
+}
+
+static void ipmi_lan_set_usage(void)
+{
+ lprintf(LOG_NOTICE, "\nusage: lan set <channel> <command> <parameter>\n");
+ lprintf(LOG_NOTICE, "LAN set command/parameter options:");
+ lprintf(LOG_NOTICE, " ipaddr <x.x.x.x> Set channel IP address");
+ lprintf(LOG_NOTICE, " netmask <x.x.x.x> Set channel IP netmask");
+ lprintf(LOG_NOTICE, " macaddr <x:x:x:x:x:x> Set channel MAC address");
+ lprintf(LOG_NOTICE, " defgw ipaddr <x.x.x.x> Set default gateway IP address");
+ lprintf(LOG_NOTICE, " defgw macaddr <x:x:x:x:x:x> Set default gateway MAC address");
+ lprintf(LOG_NOTICE, " bakgw ipaddr <x.x.x.x> Set backup gateway IP address");
+ lprintf(LOG_NOTICE, " bakgw macaddr <x:x:x:x:x:x> Set backup gateway MAC address");
+ lprintf(LOG_NOTICE, " password <password> Set session password for this channel");
+ lprintf(LOG_NOTICE, " snmp <community string> Set SNMP public community string");
+ lprintf(LOG_NOTICE, " user Enable default user for this channel");
+ lprintf(LOG_NOTICE, " access <on|off> Enable or disable access to this channel");
+ lprintf(LOG_NOTICE, " alert <on|off> Enable or disable PEF alerting for this channel");
+ lprintf(LOG_NOTICE, " arp respond <on|off> Enable or disable BMC ARP responding");
+ lprintf(LOG_NOTICE, " arp generate <on|off> Enable or disable BMC gratuitous ARP generation");
+ lprintf(LOG_NOTICE, " arp interval <seconds> Set gratuitous ARP generation interval");
+ lprintf(LOG_NOTICE, " vlan id <off|<id>> Disable or enable VLAN and set ID (1-4094)");
+ lprintf(LOG_NOTICE, " vlan priority <priority> Set vlan priority (0-7)");
+ lprintf(LOG_NOTICE, " auth <level> <type,..> Set channel authentication types");
+ lprintf(LOG_NOTICE, " level = CALLBACK, USER, OPERATOR, ADMIN");
+ lprintf(LOG_NOTICE, " type = NONE, MD2, MD5, PASSWORD, OEM");
+ lprintf(LOG_NOTICE, " ipsrc <source> Set IP Address source");
+ lprintf(LOG_NOTICE, " none = unspecified source");
+ lprintf(LOG_NOTICE, " static = address manually configured to be static");
+ lprintf(LOG_NOTICE, " dhcp = address obtained by BMC running DHCP");
+ lprintf(LOG_NOTICE, " bios = address loaded by BIOS or system software");
+ lprintf(LOG_NOTICE, " cipher_privs XXXXXXXXXXXXXXX Set RMCP+ cipher suite privilege levels");
+ lprintf(LOG_NOTICE, " X = Cipher Suite Unused");
+ lprintf(LOG_NOTICE, " c = CALLBACK");
+ lprintf(LOG_NOTICE, " u = USER");
+ lprintf(LOG_NOTICE, " o = OPERATOR");
+ lprintf(LOG_NOTICE, " a = ADMIN");
+ lprintf(LOG_NOTICE, " O = OEM\n");
+}
+
+static void
+ipmi_lan_set_vlan_usage(void)
+{
+ lprintf(LOG_NOTICE,
+ "lan set <channel> vlan id <id>\n"
+ "lan set <channel> vlan id off\n"
+ "lan set <channel> vlan priority <priority>\n");
+}
+
+static int
+ipmi_lan_set_vlan_id(struct ipmi_intf * intf, uint8_t chan, char *string)
+{
+ uint8_t data[2];
+ int rc;
+
+ if (string == NULL) {
+ data[0] = 0;
+ data[1] = 0;
+ }
+ else {
+ int id = 0;
+ if (str2int(string, &id) != 0) {
+ lprintf(LOG_ERR, "Given VLAN ID '%s' is invalid.", string);
+ return (-1);
+ }
+
+ if (id < 1 || id > 4094) {
+ lprintf(LOG_NOTICE, "vlan id must be between 1 and 4094.");
+ return -1;
+ }
+ else {
+ data[0] = (uint8_t)id;
+ data[1] = (uint8_t)(id >> 8) | 0x80;
+ }
+ }
+ rc = set_lan_param(intf, chan, IPMI_LANP_VLAN_ID, data, 2);
+ return rc;
+}
+
+static int
+ipmi_lan_set_vlan_priority(struct ipmi_intf * intf, uint8_t chan, char *string)
+{
+ uint8_t data;
+ int rc;
+ int priority = 0;
+ if (str2int(string, &priority) != 0) {
+ lprintf(LOG_ERR, "Given VLAN priority '%s' is invalid.", string);
+ return (-1);
+ }
+
+ if (priority < 0 || priority > 7) {
+ lprintf(LOG_NOTICE, "vlan priority must be between 0 and 7.");
+ return -1;
+ }
+ data = (uint8_t)priority;
+ rc = set_lan_param(intf, chan, IPMI_LANP_VLAN_PRIORITY, &data, 1);
+ return rc;
+}
+
+static int
+ipmi_lan_set(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ uint8_t data[32];
+ uint8_t chan;
+ int rc = 0;
+
+ if (argc < 2) {
+ ipmi_lan_set_usage();
+ return (-1);
+ }
+
+ if (strncmp(argv[0], "help", 4) == 0 ||
+ strncmp(argv[1], "help", 4) == 0) {
+ ipmi_lan_set_usage();
+ return 0;
+ }
+
+ if (str2uchar(argv[0], &chan) != 0) {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[0]);
+ return (-1);
+ }
+
+ /* find type of channel and only accept 802.3 LAN */
+ if (!is_lan_channel(intf, chan)) {
+ lprintf(LOG_ERR, "Channel %d is not a LAN channel!", chan);
+ ipmi_lan_set_usage();
+ return -1;
+ }
+
+ memset(&data, 0, sizeof(data));
+
+ /* set user access */
+ if (strncmp(argv[1], "user", 4) == 0) {
+ rc = ipmi_set_user_access(intf, chan, 1);
+ }
+ /* set channel access mode */
+ else if (strncmp(argv[1], "access", 6) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_NOTICE, "lan set access <on|off>");
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "lan set access <on|off>");
+ return 0;
+ }
+ else if (strncmp(argv[2], "on", 2) == 0) {
+ rc = ipmi_set_channel_access(intf, chan, 1);
+ }
+ else if (strncmp(argv[2], "off", 3) == 0) {
+ rc = ipmi_set_channel_access(intf, chan, 0);
+ }
+ else {
+ lprintf(LOG_NOTICE, "lan set access <on|off>");
+ return (-1);
+ }
+ }
+ /* set ARP control */
+ else if (strncmp(argv[1], "arp", 3) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> arp respond <on|off>\n"
+ "lan set <channel> arp generate <on|off>\n"
+ "lan set <channel> arp interval <seconds>\n\n"
+ "example: lan set 7 arp gratuitous off\n");
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> arp respond <on|off>\n"
+ "lan set <channel> arp generate <on|off>\n"
+ "lan set <channel> arp interval <seconds>\n\n"
+ "example: lan set 7 arp gratuitous off\n");
+ return 0;
+ }
+ else if (strncmp(argv[2], "interval", 8) == 0) {
+ uint8_t interval = 0;
+ if (str2uchar(argv[3], &interval) != 0) {
+ lprintf(LOG_ERR, "Given ARP interval '%s' is invalid.", argv[3]);
+ return (-1);
+ }
+ rc = lan_set_arp_interval(intf, chan, interval);
+ }
+ else if (strncmp(argv[2], "generate", 8) == 0) {
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "lan set <channel> arp generate <on|off>");
+ return (-1);
+ }
+ else if (strncmp(argv[3], "on", 2) == 0)
+ rc = lan_set_arp_generate(intf, chan, 1);
+ else if (strncmp(argv[3], "off", 3) == 0)
+ rc = lan_set_arp_generate(intf, chan, 0);
+ else {
+ lprintf(LOG_NOTICE, "lan set <channel> arp generate <on|off>");
+ return (-1);
+ }
+ }
+ else if (strncmp(argv[2], "respond", 7) == 0) {
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "lan set <channel> arp respond <on|off>");
+ return (-1);
+ }
+ else if (strncmp(argv[3], "on", 2) == 0)
+ rc = lan_set_arp_respond(intf, chan, 1);
+ else if (strncmp(argv[3], "off", 3) == 0)
+ rc = lan_set_arp_respond(intf, chan, 0);
+ else {
+ lprintf(LOG_NOTICE, "lan set <channel> arp respond <on|off>");
+ return (-1);
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> arp respond <on|off>\n"
+ "lan set <channel> arp generate <on|off>\n"
+ "lan set <channel> arp interval <seconds>\n");
+ return (-1);
+ }
+ }
+ /* set authentication types */
+ else if (strncmp(argv[1], "auth", 4) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> auth <level> <type,type,...>\n"
+ " level = CALLBACK, USER, OPERATOR, ADMIN\n"
+ " types = NONE, MD2, MD5, PASSWORD, OEM\n"
+ "example: lan set 7 auth ADMIN PASSWORD,MD5\n");
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> auth <level> <type,type,...>\n"
+ " level = CALLBACK, USER, OPERATOR, ADMIN\n"
+ " types = NONE, MD2, MD5, PASSWORD, OEM\n"
+ "example: lan set 7 auth ADMIN PASSWORD,MD5\n");
+ return 0;
+ } else {
+ rc = ipmi_lan_set_auth(intf, chan, argv[2], argv[3]);
+ }
+ }
+ /* ip address source */
+ else if (strncmp(argv[1], "ipsrc", 5) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> ipsrc <source>\n"
+ " none = unspecified\n"
+ " static = static address (manually configured)\n"
+ " dhcp = address obtained by BMC running DHCP\n"
+ " bios = address loaded by BIOS or system software\n");
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> ipsrc <source>\n"
+ " none = unspecified\n"
+ " static = static address (manually configured)\n"
+ " dhcp = address obtained by BMC running DHCP\n"
+ " bios = address loaded by BIOS or system software\n");
+ return 0;
+ }
+ else if (strncmp(argv[2], "none", 4) == 0)
+ data[0] = 0;
+ else if (strncmp(argv[2], "static", 5) == 0)
+ data[0] = 1;
+ else if (strncmp(argv[2], "dhcp", 4) == 0)
+ data[0] = 2;
+ else if (strncmp(argv[2], "bios", 4) == 0)
+ data[0] = 3;
+ else {
+ lprintf(LOG_NOTICE,
+ "lan set <channel> ipsrc <source>\n"
+ " none = unspecified\n"
+ " static = static address (manually configured)\n"
+ " dhcp = address obtained by BMC running DHCP\n"
+ " bios = address loaded by BIOS or system software\n");
+ return -1;
+ }
+ rc = set_lan_param(intf, chan, IPMI_LANP_IP_ADDR_SRC, data, 1);
+ }
+ /* session password
+ * not strictly a lan setting, but its used for lan connections */
+ else if (strncmp(argv[1], "password", 8) == 0) {
+ rc = ipmi_lan_set_password(intf, 1, (uint8_t *)argv[2]);
+ }
+ /* snmp community string */
+ else if (strncmp(argv[1], "snmp", 4) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_NOTICE, "lan set <channel> snmp <community string>");
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "lan set <channel> snmp <community string>");
+ return 0;
+ } else {
+ memcpy(data, argv[2], __min(strlen(argv[2]), 18));
+ printf("Setting LAN %s to %s\n",
+ ipmi_lan_params[IPMI_LANP_SNMP_STRING].desc, data);
+ rc = set_lan_param(intf, chan, IPMI_LANP_SNMP_STRING, data, 18);
+ }
+ }
+ /* ip address */
+ else if (strncmp(argv[1], "ipaddr", 6) == 0) {
+ if(argc != 3)
+ {
+ ipmi_lan_set_usage();
+ return -1;
+ }
+ rc = get_cmdline_ipaddr(argv[2], data);
+ if (rc == 0) {
+ printf("Setting LAN %s to %d.%d.%d.%d\n",
+ ipmi_lan_params[IPMI_LANP_IP_ADDR].desc,
+ data[0], data[1], data[2], data[3]);
+ rc = set_lan_param(intf, chan, IPMI_LANP_IP_ADDR, data, 4);
+ }
+ }
+ /* network mask */
+ else if (strncmp(argv[1], "netmask", 7) == 0) {
+ if(argc != 3)
+ {
+ ipmi_lan_set_usage();
+ return -1;
+ }
+ rc = get_cmdline_ipaddr(argv[2], data);
+ if (rc == 0) {
+ printf("Setting LAN %s to %d.%d.%d.%d\n",
+ ipmi_lan_params[IPMI_LANP_SUBNET_MASK].desc,
+ data[0], data[1], data[2], data[3]);
+ rc = set_lan_param(intf, chan, IPMI_LANP_SUBNET_MASK, data, 4);
+ }
+ }
+ /* mac address */
+ else if (strncmp(argv[1], "macaddr", 7) == 0) {
+ if(argc != 3)
+ {
+ ipmi_lan_set_usage();
+ return -1;
+ }
+ rc = get_cmdline_macaddr(argv[2], data);
+ if (rc == 0) {
+ printf("Setting LAN %s to %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ipmi_lan_params[IPMI_LANP_MAC_ADDR].desc,
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+ rc = set_lan_param(intf, chan, IPMI_LANP_MAC_ADDR, data, 6);
+ }
+ }
+ /* default gateway settings */
+ else if (strncmp(argv[1], "defgw", 5) == 0) {
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "LAN set default gateway Commands: ipaddr, macaddr");
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "LAN set default gateway Commands: ipaddr, macaddr");
+ return 0;
+ }
+ else if ((strncmp(argv[2], "ipaddr", 5) == 0) &&
+ (get_cmdline_ipaddr(argv[3], data) == 0)) {
+ printf("Setting LAN %s to %d.%d.%d.%d\n",
+ ipmi_lan_params[IPMI_LANP_DEF_GATEWAY_IP].desc,
+ data[0], data[1], data[2], data[3]);
+ rc = set_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_IP, data, 4);
+ }
+ else if ((strncmp(argv[2], "macaddr", 7) == 0) &&
+ (get_cmdline_macaddr(argv[3], data) == 0)) {
+ printf("Setting LAN %s to %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ipmi_lan_params[IPMI_LANP_DEF_GATEWAY_MAC].desc,
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+ rc = set_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_MAC, data, 6);
+ }
+ else {
+ ipmi_lan_set_usage();
+ return -1;
+ }
+ }
+ /* backup gateway settings */
+ else if (strncmp(argv[1], "bakgw", 5) == 0) {
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "LAN set backup gateway commands: ipaddr, macaddr");
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "LAN set backup gateway commands: ipaddr, macaddr");
+ return 0;
+ }
+ else if ((strncmp(argv[2], "ipaddr", 5) == 0) &&
+ (get_cmdline_ipaddr(argv[3], data) == 0)) {
+ printf("Setting LAN %s to %d.%d.%d.%d\n",
+ ipmi_lan_params[IPMI_LANP_BAK_GATEWAY_IP].desc,
+ data[0], data[1], data[2], data[3]);
+ rc = set_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_IP, data, 4);
+ }
+ else if ((strncmp(argv[2], "macaddr", 7) == 0) &&
+ (get_cmdline_macaddr(argv[3], data) == 0)) {
+ printf("Setting LAN %s to %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ipmi_lan_params[IPMI_LANP_BAK_GATEWAY_MAC].desc,
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+ rc = set_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_MAC, data, 6);
+ }
+ else {
+ ipmi_lan_set_usage();
+ return -1;
+ }
+ }
+ else if (strncasecmp(argv[1], "vlan", 4) == 0) {
+ if (argc < 4) {
+ ipmi_lan_set_vlan_usage();
+ return (-1);
+ }
+ else if (strncmp(argv[2], "help", 4) == 0) {
+ ipmi_lan_set_vlan_usage();
+ return 0;
+ }
+ else if (strncasecmp(argv[2], "id", 2) == 0) {
+ if (strncasecmp(argv[3], "off", 3) == 0) {
+ ipmi_lan_set_vlan_id(intf, chan, NULL);
+ }
+ else {
+ ipmi_lan_set_vlan_id(intf, chan, argv[3]);
+ }
+ }
+ else if (strncasecmp(argv[2], "priority", 8) == 0) {
+ ipmi_lan_set_vlan_priority(intf, chan, argv[3]);
+ }
+ else {
+ ipmi_lan_set_vlan_usage();
+ return (-1);
+ }
+ }
+ /* set PEF alerting on or off */
+ else if (strncasecmp(argv[1], "alert", 5) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_NOTICE, "LAN set alert must be 'on' or 'off'");
+ return (-1);
+ }
+ else if (strncasecmp(argv[2], "on", 2) == 0 ||
+ strncasecmp(argv[2], "enable", 6) == 0) {
+ printf("Enabling PEF alerts for LAN channel %d\n", chan);
+ rc = ipmi_set_alert_enable(intf, chan, 1);
+ }
+ else if (strncasecmp(argv[2], "off", 3) == 0 ||
+ strncasecmp(argv[2], "disable", 7) == 0) {
+ printf("Disabling PEF alerts for LAN channel %d\n", chan);
+ rc = ipmi_set_alert_enable(intf, chan, 0);
+ }
+ else {
+ lprintf(LOG_NOTICE, "LAN set alert must be 'on' or 'off'");
+ return 0;
+ }
+ }
+ /* RMCP+ cipher suite privilege levels */
+ else if (strncmp(argv[1], "cipher_privs", 12) == 0)
+ {
+ if (argc != 3) {
+ lprintf(LOG_NOTICE, "lan set <channel> cipher_privs XXXXXXXXXXXXXXX");
+ lprintf(LOG_NOTICE, " X = Cipher Suite Unused");
+ lprintf(LOG_NOTICE, " c = CALLBACK");
+ lprintf(LOG_NOTICE, " u = USER");
+ lprintf(LOG_NOTICE, " o = OPERATOR");
+ lprintf(LOG_NOTICE, " a = ADMIN");
+ lprintf(LOG_NOTICE, " O = OEM\n");
+ return (-1);
+ }
+ else if ((strncmp(argv[2], "help", 4) == 0) ||
+ get_cmdline_cipher_suite_priv_data(argv[2], data))
+ {
+ lprintf(LOG_NOTICE, "lan set <channel> cipher_privs XXXXXXXXXXXXXXX");
+ lprintf(LOG_NOTICE, " X = Cipher Suite Unused");
+ lprintf(LOG_NOTICE, " c = CALLBACK");
+ lprintf(LOG_NOTICE, " u = USER");
+ lprintf(LOG_NOTICE, " o = OPERATOR");
+ lprintf(LOG_NOTICE, " a = ADMIN");
+ lprintf(LOG_NOTICE, " O = OEM\n");
+ return 0;
+ }
+ else
+ {
+ rc = set_lan_param(intf, chan, IPMI_LANP_RMCP_PRIV_LEVELS, data, 9);
+ }
+ }
+ else {
+ ipmi_lan_set_usage();
+ return (-1);
+ }
+
+ return rc;
+}
+
+
+static int
+is_alert_destination(struct ipmi_intf * intf, uint8_t channel, uint8_t alert)
+{
+ struct lan_param * p;
+
+ p = get_lan_param(intf, channel, IPMI_LANP_NUM_DEST);
+ if (p == NULL)
+ return 0;
+ if (p->data == NULL)
+ return 0;
+
+ if (alert <= (p->data[0] & 0xf))
+ return 1;
+ else
+ return 0;
+}
+
+static int
+ipmi_lan_alert_print(struct ipmi_intf * intf, uint8_t channel, uint8_t alert)
+{
+# define PTYPE_LEN 4
+# define PADDR_LEN 13
+ struct lan_param *lp_ptr = NULL;
+ int isack = 0;
+ uint8_t ptype[PTYPE_LEN];
+ uint8_t paddr[PADDR_LEN];
+
+ lp_ptr = get_lan_param_select(intf, channel, IPMI_LANP_DEST_TYPE, alert);
+ if (lp_ptr == NULL || lp_ptr->data == NULL
+ || lp_ptr->data_len < PTYPE_LEN) {
+ return (-1);
+ }
+ memcpy(ptype, lp_ptr->data, PTYPE_LEN);
+
+ lp_ptr = get_lan_param_select(intf, channel, IPMI_LANP_DEST_ADDR, alert);
+ if (lp_ptr == NULL || lp_ptr->data == NULL
+ || lp_ptr->data_len < PADDR_LEN) {
+ return (-1);
+ }
+ memcpy(paddr, lp_ptr->data, PADDR_LEN);
+
+ printf("%-24s: %d\n", "Alert Destination",
+ ptype[0]);
+
+ if (ptype[1] & 0x80) {
+ isack = 1;
+ }
+ printf("%-24s: %s\n", "Alert Acknowledge",
+ isack ? "Acknowledged" : "Unacknowledged");
+
+ printf("%-24s: ", "Destination Type");
+ switch (ptype[1] & 0x7) {
+ case 0:
+ printf("PET Trap\n");
+ break;
+ case 6:
+ printf("OEM 1\n");
+ break;
+ case 7:
+ printf("OEM 2\n");
+ break;
+ default:
+ printf("Unknown\n");
+ break;
+ }
+
+ printf("%-24s: %d\n",
+ isack ? "Acknowledge Timeout" : "Retry Interval",
+ ptype[2]);
+
+ printf("%-24s: %d\n", "Number of Retries",
+ ptype[3] & 0x7);
+
+ if ((paddr[1] & 0xf0) != 0) {
+ /* unknown address format */
+ printf("\n");
+ return 0;
+ }
+
+ printf("%-24s: %s\n", "Alert Gateway",
+ (paddr[2] & 1) ? "Backup" : "Default");
+
+ printf("%-24s: %d.%d.%d.%d\n", "Alert IP Address",
+ paddr[3], paddr[4], paddr[5], paddr[6]);
+
+ printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", "Alert MAC Address",
+ paddr[7], paddr[8], paddr[9],
+ paddr[10], paddr[11], paddr[12]);
+
+ printf("\n");
+ return 0;
+}
+
+static int
+ipmi_lan_alert_print_all(struct ipmi_intf * intf, uint8_t channel)
+{
+ int j, ndest;
+ struct lan_param * p;
+
+ p = get_lan_param(intf, channel, IPMI_LANP_NUM_DEST);
+ if (p == NULL)
+ return -1;
+ if (p->data == NULL)
+ return -1;
+ ndest = p->data[0] & 0xf;
+
+ for (j=0; j<=ndest; j++) {
+ ipmi_lan_alert_print(intf, channel, j);
+ }
+
+ return 0;
+}
+
+static void
+ipmi_lan_alert_print_usage(void)
+{
+ lprintf(LOG_NOTICE, "\nusage: lan alert print [channel number] [alert destination]\n");
+ lprintf(LOG_NOTICE, "Default will print all alerts for the first found LAN channel");
+}
+
+static void
+ipmi_lan_alert_set_usage(void)
+{
+ lprintf(LOG_NOTICE, "\nusage: lan alert set <channel number> <alert destination> <command> <parameter>\n");
+ lprintf(LOG_NOTICE, " Command/parameter options:\n");
+ lprintf(LOG_NOTICE, " ipaddr <x.x.x.x> Set alert IP address");
+ lprintf(LOG_NOTICE, " macaddr <x:x:x:x:x:x> Set alert MAC address");
+ lprintf(LOG_NOTICE, " gateway <default|backup> Set channel gateway to use for alerts");
+ lprintf(LOG_NOTICE, " ack <on|off> Set Alert Acknowledge on or off");
+ lprintf(LOG_NOTICE, " type <pet|oem1|oem2> Set destination type as PET or OEM");
+ lprintf(LOG_NOTICE, " time <seconds> Set ack timeout or unack retry interval");
+ lprintf(LOG_NOTICE, " retry <number> Set number of alert retries");
+ lprintf(LOG_NOTICE, "");
+}
+
+static int
+ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
+ int argc, char ** argv)
+{
+ struct lan_param * p;
+ uint8_t data[32], temp[32];
+ int rc = 0;
+
+ if (argc < 2) {
+ ipmi_lan_alert_set_usage();
+ return (-1);
+ }
+
+ if (strncmp(argv[0], "help", 4) == 0 ||
+ strncmp(argv[1], "help", 4) == 0) {
+ ipmi_lan_alert_set_usage();
+ return 0;
+ }
+
+ memset(data, 0, sizeof(data));
+ memset(temp, 0, sizeof(temp));
+
+ /* alert destination ip address */
+ if (strncasecmp(argv[0], "ipaddr", 6) == 0 &&
+ (get_cmdline_ipaddr(argv[1], temp) == 0)) {
+ /* get current parameter */
+ p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_ADDR, alert);
+ if (p == NULL) {
+ return (-1);
+ }
+ memcpy(data, p->data, p->data_len);
+ /* set new ipaddr */
+ memcpy(data+3, temp, 4);
+ printf("Setting LAN Alert %d IP Address to %d.%d.%d.%d\n", alert,
+ data[3], data[4], data[5], data[6]);
+ rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_ADDR, data, p->data_len);
+ }
+ /* alert destination mac address */
+ else if (strncasecmp(argv[0], "macaddr", 7) == 0 &&
+ (get_cmdline_macaddr(argv[1], temp) == 0)) {
+ /* get current parameter */
+ p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_ADDR, alert);
+ if (p == NULL) {
+ return (-1);
+ }
+ memcpy(data, p->data, p->data_len);
+ /* set new macaddr */
+ memcpy(data+7, temp, 6);
+ printf("Setting LAN Alert %d MAC Address to "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", alert,
+ data[7], data[8], data[9], data[10], data[11], data[12]);
+ rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_ADDR, data, p->data_len);
+ }
+ /* alert destination gateway selector */
+ else if (strncasecmp(argv[0], "gateway", 7) == 0) {
+ /* get current parameter */
+ p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_ADDR, alert);
+ if (p == NULL) {
+ return (-1);
+ }
+ memcpy(data, p->data, p->data_len);
+
+ if (strncasecmp(argv[1], "def", 3) == 0 ||
+ strncasecmp(argv[1], "default", 7) == 0) {
+ printf("Setting LAN Alert %d to use Default Gateway\n", alert);
+ data[2] = 0;
+ }
+ else if (strncasecmp(argv[1], "bak", 3) == 0 ||
+ strncasecmp(argv[1], "backup", 6) == 0) {
+ printf("Setting LAN Alert %d to use Backup Gateway\n", alert);
+ data[2] = 1;
+ }
+ else {
+ ipmi_lan_alert_set_usage();
+ return -1;
+ }
+
+ rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_ADDR, data, p->data_len);
+ }
+ /* alert acknowledgement */
+ else if (strncasecmp(argv[0], "ack", 3) == 0) {
+ /* get current parameter */
+ p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert);
+ if (p == NULL) {
+ return (-1);
+ }
+ memcpy(data, p->data, p->data_len);
+
+ if (strncasecmp(argv[1], "on", 2) == 0 ||
+ strncasecmp(argv[1], "yes", 3) == 0) {
+ printf("Setting LAN Alert %d to Acknowledged\n", alert);
+ data[1] |= 0x80;
+ }
+ else if (strncasecmp(argv[1], "off", 3) == 0 ||
+ strncasecmp(argv[1], "no", 2) == 0) {
+ printf("Setting LAN Alert %d to Unacknowledged\n", alert);
+ data[1] &= ~0x80;
+ }
+ else {
+ ipmi_lan_alert_set_usage();
+ return -1;
+ }
+ rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len);
+ }
+ /* alert destination type */
+ else if (strncasecmp(argv[0], "type", 4) == 0) {
+ /* get current parameter */
+ p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert);
+ if (p == NULL) {
+ return (-1);
+ }
+ memcpy(data, p->data, p->data_len);
+
+ if (strncasecmp(argv[1], "pet", 3) == 0) {
+ printf("Setting LAN Alert %d destination to PET Trap\n", alert);
+ data[1] &= ~0x07;
+ }
+ else if (strncasecmp(argv[1], "oem1", 4) == 0) {
+ printf("Setting LAN Alert %d destination to OEM 1\n", alert);
+ data[1] &= ~0x07;
+ data[1] |= 0x06;
+ }
+ else if (strncasecmp(argv[1], "oem2", 4) == 0) {
+ printf("Setting LAN Alert %d destination to OEM 2\n", alert);
+ data[1] |= 0x07;
+ }
+ else {
+ ipmi_lan_alert_set_usage();
+ return -1;
+ }
+ rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len);
+ }
+ /* alert acknowledge timeout or retry interval */
+ else if (strncasecmp(argv[0], "time", 4) == 0) {
+ /* get current parameter */
+ p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert);
+ if (p == NULL) {
+ return (-1);
+ }
+ memcpy(data, p->data, p->data_len);
+
+ if (str2uchar(argv[1], &data[2]) != 0) {
+ lprintf(LOG_ERR, "Invalid time: %s", argv[1]);
+ return (-1);
+ }
+ printf("Setting LAN Alert %d timeout/retry to %d seconds\n", alert, data[2]);
+ rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len);
+ }
+ /* number of retries */
+ else if (strncasecmp(argv[0], "retry", 5) == 0) {
+ /* get current parameter */
+ p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert);
+ if (p == NULL) {
+ return (-1);
+ }
+ memcpy(data, p->data, p->data_len);
+
+ if (str2uchar(argv[1], &data[3]) != 0) {
+ lprintf(LOG_ERR, "Invalid retry: %s", argv[1]);
+ return (-1);
+ }
+ data[3] = data[3] & 0x7;
+ printf("Setting LAN Alert %d number of retries to %d\n", alert, data[3]);
+ rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len);
+ }
+ else {
+ ipmi_lan_alert_set_usage();
+ return -1;
+ }
+
+ return rc;
+}
+
+static int
+ipmi_lan_alert(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ uint8_t alert;
+ uint8_t channel = 1;
+
+ if (argc < 1) {
+ ipmi_lan_alert_print_usage();
+ ipmi_lan_alert_set_usage();
+ return (-1);
+ }
+ else if (strncasecmp(argv[0], "help", 4) == 0) {
+ ipmi_lan_alert_print_usage();
+ ipmi_lan_alert_set_usage();
+ return 0;
+ }
+
+ /* alert print [channel] [alert] */
+ if (strncasecmp(argv[0], "print", 5) == 0) {
+ if (argc < 2) {
+ channel = find_lan_channel(intf, 1);
+ if (!is_lan_channel(intf, channel)) {
+ lprintf(LOG_ERR, "Channel %d is not a LAN channel", channel);
+ return -1;
+ }
+ return ipmi_lan_alert_print_all(intf, channel);
+ }
+
+ if (strncasecmp(argv[1], "help", 4) == 0) {
+ ipmi_lan_alert_print_usage();
+ return 0;
+ }
+
+ if (str2uchar(argv[1], &channel) != 0) {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[1]);
+ return (-1);
+ }
+ if (!is_lan_channel(intf, channel)) {
+ lprintf(LOG_ERR, "Channel %d is not a LAN channel", channel);
+ return -1;
+ }
+
+ if (argc < 3)
+ return ipmi_lan_alert_print_all(intf, channel);
+
+ if (str2uchar(argv[2], &alert) != 0) {
+ lprintf(LOG_ERR, "Invalid alert: %s", argv[2]);
+ return (-1);
+ }
+ if (is_alert_destination(intf, channel, alert) == 0) {
+ lprintf(LOG_ERR, "Alert %d is not a valid destination", alert);
+ return -1;
+ }
+ return ipmi_lan_alert_print(intf, channel, alert);
+ }
+
+ /* alert set <channel> <alert> [option] */
+ if (strncasecmp(argv[0], "set", 3) == 0) {
+ if (argc < 5) {
+ ipmi_lan_alert_set_usage();
+ return (-1);
+ }
+ else if (strncasecmp(argv[1], "help", 4) == 0) {
+ ipmi_lan_alert_set_usage();
+ return 0;
+ }
+
+ if (str2uchar(argv[1], &channel) != 0) {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[1]);
+ return (-1);
+ }
+ if (!is_lan_channel(intf, channel)) {
+ lprintf(LOG_ERR, "Channel %d is not a LAN channel", channel);
+ return -1;
+ }
+
+ if (str2uchar(argv[2], &alert) != 0) {
+ lprintf(LOG_ERR, "Invalid alert: %s", argv[2]);
+ return (-1);
+ }
+ if (is_alert_destination(intf, channel, alert) == 0) {
+ lprintf(LOG_ERR, "Alert %d is not a valid destination", alert);
+ return -1;
+ }
+
+ return ipmi_lan_alert_set(intf, channel, alert, argc-3, &(argv[3]));
+ }
+
+ return 0;
+}
+
+
+static int
+ipmi_lan_stats_get(struct ipmi_intf * intf, uint8_t chan)
+{
+ int rc = 0;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[2];
+ uint16_t statsTemp;
+
+ if (!is_lan_channel(intf, chan)) {
+ lprintf(LOG_ERR, "Channel %d is not a LAN channel", chan);
+ return -1;
+ }
+
+ /* From here, we are ready to get the stats */
+
+ msg_data[0] = chan;
+ msg_data[1] = 0; /* Don't clear */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_LAN_GET_STAT;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get LAN Stats command failed");
+ return (-1);
+ }
+
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get LAN Stats command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ if (verbose > 1) {
+ uint8_t counter;
+ printf("--- Rx Stats ---\n");
+ for (counter=0; counter<18; counter+=2) {
+ printf("%02X", *(rsp->data + counter));
+ printf(" %02X - ", *(rsp->data + counter+1));
+ }
+ printf("\n");
+ }
+
+ statsTemp = ((*(rsp->data + 0)) << 8) | (*(rsp->data + 1));
+ printf("IP Rx Packet : %d\n", statsTemp);
+
+ statsTemp = ((*(rsp->data + 2)) << 8) | (*(rsp->data + 3));
+ printf("IP Rx Header Errors : %u\n", statsTemp);
+
+ statsTemp = ((*(rsp->data + 4)) << 8) | (*(rsp->data + 5));
+ printf("IP Rx Address Errors : %u\n", statsTemp);
+
+ statsTemp = ((*(rsp->data + 6)) << 8) | (*(rsp->data + 7));
+ printf("IP Rx Fragmented : %u\n", statsTemp);
+
+ statsTemp = ((*(rsp->data + 8)) << 8) | (*(rsp->data + 9));
+ printf("IP Tx Packet : %u\n", statsTemp);
+
+ statsTemp = ((*(rsp->data +10)) << 8) | (*(rsp->data +11));
+ printf("UDP Rx Packet : %u\n", statsTemp);
+
+ statsTemp = ((*(rsp->data + 12)) << 8) | (*(rsp->data + 13));
+ printf("RMCP Rx Valid : %u\n", statsTemp);
+
+ statsTemp = ((*(rsp->data + 14)) << 8) | (*(rsp->data + 15));
+ printf("UDP Proxy Packet Received : %u\n", statsTemp);
+
+ statsTemp = ((*(rsp->data + 16)) << 8) | (*(rsp->data + 17));
+ printf("UDP Proxy Packet Dropped : %u\n", statsTemp);
+
+ return rc;
+}
+
+
+static int
+ipmi_lan_stats_clear(struct ipmi_intf * intf, uint8_t chan)
+{
+ int rc = 0;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[2];
+
+ if (!is_lan_channel(intf, chan)) {
+ lprintf(LOG_ERR, "Channel %d is not a LAN channel", chan);
+ return -1;
+ }
+
+ /* From here, we are ready to get the stats */
+ msg_data[0] = chan;
+ msg_data[1] = 1; /* Clear */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_LAN_GET_STAT;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_INFO, "Get LAN Stats command failed");
+ return (-1);
+ }
+
+ if (rsp->ccode > 0) {
+ lprintf(LOG_INFO, "Get LAN Stats command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ return rc;
+}
+
+
+/*
+ * print_lan_usage
+ */
+static void
+print_lan_usage(void)
+{
+ lprintf(LOG_NOTICE, "LAN Commands:");
+ lprintf(LOG_NOTICE, " print [<channel number>]");
+ lprintf(LOG_NOTICE, " set <channel number> <command> <parameter>");
+ lprintf(LOG_NOTICE, " alert print <channel number> <alert destination>");
+ lprintf(LOG_NOTICE, " alert set <channel number> <alert destination> <command> <parameter>");
+ lprintf(LOG_NOTICE, " stats get [<channel number>]");
+ lprintf(LOG_NOTICE, " stats clear [<channel number>]");
+}
+
+
+int
+ipmi_lanp_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ uint8_t chan = 0;
+
+ if (argc == 0) {
+ print_lan_usage();
+ return (-1);
+ } else if (strncmp(argv[0], "help", 4) == 0) {
+ print_lan_usage();
+ return 0;
+ }
+
+ chan = find_lan_channel(intf, 1);
+
+ if (strncmp(argv[0], "printconf", 9) == 0 ||
+ strncmp(argv[0], "print", 5) == 0)
+ {
+ if (argc > 2) {
+ print_lan_usage();
+ return (-1);
+ } else if (argc == 2) {
+ if (str2uchar(argv[1], &chan) != 0) {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[1]);
+ return (-1);
+ }
+ }
+ if (!is_lan_channel(intf, chan)) {
+ lprintf(LOG_ERR, "Invalid channel: %d", chan);
+ return (-1);
+ }
+ rc = ipmi_lan_print(intf, chan);
+ } else if (strncmp(argv[0], "set", 3) == 0) {
+ rc = ipmi_lan_set(intf, argc-1, &(argv[1]));
+ } else if (strncmp(argv[0], "alert", 5) == 0) {
+ rc = ipmi_lan_alert(intf, argc-1, &(argv[1]));
+ } else if (strncmp(argv[0], "stats", 5) == 0) {
+ if (argc < 2) {
+ print_lan_usage();
+ return (-1);
+ } else if (argc == 3) {
+ if (str2uchar(argv[2], &chan) != 0) {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[2]);
+ return (-1);
+ }
+ }
+ if (!is_lan_channel(intf, chan)) {
+ lprintf(LOG_ERR, "Invalid channel: %d", chan);
+ return (-1);
+ }
+ if (strncmp(argv[1], "get", 3) == 0) {
+ rc = ipmi_lan_stats_get(intf, chan);
+ } else if (strncmp(argv[1], "clear", 5) == 0) {
+ rc = ipmi_lan_stats_clear(intf, chan);
+ } else {
+ print_lan_usage();
+ return (-1);
+ }
+ } else {
+ lprintf(LOG_NOTICE, "Invalid LAN command: %s", argv[0]);
+ return (-1);
+ }
+ return rc;
+}
diff --git a/lib/ipmi_main.c b/lib/ipmi_main.c
new file mode 100644
index 0000000..14ca183
--- /dev/null
+++ b/lib/ipmi_main.c
@@ -0,0 +1,1063 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_session.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_gendev.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_fru.h>
+#include <ipmitool/ipmi_sol.h>
+#include <ipmitool/ipmi_isol.h>
+#include <ipmitool/ipmi_lanp.h>
+#include <ipmitool/ipmi_chassis.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_firewall.h>
+#include <ipmitool/ipmi_sensor.h>
+#include <ipmitool/ipmi_channel.h>
+#include <ipmitool/ipmi_session.h>
+#include <ipmitool/ipmi_event.h>
+#include <ipmitool/ipmi_user.h>
+#include <ipmitool/ipmi_raw.h>
+#include <ipmitool/ipmi_pef.h>
+#include <ipmitool/ipmi_oem.h>
+#include <ipmitool/ipmi_ekanalyzer.h>
+#include <ipmitool/ipmi_picmg.h>
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef ENABLE_ALL_OPTIONS
+# define OPTION_STRING "I:hVvcgsEKYao:H:d:P:f:U:p:C:L:A:t:T:m:z:S:l:b:B:e:k:y:O:R:N:D:"
+#else
+# define OPTION_STRING "I:hVvcH:f:U:p:d:S:D:"
+#endif
+
+extern int verbose;
+extern int csv_output;
+extern const struct valstr ipmi_privlvl_vals[];
+extern const struct valstr ipmi_authtype_session_vals[];
+
+static struct ipmi_intf * ipmi_main_intf = NULL;
+
+/* ipmi_password_file_read - Open file and read password from it
+ *
+ * @filename: file name to read from
+ *
+ * returns pointer to allocated buffer containing password
+ * (caller is expected to free when finished)
+ * returns NULL on error
+ */
+static char *
+ipmi_password_file_read(char * filename)
+{
+ FILE * fp;
+ char * pass = NULL;
+ int l;
+
+ pass = malloc(21);
+ if (pass == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+
+ memset(pass, 0, 21);
+ fp = ipmi_open_file_read((const char *)filename);
+ if (fp == NULL) {
+ lprintf(LOG_ERR, "Unable to open password file %s",
+ filename);
+ free(pass);
+ return NULL;
+ }
+
+ /* read in id */
+ if (fgets(pass, 21, fp) == NULL) {
+ lprintf(LOG_ERR, "Unable to read password from file %s",
+ filename);
+ free(pass);
+ fclose(fp);
+ return NULL;
+ }
+
+ /* remove trailing whitespace */
+ l = strcspn(pass, " \r\n\t");
+ if (l > 0) {
+ pass[l] = '\0';
+ }
+
+ fclose(fp);
+ return pass;
+}
+
+
+/*
+ * Print all the commands in the above table to stderr
+ * used for help text on command line and shell
+ */
+void
+ipmi_cmd_print(struct ipmi_cmd * cmdlist)
+{
+ struct ipmi_cmd * cmd;
+ int hdr = 0;
+
+ if (cmdlist == NULL)
+ return;
+ for (cmd=cmdlist; cmd->func != NULL; cmd++) {
+ if (cmd->desc == NULL)
+ continue;
+ if (hdr == 0) {
+ lprintf(LOG_NOTICE, "Commands:");
+ hdr = 1;
+ }
+ lprintf(LOG_NOTICE, "\t%-12s %s", cmd->name, cmd->desc);
+ }
+ lprintf(LOG_NOTICE, "");
+}
+
+/* ipmi_cmd_run - run a command from list based on parameters
+ * called from main()
+ *
+ * 1. iterate through ipmi_cmd_list matching on name
+ * 2. call func() for that command
+ *
+ * @intf: ipmi interface
+ * @name: command name
+ * @argc: command argument count
+ * @argv: command argument list
+ *
+ * returns value from func() of that commnad if found
+ * returns -1 if command is not found
+ */
+int
+ipmi_cmd_run(struct ipmi_intf * intf, char * name, int argc, char ** argv)
+{
+ struct ipmi_cmd * cmd = intf->cmdlist;
+
+ /* hook to run a default command if nothing specified */
+ if (name == NULL) {
+ if (cmd->func == NULL || cmd->name == NULL)
+ return -1;
+ else if (strncmp(cmd->name, "default", 7) == 0)
+ return cmd->func(intf, 0, NULL);
+ else {
+ lprintf(LOG_ERR, "No command provided!");
+ ipmi_cmd_print(intf->cmdlist);
+ return -1;
+ }
+ }
+
+ for (cmd=intf->cmdlist; cmd->func != NULL; cmd++) {
+ if (strncmp(name, cmd->name, __maxlen(cmd->name, name)) == 0)
+ break;
+ }
+ if (cmd->func == NULL) {
+ cmd = intf->cmdlist;
+ if (strncmp(cmd->name, "default", 7) == 0)
+ return cmd->func(intf, argc+1, argv-1);
+
+ lprintf(LOG_ERR, "Invalid command: %s", name);
+ ipmi_cmd_print(intf->cmdlist);
+ return -1;
+ }
+ return cmd->func(intf, argc, argv);
+}
+
+static void
+ipmi_option_usage(const char * progname, struct ipmi_cmd * cmdlist, struct ipmi_intf_support * intflist)
+{
+ lprintf(LOG_NOTICE, "%s version %s\n", progname, VERSION);
+ lprintf(LOG_NOTICE, "usage: %s [options...] <command>\n", progname);
+ lprintf(LOG_NOTICE, " -h This help");
+ lprintf(LOG_NOTICE, " -V Show version information");
+ lprintf(LOG_NOTICE, " -v Verbose (can use multiple times)");
+ lprintf(LOG_NOTICE, " -c Display output in comma separated format");
+ lprintf(LOG_NOTICE, " -d N Specify a /dev/ipmiN device to use (default=0)");
+ lprintf(LOG_NOTICE, " -I intf Interface to use");
+ lprintf(LOG_NOTICE, " -H hostname Remote host name for LAN interface");
+ lprintf(LOG_NOTICE, " -p port Remote RMCP port [default=623]");
+ lprintf(LOG_NOTICE, " -U username Remote session username");
+ lprintf(LOG_NOTICE, " -f file Read remote session password from file");
+ lprintf(LOG_NOTICE, " -z size Change Size of Communication Channel (OEM)");
+ lprintf(LOG_NOTICE, " -S sdr Use local file for remote SDR cache");
+ lprintf(LOG_NOTICE, " -D tty:b[:s] Specify the serial device, baud rate to use");
+ lprintf(LOG_NOTICE, " and, optionally, specify that interface is the system one");
+#ifdef ENABLE_ALL_OPTIONS
+ lprintf(LOG_NOTICE, " -a Prompt for remote password");
+ lprintf(LOG_NOTICE, " -Y Prompt for the Kg key for IPMIv2 authentication");
+ lprintf(LOG_NOTICE, " -e char Set SOL escape character");
+ lprintf(LOG_NOTICE, " -C ciphersuite Cipher suite to be used by lanplus interface");
+ lprintf(LOG_NOTICE, " -k key Use Kg key for IPMIv2 authentication");
+ lprintf(LOG_NOTICE, " -y hex_key Use hexadecimal-encoded Kg key for IPMIv2 authentication");
+ lprintf(LOG_NOTICE, " -L level Remote session privilege level [default=ADMINISTRATOR]");
+ lprintf(LOG_NOTICE, " Append a '+' to use name/privilege lookup in RAKP1");
+ lprintf(LOG_NOTICE, " -A authtype Force use of auth type NONE, PASSWORD, MD2, MD5 or OEM");
+ lprintf(LOG_NOTICE, " -P password Remote session password");
+ lprintf(LOG_NOTICE, " -E Read password from IPMI_PASSWORD environment variable");
+ lprintf(LOG_NOTICE, " -K Read kgkey from IPMI_KGKEY environment variable");
+ lprintf(LOG_NOTICE, " -m address Set local IPMB address");
+ lprintf(LOG_NOTICE, " -b channel Set destination channel for bridged request");
+ lprintf(LOG_NOTICE, " -t address Bridge request to remote target address");
+ lprintf(LOG_NOTICE, " -B channel Set transit channel for bridged request (dual bridge)");
+ lprintf(LOG_NOTICE, " -T address Set transit address for bridge request (dual bridge)");
+ lprintf(LOG_NOTICE, " -l lun Set destination lun for raw commands");
+ lprintf(LOG_NOTICE, " -o oemtype Setup for OEM (use 'list' to see available OEM types)");
+ lprintf(LOG_NOTICE, " -O seloem Use file for OEM SEL event descriptions");
+ lprintf(LOG_NOTICE, " -N seconds Specify timeout for lan [default=2] / lanplus [default=1] interface");
+ lprintf(LOG_NOTICE, " -R retry Set the number of retries for lan/lanplus interface [default=4]");
+#endif
+ lprintf(LOG_NOTICE, "");
+
+ ipmi_intf_print(intflist);
+
+ if (cmdlist != NULL)
+ ipmi_cmd_print(cmdlist);
+}
+/* ipmi_catch_sigint - Handle the interrupt signal (Ctrl-C), close the
+ * interface, and exit ipmitool with error (-1)
+ *
+ * This insures that the IOL session gets freed
+ * for other callers.
+ *
+ * returns -1
+ */
+void ipmi_catch_sigint()
+{
+ if (ipmi_main_intf != NULL) {
+ printf("\nSIGN INT: Close Interface %s\n",ipmi_main_intf->desc);
+ ipmi_main_intf->close(ipmi_main_intf);
+ }
+ exit(-1);
+}
+
+/* ipmi_parse_hex - convert hexadecimal numbers to ascii string
+ * Input string must be composed of two-characer hexadecimal numbers.
+ * There is no separator between the numbers. Each number results in one character
+ * of the converted string.
+ *
+ * Example: ipmi_parse_hex("50415353574F5244") returns 'PASSWORD'
+ *
+ * @param str: input string. It must contain only even number of '0'-'9','a'-'f' and 'A-F' characters.
+ * @returns converted ascii string
+ * @returns NULL on error
+ */
+static unsigned char *
+ipmi_parse_hex(const char *str)
+{
+ const char * p;
+ unsigned char * out, *q;
+ unsigned char b = 0;
+ int shift = 4;
+
+ if (strlen(str) == 0)
+ return NULL;
+
+ if (strlen(str) % 2 != 0) {
+ lprintf(LOG_ERR, "Number of hex_kg characters is not even");
+ return NULL;
+ }
+
+ if (strlen(str) > (IPMI_KG_BUFFER_SIZE-1)*2) {
+ lprintf(LOG_ERR, "Kg key is too long");
+ return NULL;
+ }
+
+ out = calloc(IPMI_KG_BUFFER_SIZE, sizeof(unsigned char));
+ if (out == NULL) {
+ lprintf(LOG_ERR, "malloc failure");
+ return NULL;
+ }
+
+ for (p = str, q = out; *p; p++) {
+ if (!isxdigit(*p)) {
+ lprintf(LOG_ERR, "Kg_hex is not hexadecimal number");
+ free(out);
+ out = NULL;
+ return NULL;
+ }
+
+ if (*p < 'A') /* it must be 0-9 */
+ b = *p - '0';
+ else /* it's A-F or a-f */
+ b = (*p | 0x20) - 'a' + 10; /* convert to lowercase and to 10-15 */
+
+ *q = *q + b << shift;
+ if (shift)
+ shift = 0;
+ else {
+ shift = 4;
+ q++;
+ }
+ }
+
+ return out;
+}
+
+/* ipmi_parse_options - helper function to handle parsing command line options
+ *
+ * @argc: count of options
+ * @argv: list of options
+ * @cmdlist: list of supported commands
+ * @intflist: list of supported interfaces
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_main(int argc, char ** argv,
+ struct ipmi_cmd * cmdlist,
+ struct ipmi_intf_support * intflist)
+{
+ struct ipmi_intf_support * sup;
+ int privlvl = 0;
+ uint8_t target_addr = 0;
+ uint8_t target_channel = 0;
+
+ uint8_t transit_addr = 0;
+ uint8_t transit_channel = 0;
+ uint8_t target_lun = 0;
+ uint8_t arg_addr = 0;
+ uint8_t addr = 0;
+ uint16_t my_long_packet_size=0;
+ uint8_t my_long_packet_set=0;
+ uint8_t lookupbit = 0x10; /* use name-only lookup by default */
+ int retry = 0;
+ uint32_t timeout = 0;
+ int authtype = -1;
+ char * tmp_pass = NULL;
+ char * tmp_env = NULL;
+ char * hostname = NULL;
+ char * username = NULL;
+ char * password = NULL;
+ char * intfname = NULL;
+ char * progname = NULL;
+ char * oemtype = NULL;
+ char * sdrcache = NULL;
+ unsigned char * kgkey = NULL;
+ char * seloem = NULL;
+ int port = 0;
+ int devnum = 0;
+ int cipher_suite_id = 3; /* See table 22-19 of the IPMIv2 spec */
+ int argflag, i, found;
+ int rc = -1;
+ char sol_escape_char = SOL_ESCAPE_CHARACTER_DEFAULT;
+ char * devfile = NULL;
+
+ /* save program name */
+ progname = strrchr(argv[0], '/');
+ progname = ((progname == NULL) ? argv[0] : progname+1);
+ signal(SIGINT, ipmi_catch_sigint);
+
+ while ((argflag = getopt(argc, (char **)argv, OPTION_STRING)) != -1)
+ {
+ switch (argflag) {
+ case 'I':
+ if (intfname) {
+ free(intfname);
+ intfname = NULL;
+ }
+ intfname = strdup(optarg);
+ if (intfname == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ if (intflist != NULL) {
+ found = 0;
+ for (sup=intflist; sup->name != NULL; sup++) {
+ if (strncmp(sup->name, intfname, strlen(intfname)) == 0 &&
+ strncmp(sup->name, intfname, strlen(sup->name)) == 0 &&
+ sup->supported == 1)
+ found = 1;
+ }
+ if (!found) {
+ lprintf(LOG_ERR, "Interface %s not supported", intfname);
+ goto out_free;
+ }
+ }
+ break;
+ case 'h':
+ ipmi_option_usage(progname, cmdlist, intflist);
+ rc = 0;
+ goto out_free;
+ break;
+ case 'V':
+ printf("%s version %s\n", progname, VERSION);
+ rc = 0;
+ goto out_free;
+ break;
+ case 'd':
+ if (str2int(optarg, &devnum) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-d'.");
+ rc = -1;
+ goto out_free;
+ }
+ /* Check if device number is -gt 0; I couldn't find limit for
+ * kernels > 2.6, thus right side is unlimited.
+ */
+ if (devnum < 0) {
+ lprintf(LOG_ERR, "Device number %i is out of range.", devnum);
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'p':
+ if (str2int(optarg, &port) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-p'.");
+ rc = -1;
+ goto out_free;
+ }
+ /* Check if port is -gt 0 && port is -lt 65535 */
+ if (port < 0 || port > 65535) {
+ lprintf(LOG_ERR, "Port number %i is out of range.", port);
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'C':
+ if (str2int(optarg, &cipher_suite_id) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-C'.");
+ rc = -1;
+ goto out_free;
+ }
+ /* add check Cipher is -gt 0 */
+ if (cipher_suite_id < 0) {
+ lprintf(LOG_ERR, "Cipher suite ID %i is invalid.", cipher_suite_id);
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'c':
+ csv_output = 1;
+ break;
+ case 'H':
+ if (hostname) {
+ free(hostname);
+ hostname = NULL;
+ }
+ hostname = strdup(optarg);
+ if (hostname == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ break;
+ case 'f':
+ if (password) {
+ free(password);
+ password = NULL;
+ }
+ password = ipmi_password_file_read(optarg);
+ if (password == NULL)
+ lprintf(LOG_ERR, "Unable to read password "
+ "from file %s", optarg);
+ break;
+ case 'a':
+#ifdef HAVE_GETPASSPHRASE
+ tmp_pass = getpassphrase("Password: ");
+#else
+ tmp_pass = getpass("Password: ");
+#endif
+ if (tmp_pass != NULL) {
+ if (password) {
+ free(password);
+ password = NULL;
+ }
+ password = strdup(tmp_pass);
+ tmp_pass = NULL;
+ if (password == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ }
+ break;
+ case 'k':
+ if (kgkey) {
+ free(kgkey);
+ kgkey = NULL;
+ }
+ kgkey = strdup(optarg);
+ if (kgkey == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ break;
+ case 'K':
+ if ((tmp_env = getenv("IPMI_KGKEY"))) {
+ if (kgkey) {
+ free(kgkey);
+ kgkey = NULL;
+ }
+ kgkey = strdup(tmp_env);
+ if (kgkey == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ } else {
+ lprintf(LOG_WARN, "Unable to read kgkey from environment");
+ }
+ break;
+ case 'y':
+ if (kgkey) {
+ free(kgkey);
+ kgkey = NULL;
+ }
+ kgkey = ipmi_parse_hex(optarg);
+ if (kgkey == NULL) {
+ goto out_free;
+ }
+ break;
+ case 'Y':
+#ifdef HAVE_GETPASSPHRASE
+ tmp_pass = getpassphrase("Key: ");
+#else
+ tmp_pass = getpass("Key: ");
+#endif
+ if (tmp_pass != NULL) {
+ if (kgkey) {
+ free(kgkey);
+ kgkey = NULL;
+ }
+ kgkey = strdup(tmp_pass);
+ tmp_pass = NULL;
+ if (kgkey == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ }
+ break;
+ case 'U':
+ if (username) {
+ free(username);
+ username = NULL;
+ }
+ if (strlen(optarg) > 16) {
+ lprintf(LOG_ERR, "Username is too long (> 16 bytes)");
+ goto out_free;
+ }
+ username = strdup(optarg);
+ if (username == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ break;
+ case 'S':
+ if (sdrcache) {
+ free(sdrcache);
+ sdrcache = NULL;
+ }
+ sdrcache = strdup(optarg);
+ if (sdrcache == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ break;
+ case 'D':
+ /* check for subsequent instance of -D */
+ if (devfile) {
+ /* free memory for previous string */
+ free(devfile);
+ }
+ devfile = strdup(optarg);
+ if (devfile == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ break;
+#ifdef ENABLE_ALL_OPTIONS
+ case 'o':
+ if (oemtype) {
+ free(oemtype);
+ oemtype = NULL;
+ }
+ oemtype = strdup(optarg);
+ if (oemtype == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ if (strncmp(oemtype, "list", 4) == 0 ||
+ strncmp(oemtype, "help", 4) == 0) {
+ ipmi_oem_print();
+ rc = 0;
+ goto out_free;
+ }
+ break;
+ case 'g':
+ /* backwards compatible oem hack */
+ if (oemtype) {
+ free(oemtype);
+ oemtype = NULL;
+ }
+ oemtype = strdup("intelwv2");
+ break;
+ case 's':
+ /* backwards compatible oem hack */
+ if (oemtype) {
+ free(oemtype);
+ oemtype = NULL;
+ }
+ oemtype = strdup("supermicro");
+ break;
+ case 'P':
+ if (password) {
+ free(password);
+ password = NULL;
+ }
+ password = strdup(optarg);
+ if (password == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+
+ /* Prevent password snooping with ps */
+ i = strlen(optarg);
+ memset(optarg, 'X', i);
+ break;
+ case 'E':
+ if ((tmp_env = getenv("IPMITOOL_PASSWORD"))) {
+ if (password) {
+ free(password);
+ password = NULL;
+ }
+ password = strdup(tmp_env);
+ if (password == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ }
+ else if ((tmp_env = getenv("IPMI_PASSWORD"))) {
+ if (password) {
+ free(password);
+ password = NULL;
+ }
+ password = strdup(tmp_env);
+ if (password == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ }
+ else {
+ lprintf(LOG_WARN, "Unable to read password from environment");
+ }
+ break;
+ case 'L':
+ i = strlen(optarg);
+ if ((i > 0) && (optarg[i-1] == '+')) {
+ lookupbit = 0;
+ optarg[i-1] = 0;
+ }
+ privlvl = str2val(optarg, ipmi_privlvl_vals);
+ if (privlvl == 0xFF) {
+ lprintf(LOG_WARN, "Invalid privilege level %s", optarg);
+ }
+ break;
+ case 'A':
+ authtype = str2val(optarg, ipmi_authtype_session_vals);
+ break;
+ case 't':
+ if (str2uchar(optarg, &target_addr) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-t'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'b':
+ if (str2uchar(optarg, &target_channel) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-b'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'T':
+ if (str2uchar(optarg, &transit_addr) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-T'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'B':
+ if (str2uchar(optarg, &transit_channel) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-B'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'l':
+ if (str2uchar(optarg, &target_lun) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-l'.");
+ rc = 1;
+ goto out_free;
+ }
+ break;
+ case 'm':
+ if (str2uchar(optarg, &arg_addr) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-m'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'e':
+ sol_escape_char = optarg[0];
+ break;
+ case 'O':
+ if (seloem) {
+ free(seloem);
+ seloem = NULL;
+ }
+ seloem = strdup(optarg);
+ if (seloem == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ break;
+ case 'z':
+ if (str2ushort(optarg, &my_long_packet_size) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-z'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ /* Retry and Timeout */
+ case 'R':
+ if (str2int(optarg, &retry) != 0 || retry < 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-R'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+ case 'N':
+ if (str2uint(optarg, &timeout) != 0) {
+ lprintf(LOG_ERR, "Invalid parameter given or out of range for '-N'.");
+ rc = -1;
+ goto out_free;
+ }
+ break;
+#endif
+ default:
+ ipmi_option_usage(progname, cmdlist, intflist);
+ goto out_free;
+ }
+ }
+
+ /* check for command before doing anything */
+ if (argc-optind > 0 &&
+ strncmp(argv[optind], "help", 4) == 0) {
+ ipmi_cmd_print(cmdlist);
+ rc = 0;
+ goto out_free;
+ }
+
+ /*
+ * If the user has specified a hostname (-H option)
+ * then this is a remote access session.
+ *
+ * If no password was specified by any other method
+ * and the authtype was not explicitly set to NONE
+ * then prompt the user.
+ */
+ if (hostname != NULL && password == NULL &&
+ (authtype != IPMI_SESSION_AUTHTYPE_NONE || authtype < 0)) {
+#ifdef HAVE_GETPASSPHRASE
+ tmp_pass = getpassphrase("Password: ");
+#else
+ tmp_pass = getpass("Password: ");
+#endif
+ if (tmp_pass != NULL) {
+ password = strdup(tmp_pass);
+ tmp_pass = NULL;
+ if (password == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ }
+ }
+
+ /* if no interface was specified but a
+ * hostname was then use LAN by default
+ * otherwise the default is hardcoded
+ * to use the first entry in the list
+ */
+ if (intfname == NULL && hostname != NULL) {
+ intfname = strdup("lan");
+ if (intfname == NULL) {
+ lprintf(LOG_ERR, "%s: malloc failure", progname);
+ goto out_free;
+ }
+ }
+
+ if (password != NULL && intfname != NULL) {
+ if (strcmp(intfname, "lan") == 0 && strlen(password) > 16) {
+ lprintf(LOG_ERR, "%s: password is longer than 16 bytes.", intfname);
+ rc = -1;
+ goto out_free;
+ } else if (strcmp(intfname, "lanplus") == 0 && strlen(password) > 20) {
+ lprintf(LOG_ERR, "%s: password is longer than 20 bytes.", intfname);
+ rc = -1;
+ goto out_free;
+ }
+ } /* if (password != NULL && intfname != NULL) */
+
+ /* load interface */
+ ipmi_main_intf = ipmi_intf_load(intfname);
+ if (ipmi_main_intf == NULL) {
+ lprintf(LOG_ERR, "Error loading interface %s", intfname);
+ goto out_free;
+ }
+
+ /* setup log */
+ log_init(progname, 0, verbose);
+
+ /* run OEM setup if found */
+ if (oemtype != NULL &&
+ ipmi_oem_setup(ipmi_main_intf, oemtype) < 0) {
+ lprintf(LOG_ERR, "OEM setup for \"%s\" failed", oemtype);
+ goto out_free;
+ }
+
+ /* set session variables */
+ if (hostname != NULL)
+ ipmi_intf_session_set_hostname(ipmi_main_intf, hostname);
+ if (username != NULL)
+ ipmi_intf_session_set_username(ipmi_main_intf, username);
+ if (password != NULL)
+ ipmi_intf_session_set_password(ipmi_main_intf, password);
+ if (kgkey != NULL)
+ ipmi_intf_session_set_kgkey(ipmi_main_intf, kgkey);
+ if (port > 0)
+ ipmi_intf_session_set_port(ipmi_main_intf, port);
+ if (authtype >= 0)
+ ipmi_intf_session_set_authtype(ipmi_main_intf, (uint8_t)authtype);
+ if (privlvl > 0)
+ ipmi_intf_session_set_privlvl(ipmi_main_intf, (uint8_t)privlvl);
+ else
+ ipmi_intf_session_set_privlvl(ipmi_main_intf,
+ IPMI_SESSION_PRIV_ADMIN); /* default */
+ /* Adding retry and timeout for interface that support it */
+ if (retry > 0)
+ ipmi_intf_session_set_retry(ipmi_main_intf, retry);
+ if (timeout > 0)
+ ipmi_intf_session_set_timeout(ipmi_main_intf, timeout);
+
+ ipmi_intf_session_set_lookupbit(ipmi_main_intf, lookupbit);
+ ipmi_intf_session_set_sol_escape_char(ipmi_main_intf, sol_escape_char);
+ ipmi_intf_session_set_cipher_suite_id(ipmi_main_intf, cipher_suite_id);
+
+ ipmi_main_intf->devnum = devnum;
+
+ /* setup device file if given */
+ ipmi_main_intf->devfile = devfile;
+
+ /* Open the interface with the specified or default IPMB address */
+ ipmi_main_intf->my_addr = arg_addr ? arg_addr : IPMI_BMC_SLAVE_ADDR;
+ if (ipmi_main_intf->open != NULL) {
+ if (ipmi_main_intf->open(ipmi_main_intf) < 0) {
+ goto out_free;
+ }
+ }
+ /*
+ * Attempt picmg discovery of the actual interface address unless
+ * the users specified an address.
+ * Address specification always overrides discovery
+ */
+ if (picmg_discover(ipmi_main_intf) && !arg_addr) {
+ lprintf(LOG_DEBUG, "Running PICMG Get Address Info");
+ addr = ipmi_picmg_ipmb_address(ipmi_main_intf);
+ lprintf(LOG_INFO, "Discovered IPMB-0 address 0x%x", addr);
+ }
+
+ /*
+ * If we discovered the ipmb address and it is not the same as what we
+ * used for open, Set the discovered IPMB address as my address if the
+ * interface supports it.
+ */
+ if (addr != 0 && addr != ipmi_main_intf->my_addr &&
+ ipmi_main_intf->set_my_addr) {
+ /*
+ * Only set the interface address on interfaces which support
+ * it
+ */
+ (void) ipmi_main_intf->set_my_addr(ipmi_main_intf, addr);
+ }
+
+ /* If bridging addresses are specified, handle them */
+ if (target_addr > 0) {
+ ipmi_main_intf->target_addr = target_addr;
+ ipmi_main_intf->target_lun = target_lun ;
+ ipmi_main_intf->target_channel = target_channel ;
+ }
+ if (transit_addr > 0) {
+ /* sanity check, transit makes no sense without a target */
+ if ((transit_addr != 0 || transit_channel != 0) &&
+ ipmi_main_intf->target_addr == 0) {
+ lprintf(LOG_ERR,
+ "Transit address/channel %#x/%#x ignored. "
+ "Target address must be specified!",
+ transit_addr, transit_channel);
+ goto out_free;
+ }
+
+ ipmi_main_intf->transit_addr = transit_addr;
+ ipmi_main_intf->transit_channel = transit_channel;
+ }
+ if (ipmi_main_intf->target_addr > 0) {
+ /* must be admin level to do this over lan */
+ ipmi_intf_session_set_privlvl(ipmi_main_intf, IPMI_SESSION_PRIV_ADMIN);
+ /* Get the ipmb address of the targeted entity */
+ ipmi_main_intf->target_ipmb_addr =
+ ipmi_picmg_ipmb_address(ipmi_main_intf);
+ lprintf(LOG_DEBUG, "Specified addressing Target %#x:%#x Transit %#x:%#x",
+ ipmi_main_intf->target_addr,
+ ipmi_main_intf->target_channel,
+ ipmi_main_intf->transit_addr,
+ ipmi_main_intf->transit_channel);
+ if (ipmi_main_intf->target_ipmb_addr) {
+ lprintf(LOG_INFO, "Discovered Target IPMB-0 address %#x",
+ ipmi_main_intf->target_ipmb_addr);
+ }
+ }
+
+ lprintf(LOG_DEBUG, "Interface address: my_addr %#x "
+ "transit %#x:%#x target %#x:%#x "
+ "ipmb_target %#x\n",
+ ipmi_main_intf->my_addr,
+ ipmi_main_intf->transit_addr,
+ ipmi_main_intf->transit_channel,
+ ipmi_main_intf->target_addr,
+ ipmi_main_intf->target_channel,
+ ipmi_main_intf->target_ipmb_addr);
+
+ /* parse local SDR cache if given */
+ if (sdrcache != NULL) {
+ ipmi_sdr_list_cache_fromfile(ipmi_main_intf, sdrcache);
+ }
+ /* Parse SEL OEM file if given */
+ if (seloem != NULL) {
+ ipmi_sel_oem_init(seloem);
+ }
+
+ /* Enable Big Buffer when requested */
+ if ( my_long_packet_size != 0 ) {
+ /* Enable Big Buffer when requested */
+ if (!ipmi_oem_active(ipmi_main_intf, "kontron") ||
+ ipmi_kontronoem_set_large_buffer(ipmi_main_intf,
+ my_long_packet_size ) == 0) {
+ printf("Setting large buffer to %i\n", my_long_packet_size);
+ my_long_packet_set = 1;
+ ipmi_intf_set_max_request_data_size(ipmi_main_intf,
+ my_long_packet_size);
+ }
+ }
+
+ ipmi_main_intf->cmdlist = cmdlist;
+
+ /* now we finally run the command */
+ if (argc-optind > 0)
+ rc = ipmi_cmd_run(ipmi_main_intf, argv[optind], argc-optind-1,
+ &(argv[optind+1]));
+ else
+ rc = ipmi_cmd_run(ipmi_main_intf, NULL, 0, NULL);
+
+ if (my_long_packet_set == 1) {
+ if (ipmi_oem_active(ipmi_main_intf, "kontron")) {
+ /* Restore defaults */
+ ipmi_kontronoem_set_large_buffer( ipmi_main_intf, 0 );
+ }
+ }
+
+ /* clean repository caches */
+ ipmi_cleanup(ipmi_main_intf);
+
+ /* call interface close function if available */
+ if (ipmi_main_intf->opened > 0 && ipmi_main_intf->close != NULL)
+ ipmi_main_intf->close(ipmi_main_intf);
+
+ out_free:
+ log_halt();
+
+ if (intfname != NULL) {
+ free(intfname);
+ intfname = NULL;
+ }
+ if (hostname != NULL) {
+ free(hostname);
+ hostname = NULL;
+ }
+ if (username != NULL) {
+ free(username);
+ username = NULL;
+ }
+ if (password != NULL) {
+ free(password);
+ password = NULL;
+ }
+ if (oemtype != NULL) {
+ free(oemtype);
+ oemtype = NULL;
+ }
+ if (seloem != NULL) {
+ free(seloem);
+ seloem = NULL;
+ }
+ if (kgkey != NULL) {
+ free(kgkey);
+ kgkey = NULL;
+ }
+ if (sdrcache != NULL) {
+ free(sdrcache);
+ sdrcache = NULL;
+ }
+ if (devfile) {
+ free(devfile);
+ devfile = NULL;
+ }
+
+ return rc;
+}
+
+
diff --git a/lib/ipmi_mc.c b/lib/ipmi_mc.c
new file mode 100644
index 0000000..2890c90
--- /dev/null
+++ b/lib/ipmi_mc.c
@@ -0,0 +1,1112 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/bswap.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_strings.h>
+
+extern int verbose;
+
+static int ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv,
+ int is_set);
+static void printf_sysinfo_usage(int full_help);
+
+/* ipmi_mc_reset - attempt to reset an MC
+ *
+ * @intf: ipmi interface
+ * @cmd: reset command to send
+ * BMC_WARM_RESET or
+ * BMC_COLD_RESET
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_mc_reset(struct ipmi_intf * intf, int cmd)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ if( !intf->opened )
+ intf->open(intf);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = cmd;
+ req.msg.data_len = 0;
+
+ if (cmd == BMC_COLD_RESET)
+ intf->noanswer = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (cmd == BMC_COLD_RESET)
+ intf->abort = 1;
+
+ if (cmd == BMC_COLD_RESET && rsp == NULL) {
+ /* This is expected. See 20.2 Cold Reset Command, p.243, IPMIv2.0 rev1.0 */
+ } else if (rsp == NULL) {
+ lprintf(LOG_ERR, "MC reset command failed.");
+ return (-1);
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "MC reset command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ printf("Sent %s reset command to MC\n",
+ (cmd == BMC_WARM_RESET) ? "warm" : "cold");
+
+ return 0;
+}
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+struct bmc_enables_data {
+#if WORDS_BIGENDIAN
+ uint8_t oem2 : 1;
+ uint8_t oem1 : 1;
+ uint8_t oem0 : 1;
+ uint8_t __reserved : 1;
+ uint8_t system_event_log : 1;
+ uint8_t event_msgbuf : 1;
+ uint8_t event_msgbuf_intr : 1;
+ uint8_t receive_msg_intr : 1;
+#else
+ uint8_t receive_msg_intr : 1;
+ uint8_t event_msgbuf_intr : 1;
+ uint8_t event_msgbuf : 1;
+ uint8_t system_event_log : 1;
+ uint8_t __reserved : 1;
+ uint8_t oem0 : 1;
+ uint8_t oem1 : 1;
+ uint8_t oem2 : 1;
+#endif
+} ATTRIBUTE_PACKING;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(0)
+#endif
+
+struct bitfield_data {
+ const char * name;
+ const char * desc;
+ uint32_t mask;
+};
+
+struct bitfield_data mc_enables_bf[] = {
+ {
+ name: "recv_msg_intr",
+ desc: "Receive Message Queue Interrupt",
+ mask: 1<<0,
+ },
+ {
+ name: "event_msg_intr",
+ desc: "Event Message Buffer Full Interrupt",
+ mask: 1<<1,
+ },
+ {
+ name: "event_msg",
+ desc: "Event Message Buffer",
+ mask: 1<<2,
+ },
+ {
+ name: "system_event_log",
+ desc: "System Event Logging",
+ mask: 1<<3,
+ },
+ {
+ name: "oem0",
+ desc: "OEM 0",
+ mask: 1<<5,
+ },
+ {
+ name: "oem1",
+ desc: "OEM 1",
+ mask: 1<<6,
+ },
+ {
+ name: "oem2",
+ desc: "OEM 2",
+ mask: 1<<7,
+ },
+ { NULL },
+};
+
+static void
+printf_mc_reset_usage(void)
+{
+ lprintf(LOG_NOTICE, "usage: mc reset <warm|cold>");
+} /* printf_mc_reset_usage(void) */
+
+static void
+printf_mc_usage(void)
+{
+ struct bitfield_data * bf;
+ lprintf(LOG_NOTICE, "MC Commands:");
+ lprintf(LOG_NOTICE, " reset <warm|cold>");
+ lprintf(LOG_NOTICE, " guid");
+ lprintf(LOG_NOTICE, " info");
+ lprintf(LOG_NOTICE, " watchdog <get|reset|off>");
+ lprintf(LOG_NOTICE, " selftest");
+ lprintf(LOG_NOTICE, " getenables");
+ lprintf(LOG_NOTICE, " setenables <option=on|off> ...");
+ for (bf = mc_enables_bf; bf->name != NULL; bf++) {
+ lprintf(LOG_NOTICE, " %-20s %s", bf->name, bf->desc);
+ }
+ printf_sysinfo_usage(0);
+}
+
+static void
+printf_sysinfo_usage(int full_help)
+{
+ if (full_help != 0)
+ lprintf(LOG_NOTICE, "usage:");
+
+ lprintf(LOG_NOTICE, " getsysinfo <argument>");
+
+ if (full_help != 0) {
+ lprintf(LOG_NOTICE,
+ " Retrieves system info from BMC for given argument");
+ }
+
+ lprintf(LOG_NOTICE, " setsysinfo <argument> <string>");
+
+ if (full_help != 0) {
+ lprintf(LOG_NOTICE,
+ " Stores system info string for given argument to BMC");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " Valid arguments are:");
+ }
+ lprintf(LOG_NOTICE,
+ " primary_os_name Primary operating system name");
+ lprintf(LOG_NOTICE, " os_name Operating system name");
+ lprintf(LOG_NOTICE,
+ " system_name System Name of server(vendor dependent)");
+ lprintf(LOG_NOTICE,
+ " delloem_os_version Running version of operating system");
+ lprintf(LOG_NOTICE, " delloem_url URL of BMC webserver");
+ lprintf(LOG_NOTICE, "");
+}
+
+static void
+print_watchdog_usage(void)
+{
+ lprintf(LOG_NOTICE, "usage: watchdog <command>:");
+ lprintf(LOG_NOTICE, " get : Get Current Watchdog settings");
+ lprintf(LOG_NOTICE, " reset : Restart Watchdog timer based on most recent settings");
+ lprintf(LOG_NOTICE, " off : Shut off a running Watchdog timer");
+}
+
+/* ipmi_mc_get_enables - print out MC enables
+ *
+ * @intf: ipmi inteface
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_mc_get_enables(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct bitfield_data * bf;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_GLOBAL_ENABLES;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Global Enables command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Global Enables command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ for (bf = mc_enables_bf; bf->name != NULL; bf++) {
+ printf("%-40s : %sabled\n", bf->desc,
+ rsp->data[0] & bf->mask ? "en" : "dis");
+ }
+
+ return 0;
+}
+
+/* ipmi_mc_set_enables - set MC enable flags
+ *
+ * @intf: ipmi inteface
+ * @argc: argument count
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_mc_set_enables(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct bitfield_data * bf;
+ uint8_t en;
+ int i;
+
+ if (argc < 1) {
+ printf_mc_usage();
+ return (-1);
+ }
+ else if (strncmp(argv[0], "help", 4) == 0) {
+ printf_mc_usage();
+ return 0;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_GLOBAL_ENABLES;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Global Enables command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Global Enables command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ en = rsp->data[0];
+
+ for (i = 0; i < argc; i++) {
+ for (bf = mc_enables_bf; bf->name != NULL; bf++) {
+ int nl = strlen(bf->name);
+ if (strncmp(argv[i], bf->name, nl) != 0)
+ continue;
+ if (strncmp(argv[i]+nl+1, "off", 3) == 0) {
+ printf("Disabling %s\n", bf->desc);
+ en &= ~bf->mask;
+ }
+ else if (strncmp(argv[i]+nl+1, "on", 2) == 0) {
+ printf("Enabling %s\n", bf->desc);
+ en |= bf->mask;
+ }
+ else {
+ lprintf(LOG_ERR, "Unrecognized option: %s", argv[i]);
+ }
+ }
+ }
+
+ if (en == rsp->data[0]) {
+ printf("\nNothing to change...\n");
+ ipmi_mc_get_enables(intf);
+ return 0;
+ }
+
+ req.msg.cmd = BMC_SET_GLOBAL_ENABLES;
+ req.msg.data = &en;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set Global Enables command failed");
+ return -1;
+ }
+ else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set Global Enables command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("\nVerifying...\n");
+ ipmi_mc_get_enables(intf);
+
+ return 0;
+}
+
+/* IPM Device, Get Device ID Command - Additional Device Support */
+const char *ipm_dev_adtl_dev_support[8] = {
+ "Sensor Device", /* bit 0 */
+ "SDR Repository Device", /* bit 1 */
+ "SEL Device", /* bit 2 */
+ "FRU Inventory Device", /* ... */
+ "IPMB Event Receiver",
+ "IPMB Event Generator",
+ "Bridge",
+ "Chassis Device" /* bit 7 */
+};
+
+/* ipmi_mc_get_deviceid - print information about this MC
+ *
+ * @intf: ipmi interface
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_mc_get_deviceid(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct ipm_devid_rsp *devid;
+ int i;
+ const char *product=NULL;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Device ID command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Device ID command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ devid = (struct ipm_devid_rsp *) rsp->data;
+ printf("Device ID : %i\n",
+ devid->device_id);
+ printf("Device Revision : %i\n",
+ devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK);
+ printf("Firmware Revision : %u.%02x\n",
+ devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK,
+ devid->fw_rev2);
+ printf("IPMI Version : %x.%x\n",
+ IPM_DEV_IPMI_VERSION_MAJOR(devid->ipmi_version),
+ IPM_DEV_IPMI_VERSION_MINOR(devid->ipmi_version));
+ printf("Manufacturer ID : %lu\n",
+ (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id));
+ printf("Manufacturer Name : %s\n",
+ val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
+ ipmi_oem_info) );
+
+ printf("Product ID : %u (0x%02x%02x)\n",
+ buf2short((uint8_t *)(devid->product_id)),
+ devid->product_id[1], devid->product_id[0]);
+
+ product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
+ (devid->product_id[1]<<8)+devid->product_id[0],
+ ipmi_oem_product_info);
+
+ if (product!=NULL) {
+ printf("Product Name : %s\n", product);
+ }
+
+ printf("Device Available : %s\n",
+ (devid->fw_rev1 & IPM_DEV_FWREV1_AVAIL_MASK) ?
+ "no" : "yes");
+ printf("Provides Device SDRs : %s\n",
+ (devid->device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) ?
+ "yes" : "no");
+ printf("Additional Device Support :\n");
+ for (i = 0; i < IPM_DEV_ADTL_SUPPORT_BITS; i++) {
+ if (devid->adtl_device_support & (1 << i)) {
+ printf(" %s\n", ipm_dev_adtl_dev_support[i]);
+ }
+ }
+ if (rsp->data_len == sizeof(*devid)) {
+ printf("Aux Firmware Rev Info : \n");
+ /* These values could be looked-up by vendor if documented,
+ * so we put them on individual lines for better treatment later
+ */
+ printf(" 0x%02x\n 0x%02x\n 0x%02x\n 0x%02x\n",
+ devid->aux_fw_rev[0],
+ devid->aux_fw_rev[1],
+ devid->aux_fw_rev[2],
+ devid->aux_fw_rev[3]);
+ }
+ return 0;
+}
+
+/* Structure follow the IPMI V.2 Rev 1.0
+ * See Table 20-10 */
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+struct ipmi_guid {
+ uint32_t time_low; /* timestamp low field */
+ uint16_t time_mid; /* timestamp middle field */
+ uint16_t time_hi_and_version; /* timestamp high field and version number */
+ uint8_t clock_seq_hi_variant;/* clock sequence high field and variant */
+ uint8_t clock_seq_low; /* clock sequence low field */
+ uint8_t node[6]; /* node */
+} ATTRIBUTE_PACKING;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(0)
+#endif
+
+/* ipmi_mc_get_guid - print this MC GUID
+ *
+ * @intf: ipmi interface
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_mc_get_guid(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct ipmi_guid guid;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_GUID;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get GUID command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get GUID command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ if (rsp->data_len == sizeof(struct ipmi_guid)) {
+ char tbuf[40];
+ time_t s;
+ memset(tbuf, 0, 40);
+ memset(&guid, 0, sizeof(struct ipmi_guid));
+ memcpy(&guid, rsp->data, rsp->data_len);
+
+ /* Kipp - changed order of last field (node) to follow specification */
+ printf("System GUID : %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
+ guid.time_low, guid.time_mid, guid.time_hi_and_version,
+ guid.clock_seq_hi_variant << 8 | guid.clock_seq_low,
+ guid.node[0], guid.node[1], guid.node[2],
+ guid.node[3], guid.node[4], guid.node[5]);
+
+ s = (time_t)guid.time_low; /* Kipp - removed the BSWAP_32, it was not needed here */
+ strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", localtime(&s));
+ printf("Timestamp : %s\n", tbuf);
+ }
+ else {
+ lprintf(LOG_ERR, "Invalid GUID length %d", rsp->data_len);
+ }
+
+ return 0;
+}
+
+/* ipmi_mc_get_selftest - returns and print selftest results
+ *
+ * @intf: ipmi interface
+ */
+static int ipmi_mc_get_selftest(struct ipmi_intf * intf)
+{
+ int rv = 0;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct ipm_selftest_rsp *sft_res;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_SELF_TEST;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp) {
+ lprintf(LOG_ERR, "No response from devices\n");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Bad response: (%s)",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ sft_res = (struct ipm_selftest_rsp *) rsp->data;
+
+ if (sft_res->code == IPM_SFT_CODE_OK) {
+ printf("Selftest: passed\n");
+ rv = 0;
+ }
+
+ else if (sft_res->code == IPM_SFT_CODE_NOT_IMPLEMENTED) {
+ printf("Selftest: not implemented\n");
+ rv = -1;
+ }
+
+ else if (sft_res->code == IPM_SFT_CODE_DEV_CORRUPTED) {
+ printf("Selftest: device corrupted\n");
+ rv = -1;
+
+ if (sft_res->test & IPM_SELFTEST_SEL_ERROR) {
+ printf(" -> SEL device not accessible\n");
+ }
+ if (sft_res->test & IPM_SELFTEST_SDR_ERROR) {
+ printf(" -> SDR repository not accesible\n");
+ }
+ if (sft_res->test & IPM_SELFTEST_FRU_ERROR) {
+ printf("FRU device not accessible\n");
+ }
+ if (sft_res->test & IPM_SELFTEST_IPMB_ERROR) {
+ printf("IPMB signal lines do not respond\n");
+ }
+ if (sft_res->test & IPM_SELFTEST_SDRR_EMPTY) {
+ printf("SDR repository empty\n");
+ }
+ if (sft_res->test & IPM_SELFTEST_INTERNAL_USE) {
+ printf("Internal Use Area corrupted\n");
+ }
+ if (sft_res->test & IPM_SELFTEST_FW_BOOTBLOCK) {
+ printf("Controller update boot block corrupted\n");
+ }
+ if (sft_res->test & IPM_SELFTEST_FW_CORRUPTED) {
+ printf("controller operational firmware corrupted\n");
+ }
+ }
+
+ else if (sft_res->code == IPM_SFT_CODE_FATAL_ERROR) {
+ printf("Selftest : fatal error\n");
+ printf("Failure code : %02x\n", sft_res->test);
+ rv = -1;
+ }
+
+ else if (sft_res->code == IPM_SFT_CODE_RESERVED) {
+ printf("Selftest: N/A");
+ rv = -1;
+ }
+
+ else {
+ printf("Selftest : device specific (%02Xh)\n", sft_res->code);
+ printf("Failure code : %02Xh\n", sft_res->test);
+ rv = 0;
+ }
+
+ return rv;
+}
+
+/* ipmi_mc_get_watchdog
+ *
+ * @intf: ipmi interface
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+
+const char *wdt_use_string[8] = {
+ "Reserved",
+ "BIOS FRB2",
+ "BIOS/POST",
+ "OS Load",
+ "SMS/OS",
+ "OEM",
+ "Reserved",
+ "Reserved"
+};
+
+const char *wdt_action_string[8] = {
+ "No action",
+ "Hard Reset",
+ "Power Down",
+ "Power Cycle",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved"
+};
+
+static int
+ipmi_mc_get_watchdog(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct ipm_get_watchdog_rsp * wdt_res;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_WATCHDOG_TIMER;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Watchdog Timer command failed");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Get Watchdog Timer command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ wdt_res = (struct ipm_get_watchdog_rsp *) rsp->data;
+
+ printf("Watchdog Timer Use: %s (0x%02x)\n",
+ wdt_use_string[(wdt_res->timer_use & 0x07 )], wdt_res->timer_use);
+ printf("Watchdog Timer Is: %s\n",
+ wdt_res->timer_use & 0x40 ? "Started/Running" : "Stopped");
+ printf("Watchdog Timer Actions: %s (0x%02x)\n",
+ wdt_action_string[(wdt_res->timer_actions&0x07)], wdt_res->timer_actions);
+ printf("Pre-timeout interval: %d seconds\n", wdt_res->pre_timeout);
+ printf("Timer Expiration Flags: 0x%02x\n", wdt_res->timer_use_exp);
+ printf("Initial Countdown: %i sec\n",
+ ((wdt_res->initial_countdown_msb << 8) | wdt_res->initial_countdown_lsb)/10);
+ printf("Present Countdown: %i sec\n",
+ (((wdt_res->present_countdown_msb << 8) | wdt_res->present_countdown_lsb)) / 10);
+
+ return 0;
+}
+
+/* ipmi_mc_shutoff_watchdog
+ *
+ * @intf: ipmi interface
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_mc_shutoff_watchdog(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_SET_WATCHDOG_TIMER;
+ req.msg.data = msg_data;
+ req.msg.data_len = 6;
+
+ /*
+ * The only set cmd we're allowing is to shut off the timer.
+ * Turning on the timer should be the job of the ipmi watchdog driver.
+ * See 'modinfo ipmi_watchdog' for more info. (NOTE: the reset
+ * command will restart the timer if it's already been initialized.)
+ *
+ * Out-of-band watchdog set commands can still be sent via the raw
+ * command interface but this is a very dangerous thing to do since
+ * a periodic "poke"/reset over a network is unreliable. This is
+ * not a recommended way to use the IPMI watchdog commands.
+ */
+
+ msg_data[0] = IPM_WATCHDOG_SMS_OS;
+ msg_data[1] = IPM_WATCHDOG_NO_ACTION;
+ msg_data[2] = 0x00; /* pretimeout interval */
+ msg_data[3] = IPM_WATCHDOG_CLEAR_SMS_OS;
+ msg_data[4] = 0xb8; /* countdown lsb (100 ms/count) */
+ msg_data[5] = 0x0b; /* countdown msb - 5 mins */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed!");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed! %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("Watchdog Timer Shutoff successful -- timer stopped\n");
+ return 0;
+}
+
+
+/* ipmi_mc_rst_watchdog
+ *
+ * @intf: ipmi interface
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_mc_rst_watchdog(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_RESET_WATCHDOG_TIMER;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Reset Watchdog Timer command failed!");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Reset Watchdog Timer command failed: %s",
+ (rsp->ccode == IPM_WATCHDOG_RESET_ERROR) ?
+ "Attempt to reset unitialized watchdog" :
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("IPMI Watchdog Timer Reset - countdown restarted!\n");
+ return 0;
+}
+
+/* ipmi_mc_main - top-level handler for MC functions
+ *
+ * @intf: ipmi interface
+ * @argc: number of arguments
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_mc_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if (argc < 1) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ printf_mc_usage();
+ rc = (-1);
+ }
+ else if (strncmp(argv[0], "help", 4) == 0) {
+ printf_mc_usage();
+ rc = 0;
+ }
+ else if (strncmp(argv[0], "reset", 5) == 0) {
+ if (argc < 2) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ printf_mc_reset_usage();
+ rc = (-1);
+ }
+ else if (strncmp(argv[1], "help", 4) == 0) {
+ printf_mc_reset_usage();
+ rc = 0;
+ }
+ else if (strncmp(argv[1], "cold", 4) == 0) {
+ rc = ipmi_mc_reset(intf, BMC_COLD_RESET);
+ }
+ else if (strncmp(argv[1], "warm", 4) == 0) {
+ rc = ipmi_mc_reset(intf, BMC_WARM_RESET);
+ }
+ else {
+ lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]);
+ printf_mc_reset_usage();
+ rc = (-1);
+ }
+ }
+ else if (strncmp(argv[0], "info", 4) == 0) {
+ rc = ipmi_mc_get_deviceid(intf);
+ }
+ else if (strncmp(argv[0], "guid", 4) == 0) {
+ rc = ipmi_mc_get_guid(intf);
+ }
+ else if (strncmp(argv[0], "getenables", 10) == 0) {
+ rc = ipmi_mc_get_enables(intf);
+ }
+ else if (strncmp(argv[0], "setenables", 10) == 0) {
+ rc = ipmi_mc_set_enables(intf, argc-1, &(argv[1]));
+ }
+ else if (!strncmp(argv[0], "selftest", 8)) {
+ rc = ipmi_mc_get_selftest(intf);
+ }
+ else if (!strncmp(argv[0], "watchdog", 8)) {
+ if (argc < 2) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ print_watchdog_usage();
+ rc = (-1);
+ }
+ else if (strncmp(argv[1], "help", 4) == 0) {
+ print_watchdog_usage();
+ rc = 0;
+ }
+ else if (strncmp(argv[1], "get", 3) == 0) {
+ rc = ipmi_mc_get_watchdog(intf);
+ }
+ else if(strncmp(argv[1], "off", 3) == 0) {
+ rc = ipmi_mc_shutoff_watchdog(intf);
+ }
+ else if(strncmp(argv[1], "reset", 5) == 0) {
+ rc = ipmi_mc_rst_watchdog(intf);
+ }
+ else {
+ lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]);
+ print_watchdog_usage();
+ rc = (-1);
+ }
+ }
+ else if (strncmp(argv[0], "getsysinfo", 10) == 0) {
+ rc = ipmi_sysinfo_main(intf, argc, argv, 0);
+ }
+ else if (strncmp(argv[0], "setsysinfo", 10) == 0) {
+ rc = ipmi_sysinfo_main(intf, argc, argv, 1);
+ }
+ else {
+ lprintf(LOG_ERR, "Invalid mc/bmc command: %s", argv[0]);
+ printf_mc_usage();
+ rc = (-1);
+ }
+ return rc;
+}
+
+/*
+ * sysinfo_param() - function converts sysinfo param to int
+ *
+ * @str - user input string
+ * @maxset - ?
+ *
+ * returns (-1) on error
+ * returns > 0 on success
+ */
+static int
+sysinfo_param(const char *str, int *maxset)
+{
+ if (!str || !maxset)
+ return (-1);
+
+ *maxset = 4;
+ if (!strcmp(str, "system_name"))
+ return IPMI_SYSINFO_HOSTNAME;
+ else if (!strcmp(str, "primary_os_name"))
+ return IPMI_SYSINFO_PRIMARY_OS_NAME;
+ else if (!strcmp(str, "os_name"))
+ return IPMI_SYSINFO_OS_NAME;
+ else if (!strcmp(str, "delloem_os_version"))
+ return IPMI_SYSINFO_DELL_OS_VERSION;
+ else if (!strcmp(str, "delloem_url")) {
+ *maxset = 2;
+ return IPMI_SYSINFO_DELL_URL;
+ }
+
+ return (-1);
+}
+
+/*
+ * ipmi_mc_getsysinfo() - function processes the IPMI Get System Info command
+ *
+ * @intf - ipmi interface
+ * @param - parameter eg. 0xC0..0xFF = OEM
+ * @block - number of block parameters
+ * @set - number of set parameters
+ * @len - length of buffer
+ * @buffer - pointer to buffer
+ *
+ * returns (-1) on failure
+ * returns 0 on success
+ * returns > 0 IPMI code
+ */
+int
+ipmi_mc_getsysinfo(struct ipmi_intf * intf, int param, int block, int set,
+ int len, void *buffer)
+{
+ uint8_t data[4];
+ struct ipmi_rs *rsp = NULL;
+ struct ipmi_rq req = {0};
+
+ memset(buffer, 0, len);
+ memset(data, 0, 4);
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_GET_SYS_INFO;
+ req.msg.data_len = 4;
+ req.msg.data = data;
+
+ if (verbose > 1)
+ printf("getsysinfo: %.2x/%.2x/%.2x\n", param, block, set);
+
+ data[0] = 0; /* get/set */
+ data[1] = param;
+ data[2] = block;
+ data[3] = set;
+
+ /*
+ * Format of get output is:
+ * u8 param_rev
+ * u8 selector
+ * u8 encoding bit[0-3];
+ * u8 length
+ * u8 data0[14]
+ */
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ return (-1);
+
+ if (rsp->ccode == 0) {
+ if (len > rsp->data_len)
+ len = rsp->data_len;
+ if (len && buffer)
+ memcpy(buffer, rsp->data, len);
+ }
+ return rsp->ccode;
+}
+
+/*
+ * ipmi_mc_setsysinfo() - function processes the IPMI Set System Info command
+ *
+ * @intf - ipmi interface
+ * @len - length of buffer
+ * @buffer - pointer to buffer
+ *
+ * returns (-1) on failure
+ * returns 0 on success
+ * returns > 0 IPMI code
+ */
+int
+ipmi_mc_setsysinfo(struct ipmi_intf * intf, int len, void *buffer)
+{
+ struct ipmi_rs *rsp = NULL;
+ struct ipmi_rq req = {0};
+
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = IPMI_SET_SYS_INFO;
+ req.msg.data_len = len;
+ req.msg.data = buffer;
+
+ /*
+ * Format of set input:
+ * u8 param rev
+ * u8 selector
+ * u8 data1[16]
+ */
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp != NULL) {
+ return rsp->ccode;
+ }
+ return -1;
+}
+
+static int
+ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv, int is_set)
+{
+ char *str;
+ unsigned char infostr[256];
+ unsigned char paramdata[18];
+ int len, maxset, param, pos, rc, set;
+
+ if (argc == 2 && strcmp(argv[1], "help") == 0) {
+ printf_sysinfo_usage(1);
+ return 0;
+ }
+ else if (argc < 2 || (is_set == 1 && argc < 3)) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ printf_sysinfo_usage(1);
+ return (-1);
+ }
+
+ /* Get Parameters */
+ if ((param = sysinfo_param(argv[1], &maxset)) < 0) {
+ lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]);
+ printf_sysinfo_usage(1);
+ return (-1);
+ }
+
+ rc = 0;
+ if (is_set != 0) {
+ str = argv[2];
+ set = pos = 0;
+ len = strlen(str);
+
+ /* first block holds 14 bytes, all others hold 16 */
+ if ((len + 2 + 15) / 16 >= maxset)
+ len = (maxset * 16) - 2;
+
+ do {
+ memset(paramdata, 0, sizeof(paramdata));
+ paramdata[0] = param;
+ paramdata[1] = set;
+ if (set == 0) {
+ /* First block is special case */
+ paramdata[2] = 0; /* ascii encoding */
+ paramdata[3] = len; /* length */
+ strncpy(paramdata + 4, str + pos, IPMI_SYSINFO_SET0_SIZE);
+ pos += IPMI_SYSINFO_SET0_SIZE;
+ }
+ else {
+ strncpy(paramdata + 2, str + pos, IPMI_SYSINFO_SETN_SIZE);
+ pos += IPMI_SYSINFO_SETN_SIZE;
+ }
+ rc = ipmi_mc_setsysinfo(intf, 18, paramdata);
+
+ if (rc)
+ break;
+
+ set++;
+ } while (pos < len);
+ }
+ else {
+ memset(infostr, 0, sizeof(infostr));
+ /* Read blocks of data */
+ pos = 0;
+ for (set = 0; set < maxset; set++) {
+ rc = ipmi_mc_getsysinfo(intf, param, set, 0, 18, paramdata);
+
+ if (rc)
+ break;
+
+ if (set == 0) {
+ /* First block is special case */
+ if ((paramdata[2] & 0xF) == 0) {
+ /* Determine max number of blocks to read */
+ maxset = ((paramdata[3] + 2) + 15) / 16;
+ }
+ memcpy(infostr + pos, paramdata + 4, IPMI_SYSINFO_SET0_SIZE);
+ pos += IPMI_SYSINFO_SET0_SIZE;
+ }
+ else {
+ memcpy(infostr + pos, paramdata + 2, IPMI_SYSINFO_SETN_SIZE);
+ pos += IPMI_SYSINFO_SETN_SIZE;
+ }
+ }
+ printf("%s\n", infostr);
+ }
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s %s set %d command failed", argv[0], argv[1], set);
+ }
+ else if (rc == 0x80) {
+ lprintf(LOG_ERR, "%s %s parameter not supported", argv[0], argv[1]);
+ }
+ else if (rc > 0) {
+ lprintf(LOG_ERR, "%s command failed: %s", argv[0],
+ val2str(rc, completion_code_vals));
+ }
+ return rc;
+}
diff --git a/lib/ipmi_oem.c b/lib/ipmi_oem.c
new file mode 100644
index 0000000..89495c0
--- /dev/null
+++ b/lib/ipmi_oem.c
@@ -0,0 +1,168 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/log.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_sel.h>
+
+static int ipmi_oem_supermicro(struct ipmi_intf * intf);
+static int ipmi_oem_ibm(struct ipmi_intf * intf);
+
+static struct ipmi_oem_handle ipmi_oem_list[] = {
+ {
+ name: "supermicro",
+ desc: "Supermicro IPMIv1.5 BMC with OEM LAN authentication support",
+ setup: ipmi_oem_supermicro,
+ },
+ {
+ name: "intelwv2",
+ desc: "Intel SE7501WV2 IPMIv1.5 BMC with extra LAN communication support",
+ },
+ {
+ name: "intelplus",
+ desc: "Intel IPMI 2.0 BMC with RMCP+ communication support",
+ },
+ {
+ name: "icts",
+ desc: "IPMI 2.0 ICTS compliance support",
+ },
+ {
+ name: "ibm",
+ desc: "IBM OEM support",
+ setup: ipmi_oem_ibm,
+ },
+ {
+ name: "i82571spt",
+ desc: "Intel 82571 MAC with integrated RMCP+ support in super pass-through mode",
+ },
+ {
+ name: "kontron",
+ desc: "Kontron OEM big buffer support"
+ },
+ { 0 }
+};
+
+/* Supermicro IPMIv2 BMCs use OEM authtype */
+static int
+ipmi_oem_supermicro(struct ipmi_intf * intf)
+{
+ ipmi_intf_session_set_authtype(intf, IPMI_SESSION_AUTHTYPE_OEM);
+ return 0;
+}
+
+static int
+ipmi_oem_ibm(struct ipmi_intf * intf)
+{
+ char * filename;
+ if ((filename = getenv("IPMI_OEM_IBM_DATAFILE")) == NULL) {
+ lprintf(LOG_ERR, "Unable to read IPMI_OEM_IBM_DATAFILE from environment");
+ return -1;
+ }
+ return ipmi_sel_oem_init((const char *)filename);
+}
+
+/* ipmi_oem_print - print list of OEM handles
+ */
+void
+ipmi_oem_print(void)
+{
+ struct ipmi_oem_handle * oem;
+ lprintf(LOG_NOTICE, "\nOEM Support:");
+ for (oem=ipmi_oem_list; oem->name != NULL && oem->desc != NULL; oem++) {
+ lprintf(LOG_NOTICE, "\t%-12s %s", oem->name, oem->desc);
+ }
+ lprintf(LOG_NOTICE, "");
+}
+
+/* ipmi_oem_setup - do initial setup of OEM handle
+ *
+ * @intf: ipmi interface
+ * @oemtype: OEM handle name
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_oem_setup(struct ipmi_intf * intf, char * oemtype)
+{
+ struct ipmi_oem_handle * oem;
+ int rc = 0;
+
+ if (oemtype == NULL ||
+ strncmp(oemtype, "help", 4) == 0 ||
+ strncmp(oemtype, "list", 4) == 0) {
+ ipmi_oem_print();
+ return -1;
+ }
+
+ for (oem=ipmi_oem_list; oem->name != NULL; oem++) {
+ if (strncmp(oemtype, oem->name, strlen(oem->name)) == 0)
+ break;
+ }
+
+ if (oem->name == NULL)
+ return -1;
+
+ /* save pointer for later use */
+ intf->oem = oem;
+
+ /* run optional setup function if it is defined */
+ if (oem->setup != NULL) {
+ lprintf(LOG_DEBUG, "Running OEM setup for \"%s\"", oem->desc);
+ rc = oem->setup(intf);
+ }
+
+ return rc;
+}
+
+/* ipmi_oem_active - used to determine if a particular OEM type is set
+ *
+ * @intf: ipmi interface
+ * @oemtype: string containing name of ipmi handle to check
+ *
+ * returns 1 if requested ipmi handle is active
+ * returns 0 otherwise
+ */
+int
+ipmi_oem_active(struct ipmi_intf * intf, const char * oemtype)
+{
+ if (intf->oem == NULL)
+ return 0;
+
+ if (strncmp(intf->oem->name, oemtype, strlen(oemtype)) == 0)
+ return 1;
+
+ return 0;
+}
diff --git a/lib/ipmi_pef.c b/lib/ipmi_pef.c
new file mode 100644
index 0000000..154bf40
--- /dev/null
+++ b/lib/ipmi_pef.c
@@ -0,0 +1,890 @@
+/*
+ * Copyright (c) 2004 Dell Computers. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Dell Computers, or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * DELL COMPUTERS ("DELL") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * DELL OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF DELL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#include <ipmitool/bswap.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_pef.h>
+
+extern int verbose;
+/*
+// common kywd/value printf() templates
+*/
+static const char * pef_fld_fmts[][2] = {
+ {"%-*s : %u\n", " | %u"}, /* F_DEC: unsigned value */
+ {"%-*s : %d\n", " | %d"}, /* F_INT: signed value */
+ {"%-*s : %s\n", " | %s"}, /* F_STR: string value */
+ {"%-*s : 0x%x\n", " | 0x%x"}, /* F_HEX: "N hex digits" */
+ {"%-*s : 0x%04x\n", " | 0x%04x"}, /* F_2XD: "2 hex digits" */
+ {"%-*s : 0x%02x\n", " | 0x%02x"}, /* F_1XD: "1 hex digit" */
+ {"%-*s : %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+ " | %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"},
+};
+typedef enum {
+ F_DEC,
+ F_INT,
+ F_STR,
+ F_HEX,
+ F_2XD,
+ F_1XD,
+ F_UID,
+} fmt_e;
+#define KYWD_LENGTH 24
+static int first_field = 1;
+
+static const char * pef_flag_fmts[][3] = {
+ {"", "false", "true"},
+ {"supported", "un", ""},
+ {"active", "in", ""},
+ {"abled", "dis", "en"},
+};
+static const char * listitem[] = {" | %s", ",%s", "%s"};
+
+const char *
+ipmi_pef_bit_desc(struct bit_desc_map * map, uint32_t value)
+{ /*
+ // return description/text label(s) for the given value.
+ // NB: uses a static buffer
+ */
+ static char buf[128];
+ char * p;
+ struct desc_map * pmap;
+ uint32_t match, index;
+
+ *(p = buf) = '\0';
+ index = 2;
+ for (pmap=map->desc_maps; pmap && pmap->desc; pmap++) {
+ if (map->desc_map_type == BIT_DESC_MAP_LIST)
+ match = (value == pmap->mask);
+ else
+ match = ((value & pmap->mask) == pmap->mask);
+
+ if (match) {
+ sprintf(p, listitem[index], pmap->desc);
+ p = strchr(p, '\0');
+ if (map->desc_map_type != BIT_DESC_MAP_ALL)
+ break;
+ index = 1;
+ }
+ }
+ if (p == buf)
+ return("None");
+
+ return((const char *)buf);
+}
+
+void
+ipmi_pef_print_flags(struct bit_desc_map * map, flg_e type, uint32_t val)
+{ /*
+ // print features/flags, using val (a bitmask), according to map.
+ // observe the verbose flag, and print any labels, etc. based on type
+ */
+ struct desc_map * pmap;
+ uint32_t maskval, index;
+
+ index = 0;
+ for (pmap=map->desc_maps; pmap && pmap->desc; pmap++) {
+ maskval = (val & pmap->mask);
+ if (verbose)
+ printf("%-*s : %s%s\n", KYWD_LENGTH,
+ ipmi_pef_bit_desc(map, pmap->mask),
+ pef_flag_fmts[type][1 + (maskval != 0)],
+ pef_flag_fmts[type][0]);
+ else if (maskval != 0) {
+ printf(listitem[index], ipmi_pef_bit_desc(map, maskval));
+ index = 1;
+ }
+ }
+}
+
+static void
+ipmi_pef_print_field(const char * fmt[2], const char * label, unsigned long val)
+{ /*
+ // print a 'field' (observes 'verbose' flag)
+ */
+ if (verbose)
+ printf(fmt[0], KYWD_LENGTH, label, val);
+ else if (first_field)
+ printf(&fmt[1][2], val); /* skip field separator */
+ else
+ printf(fmt[1], val);
+
+ first_field = 0;
+}
+
+void
+ipmi_pef_print_dec(const char * text, uint32_t val)
+{ /* unsigned */
+ ipmi_pef_print_field(pef_fld_fmts[F_DEC], text, val);
+}
+
+void
+ipmi_pef_print_int(const char * text, uint32_t val)
+{ /* signed */
+ ipmi_pef_print_field(pef_fld_fmts[F_INT], text, val);
+}
+
+void
+ipmi_pef_print_hex(const char * text, uint32_t val)
+{ /* hex */
+ ipmi_pef_print_field(pef_fld_fmts[F_HEX], text, val);
+}
+
+void
+ipmi_pef_print_str(const char * text, const char * val)
+{ /* string */
+ ipmi_pef_print_field(pef_fld_fmts[F_STR], text, (unsigned long)val);
+}
+
+void
+ipmi_pef_print_2xd(const char * text, uint8_t u1, uint8_t u2)
+{ /* 2 hex digits */
+ uint32_t val = ((u1 << 8) + u2) & 0xffff;
+ ipmi_pef_print_field(pef_fld_fmts[F_2XD], text, val);
+}
+
+void
+ipmi_pef_print_1xd(const char * text, uint32_t val)
+{ /* 1 hex digit */
+ ipmi_pef_print_field(pef_fld_fmts[F_1XD], text, val);
+}
+
+static struct ipmi_rs *
+ipmi_pef_msg_exchange(struct ipmi_intf * intf, struct ipmi_rq * req, char * txt)
+{ /*
+ // common IPMItool rqst/resp handling
+ */
+ struct ipmi_rs * rsp = intf->sendrecv(intf, req);
+ if (!rsp) {
+ return(NULL);
+ } else if (rsp->ccode == 0x80) {
+ return(NULL); /* Do not output error, just unsupported parameters */
+ } else if (rsp->ccode) {
+ lprintf(LOG_ERR, " **Error %x in '%s' command", rsp->ccode, txt);
+ return(NULL);
+ }
+ if (verbose > 2) {
+ printbuf(rsp->data, rsp->data_len, txt);
+ }
+ return(rsp);
+}
+
+static uint8_t
+ipmi_pef_get_policy_table(struct ipmi_intf * intf,
+ struct pef_cfgparm_policy_table_entry ** table)
+{ /*
+ // get the PEF policy table: allocate space, fillin, and return its size
+ // NB: the caller must free the returned area (when returned size > 0)
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_cfgparm_selector psel;
+ struct pef_cfgparm_policy_table_entry * ptbl, * ptmp;
+ uint32_t i;
+ uint8_t tbl_size;
+
+ memset(&psel, 0, sizeof(psel));
+ psel.id = PEF_CFGPARM_ID_PEF_ALERT_POLICY_TABLE_SIZE;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = IPMI_CMD_GET_PEF_CONFIG_PARMS;
+ req.msg.data = (uint8_t *)&psel;
+ req.msg.data_len = sizeof(psel);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Alert policy table size");
+ if (!rsp)
+ return(0);
+ tbl_size = (rsp->data[1] & PEF_POLICY_TABLE_SIZE_MASK);
+ i = (tbl_size * sizeof(struct pef_cfgparm_policy_table_entry));
+ if (!i
+ || (ptbl = (struct pef_cfgparm_policy_table_entry *)malloc(i)) == NULL)
+ return(0);
+
+ memset(&psel, 0, sizeof(psel));
+ psel.id = PEF_CFGPARM_ID_PEF_ALERT_POLICY_TABLE_ENTRY;
+ for (ptmp=ptbl, i=1; i<=tbl_size; i++) {
+ psel.set = (i & PEF_POLICY_TABLE_ID_MASK);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Alert policy table entry");
+ if (!rsp
+ || i != (rsp->data[1] & PEF_POLICY_TABLE_ID_MASK)) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Alert policy table entry");
+ free(ptbl);
+ ptbl = NULL;
+ tbl_size = 0;
+ break;
+ }
+ memcpy(ptmp, &rsp->data[1], sizeof(*ptmp));
+ ptmp++;
+ }
+
+ *table = ptbl;
+ return(tbl_size);
+}
+
+static void
+ipmi_pef_print_lan_dest(struct ipmi_intf * intf, uint8_t ch, uint8_t dest)
+{ /*
+ // print LAN alert destination info
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_lan_cfgparm_selector lsel;
+ struct pef_lan_cfgparm_dest_type * ptype;
+ struct pef_lan_cfgparm_dest_info * pinfo;
+ char buf[32];
+ uint8_t tbl_size, dsttype, timeout, retries;
+
+ memset(&lsel, 0, sizeof(lsel));
+ lsel.id = PEF_LAN_CFGPARM_ID_DEST_COUNT;
+ lsel.ch = ch;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_CMD_LAN_GET_CONFIG;
+ req.msg.data = (uint8_t *)&lsel;
+ req.msg.data_len = sizeof(lsel);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Alert destination count");
+ if (!rsp) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Alert destination count");
+ return;
+ }
+ tbl_size = (rsp->data[1] & PEF_LAN_DEST_TABLE_SIZE_MASK);
+ //if (tbl_size == 0 || dest == 0) /* LAN alerting not supported */
+ // return;
+
+ lsel.id = PEF_LAN_CFGPARM_ID_DESTTYPE;
+ lsel.set = dest;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Alert destination type");
+ if (!rsp || rsp->data[1] != lsel.set) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Alert destination type");
+ return;
+ }
+ ptype = (struct pef_lan_cfgparm_dest_type *)&rsp->data[1];
+ dsttype = (ptype->dest_type & PEF_LAN_DEST_TYPE_MASK);
+ timeout = ptype->alert_timeout;
+ retries = (ptype->retries & PEF_LAN_RETRIES_MASK);
+ ipmi_pef_print_str("Alert destination type",
+ ipmi_pef_bit_desc(&pef_b2s_lan_desttype, dsttype));
+ if (dsttype == PEF_LAN_DEST_TYPE_PET) {
+ lsel.id = PEF_LAN_CFGPARM_ID_PET_COMMUNITY;
+ lsel.set = 0;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "PET community");
+ if (!rsp)
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "PET community");
+ else {
+ rsp->data[19] = '\0';
+ ipmi_pef_print_str("PET Community", (const char *)&rsp->data[1]);
+ }
+ }
+ ipmi_pef_print_dec("ACK timeout/retry (secs)", timeout);
+ ipmi_pef_print_dec("Retries", retries);
+
+ lsel.id = PEF_LAN_CFGPARM_ID_DESTADDR;
+ lsel.set = dest;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Alert destination info");
+ if (!rsp || rsp->data[1] != lsel.set)
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Alert destination info");
+ else {
+ pinfo = (struct pef_lan_cfgparm_dest_info *)&rsp->data[1];
+ sprintf(buf, "%u.%u.%u.%u",
+ pinfo->ip[0], pinfo->ip[1], pinfo->ip[2], pinfo->ip[3]);
+ ipmi_pef_print_str("IP address", buf);
+
+ sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+ pinfo->mac[0], pinfo->mac[1], pinfo->mac[2],
+ pinfo->mac[3], pinfo->mac[4], pinfo->mac[5]);
+ ipmi_pef_print_str("MAC address", buf);
+ }
+}
+
+static void
+ipmi_pef_print_serial_dest_dial(struct ipmi_intf * intf, char * label,
+ struct pef_serial_cfgparm_selector * ssel)
+{ /*
+ // print a dial string
+ */
+#define BLOCK_SIZE 16
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_serial_cfgparm_selector tmp;
+ char * p, strval[(6 * BLOCK_SIZE) + 1];
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.id = PEF_SERIAL_CFGPARM_ID_DEST_DIAL_STRING_COUNT;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_CMD_SERIAL_GET_CONFIG;
+ req.msg.data = (uint8_t *)&tmp;
+ req.msg.data_len = sizeof(tmp);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Dial string count");
+ if (!rsp || (rsp->data[1] & PEF_SERIAL_DIAL_STRING_COUNT_MASK) == 0)
+ return; /* sssh, not supported */
+
+ memcpy(&tmp, ssel, sizeof(tmp));
+ tmp.id = PEF_SERIAL_CFGPARM_ID_DEST_DIAL_STRING;
+ tmp.block = 1;
+ memset(strval, 0, sizeof(strval));
+ p = strval;
+ for (;;) {
+ rsp = ipmi_pef_msg_exchange(intf, &req, label);
+ if (!rsp
+ || (rsp->data[1] != ssel->id)
+ || (rsp->data[2] != tmp.block)) {
+ lprintf(LOG_ERR, " **Error retrieving %s", label);
+ return;
+ }
+ memcpy(p, &rsp->data[3], BLOCK_SIZE);
+ if (strchr(p, '\0') <= (p + BLOCK_SIZE))
+ break;
+ if ((p += BLOCK_SIZE) >= &strval[sizeof(strval)-1])
+ break;
+ tmp.block++;
+ }
+
+ ipmi_pef_print_str(label, strval);
+#undef BLOCK_SIZE
+}
+
+static void
+ipmi_pef_print_serial_dest_tap(struct ipmi_intf * intf,
+ struct pef_serial_cfgparm_selector * ssel)
+{ /*
+ // print TAP destination info
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_serial_cfgparm_selector tmp;
+ struct pef_serial_cfgparm_tap_svc_settings * pset;
+ uint8_t dialstr_id, setting_id;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.id = PEF_SERIAL_CFGPARM_ID_TAP_ACCT_COUNT;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_CMD_SERIAL_GET_CONFIG;
+ req.msg.data = (uint8_t *)&tmp;
+ req.msg.data_len = sizeof(tmp);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Number of TAP accounts");
+ if (!rsp || (rsp->data[1] & PEF_SERIAL_TAP_ACCT_COUNT_MASK) == 0)
+ return; /* sssh, not supported */
+
+ memcpy(&tmp, ssel, sizeof(tmp));
+ tmp.id = PEF_SERIAL_CFGPARM_ID_TAP_ACCT_INFO;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "TAP account info");
+ if (!rsp || (rsp->data[1] != tmp.set)) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "TAP account info");
+ return;
+ }
+ dialstr_id = (rsp->data[2] & PEF_SERIAL_TAP_ACCT_INFO_DIAL_STRING_ID_MASK);
+ dialstr_id >>= PEF_SERIAL_TAP_ACCT_INFO_DIAL_STRING_ID_SHIFT;
+ setting_id = (rsp->data[2] & PEF_SERIAL_TAP_ACCT_INFO_SVC_SETTINGS_ID_MASK);
+ tmp.set = dialstr_id;
+ ipmi_pef_print_serial_dest_dial(intf, "TAP Dial string", &tmp);
+
+ tmp.set = setting_id;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "TAP service settings");
+ if (!rsp || (rsp->data[1] != tmp.set)) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "TAP service settings");
+ return;
+ }
+ pset = (struct pef_serial_cfgparm_tap_svc_settings *)&rsp->data[1];
+ ipmi_pef_print_str("TAP confirmation",
+ ipmi_pef_bit_desc(&pef_b2s_tap_svc_confirm, pset->confirmation_flags));
+
+ /* TODO : additional TAP settings? */
+}
+
+static void
+ipmi_pef_print_serial_dest_ppp(struct ipmi_intf * intf,
+ struct pef_serial_cfgparm_selector * ssel)
+{ /*
+ // print PPP destination info
+ */
+
+ /* TODO */
+}
+
+static void
+ipmi_pef_print_serial_dest_callback(struct ipmi_intf * intf,
+ struct pef_serial_cfgparm_selector * ssel)
+{ /*
+ // print callback destination info
+ */
+
+ /* TODO */
+}
+
+static void
+ipmi_pef_print_serial_dest(struct ipmi_intf * intf, uint8_t ch, uint8_t dest)
+{ /*
+ // print Serial/PPP alert destination info
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_serial_cfgparm_selector ssel;
+ uint8_t tbl_size, wrk;
+ struct pef_serial_cfgparm_dest_info * pinfo;
+
+ memset(&ssel, 0, sizeof(ssel));
+ ssel.id = PEF_SERIAL_CFGPARM_ID_DEST_COUNT;
+ ssel.ch = ch;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_CMD_SERIAL_GET_CONFIG;
+ req.msg.data = (uint8_t *)&ssel;
+ req.msg.data_len = sizeof(ssel);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Alert destination count");
+ if (!rsp) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Alert destination count");
+ return;
+ }
+ tbl_size = (rsp->data[1] & PEF_SERIAL_DEST_TABLE_SIZE_MASK);
+ if (!dest || tbl_size == 0) /* Page alerting not supported */
+ return;
+
+ ssel.id = PEF_SERIAL_CFGPARM_ID_DESTINFO;
+ ssel.set = dest;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Alert destination info");
+ if (!rsp || rsp->data[1] != ssel.set)
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Alert destination info");
+ else {
+ pinfo = (struct pef_serial_cfgparm_dest_info *)rsp->data;
+ wrk = (pinfo->dest_type & PEF_SERIAL_DEST_TYPE_MASK);
+ ipmi_pef_print_str("Alert destination type",
+ ipmi_pef_bit_desc(&pef_b2s_serial_desttype, wrk));
+ ipmi_pef_print_dec("ACK timeout (secs)",
+ pinfo->alert_timeout);
+ ipmi_pef_print_dec("Retries",
+ (pinfo->retries & PEF_SERIAL_RETRIES_MASK));
+ switch (wrk) {
+ case PEF_SERIAL_DEST_TYPE_DIAL:
+ ipmi_pef_print_serial_dest_dial(intf, "Serial dial string", &ssel);
+ break;
+ case PEF_SERIAL_DEST_TYPE_TAP:
+ ipmi_pef_print_serial_dest_tap(intf, &ssel);
+ break;
+ case PEF_SERIAL_DEST_TYPE_PPP:
+ ipmi_pef_print_serial_dest_ppp(intf, &ssel);
+ break;
+ case PEF_SERIAL_DEST_TYPE_BASIC_CALLBACK:
+ case PEF_SERIAL_DEST_TYPE_PPP_CALLBACK:
+ ipmi_pef_print_serial_dest_callback(intf, &ssel);
+ break;
+ }
+ }
+}
+
+static void
+ipmi_pef_print_dest(struct ipmi_intf * intf, uint8_t ch, uint8_t dest)
+{ /*
+ // print generic alert destination info
+ */
+ ipmi_pef_print_dec("Destination ID", dest);
+}
+
+void
+ipmi_pef_print_event_info(struct pef_cfgparm_filter_table_entry * pef, char * buf)
+{ /*
+ // print PEF entry Event info: class, severity, trigger, etc.
+ */
+ static char * classes[] = {"Discrete", "Threshold", "OEM"};
+ uint16_t offmask;
+ char * p;
+ int i;
+ uint8_t t;
+
+ ipmi_pef_print_str("Event severity",
+ ipmi_pef_bit_desc(&pef_b2s_severities, pef->entry.severity));
+
+ t = pef->entry.event_trigger;
+ if (t == PEF_EVENT_TRIGGER_THRESHOLD)
+ i = 1;
+ else if (t > PEF_EVENT_TRIGGER_SENSOR_SPECIFIC)
+ i = 2;
+ else
+ i = 0;
+ ipmi_pef_print_str("Event class", classes[i]);
+
+ offmask = ((pef->entry.event_data_1_offset_mask[1] << 8)
+ + pef->entry.event_data_1_offset_mask[0]);
+
+ if (offmask == 0xffff || t == PEF_EVENT_TRIGGER_MATCH_ANY)
+ strcpy(buf, "Any");
+ else if (t == PEF_EVENT_TRIGGER_UNSPECIFIED)
+ strcpy(buf, "Unspecified");
+ else if (t == PEF_EVENT_TRIGGER_SENSOR_SPECIFIC)
+ strcpy(buf, "Sensor-specific");
+ else if (t > PEF_EVENT_TRIGGER_SENSOR_SPECIFIC)
+ strcpy(buf, "OEM");
+ else {
+ sprintf(buf, "(0x%02x/0x%04x)", t, offmask);
+ p = strchr(buf, '\0');
+ for (i=0; i<PEF_B2S_GENERIC_ER_ENTRIES; i++) {
+ if (offmask & 1) {
+ if ((t-1) >= PEF_B2S_GENERIC_ER_ENTRIES) {
+ sprintf(p, ", Unrecognized event trigger");
+ } else {
+ sprintf(p, ",%s", ipmi_pef_bit_desc(pef_b2s_generic_ER[t-1], i));
+ }
+ p = strchr(p, '\0');
+ }
+ offmask >>= 1;
+ }
+ }
+
+ ipmi_pef_print_str("Event trigger(s)", buf);
+}
+
+static void
+ipmi_pef_print_entry(struct ipmi_rs * rsp, uint8_t id,
+ struct pef_cfgparm_filter_table_entry * pef)
+{ /*
+ // print a PEF table entry
+ */
+ uint8_t wrk, set;
+ char buf[128];
+
+ ipmi_pef_print_dec("PEF table entry", id);
+
+ wrk = !!(pef->entry.config & PEF_CONFIG_ENABLED);
+ sprintf(buf, "%sactive", (wrk ? "" : "in"));
+ if (pef->entry.config & PEF_CONFIG_PRECONFIGURED)
+ strcat(buf, ", pre-configured");
+
+ ipmi_pef_print_str("Status", buf);
+
+ if (wrk != 0) {
+ ipmi_pef_print_1xd("Version", rsp->data[0]);
+ ipmi_pef_print_str("Sensor type",
+ ipmi_pef_bit_desc(&pef_b2s_sensortypes, pef->entry.sensor_type));
+
+ if (pef->entry.sensor_number == PEF_SENSOR_NUMBER_MATCH_ANY)
+ ipmi_pef_print_str("Sensor number", "Any");
+ else
+ ipmi_pef_print_dec("Sensor number", pef->entry.sensor_number);
+
+ ipmi_pef_print_event_info(pef, buf);
+ ipmi_pef_print_str("Action",
+ ipmi_pef_bit_desc(&pef_b2s_actions, pef->entry.action));
+
+ if (pef->entry.action & PEF_ACTION_ALERT) {
+ set = (pef->entry.policy_number & PEF_POLICY_NUMBER_MASK);
+ ipmi_pef_print_int("Policy set", set);
+ }
+ }
+}
+
+static void
+ipmi_pef_list_entries(struct ipmi_intf * intf)
+{ /*
+ // list all PEF table entries
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_cfgparm_selector psel;
+ struct pef_cfgparm_filter_table_entry * pcfg;
+ uint32_t i;
+ uint8_t max_filters;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = IPMI_CMD_GET_PEF_CAPABILITIES;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "PEF capabilities");
+ if (!rsp
+ || (max_filters = ((struct pef_capabilities *)rsp->data)->tblsize) == 0)
+ return; /* sssh, not supported */
+
+ memset(&psel, 0, sizeof(psel));
+ psel.id = PEF_CFGPARM_ID_PEF_FILTER_TABLE_ENTRY;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = IPMI_CMD_GET_PEF_CONFIG_PARMS;
+ req.msg.data = (uint8_t *)&psel;
+ req.msg.data_len = sizeof(psel);
+ for (i=1; i<=max_filters; i++) {
+ if (i > 1)
+ printf("\n");
+ psel.set = (i & PEF_FILTER_TABLE_ID_MASK);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "PEF table entry");
+ if (!rsp
+ || (psel.set != (rsp->data[1] & PEF_FILTER_TABLE_ID_MASK))) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "PEF table entry");
+ continue;
+ }
+ pcfg = (struct pef_cfgparm_filter_table_entry *)&rsp->data[1];
+ first_field = 1;
+ ipmi_pef_print_entry(rsp, psel.set, pcfg);
+ }
+}
+
+static void
+ipmi_pef_list_policies(struct ipmi_intf * intf)
+{ /*
+ // list PEF alert policies
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_cfgparm_policy_table_entry * ptbl = NULL;
+ struct pef_cfgparm_policy_table_entry * ptmp = NULL;
+ uint32_t i;
+ uint8_t wrk, ch, medium, tbl_size;
+
+ tbl_size = ipmi_pef_get_policy_table(intf, &ptbl);
+ if (!tbl_size) {
+ if (!ptbl) {
+ free(ptbl);
+ ptbl = NULL;
+ }
+ return;
+ }
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_CMD_GET_CHANNEL_INFO;
+ req.msg.data = &ch;
+ req.msg.data_len = sizeof(ch);
+ for (ptmp=ptbl, i=1; i<=tbl_size; i++, ptmp++) {
+ if ((ptmp->entry.policy & PEF_POLICY_ENABLED) == PEF_POLICY_ENABLED) {
+ if (i > 1)
+ printf("\n");
+ first_field = 1;
+ ipmi_pef_print_dec("Alert policy table entry",
+ (ptmp->data1 & PEF_POLICY_TABLE_ID_MASK));
+ ipmi_pef_print_dec("Policy set",
+ (ptmp->entry.policy & PEF_POLICY_ID_MASK) >> PEF_POLICY_ID_SHIFT);
+ ipmi_pef_print_str("Policy entry rule",
+ ipmi_pef_bit_desc(&pef_b2s_policies, (ptmp->entry.policy & PEF_POLICY_FLAGS_MASK)));
+
+ if (ptmp->entry.alert_string_key & PEF_POLICY_EVENT_SPECIFIC) {
+ ipmi_pef_print_str("Event-specific", "true");
+// continue;
+ }
+ wrk = ptmp->entry.chan_dest;
+
+ /* channel/description */
+ ch = (wrk & PEF_POLICY_CHANNEL_MASK) >> PEF_POLICY_CHANNEL_SHIFT;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Channel info");
+ if (!rsp || rsp->data[0] != ch) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Channel info");
+ continue;
+ }
+ medium = rsp->data[1];
+ ipmi_pef_print_dec("Channel number", ch);
+ ipmi_pef_print_str("Channel medium",
+ ipmi_pef_bit_desc(&pef_b2s_ch_medium, medium));
+
+ /* destination/description */
+ wrk &= PEF_POLICY_DESTINATION_MASK;
+ switch (medium) {
+ case PEF_CH_MEDIUM_TYPE_LAN:
+ ipmi_pef_print_lan_dest(intf, ch, wrk);
+ break;
+ case PEF_CH_MEDIUM_TYPE_SERIAL:
+ ipmi_pef_print_serial_dest(intf, ch, wrk);
+ break;
+ default:
+ ipmi_pef_print_dest(intf, ch, wrk);
+ break;
+ }
+ }
+ }
+ free(ptbl);
+ ptbl = NULL;
+}
+
+static void
+ipmi_pef_get_status(struct ipmi_intf * intf)
+{ /*
+ // report the PEF status
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_cfgparm_selector psel;
+ char tbuf[40];
+ uint32_t timei;
+ time_t ts;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = IPMI_CMD_GET_LAST_PROCESSED_EVT_ID;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "Last S/W processed ID");
+ if (!rsp) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "Last S/W processed ID");
+ return;
+ }
+ memcpy(&timei, rsp->data, sizeof(timei));
+#if WORDS_BIGENDIAN
+ timei = BSWAP_32(timei);
+#endif
+ ts = (time_t)timei;
+
+ strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&ts));
+
+ ipmi_pef_print_str("Last SEL addition", tbuf);
+ ipmi_pef_print_2xd("Last SEL record ID", rsp->data[5], rsp->data[4]);
+ ipmi_pef_print_2xd("Last S/W processed ID", rsp->data[7], rsp->data[6]);
+ ipmi_pef_print_2xd("Last BMC processed ID", rsp->data[9], rsp->data[8]);
+
+ memset(&psel, 0, sizeof(psel));
+ psel.id = PEF_CFGPARM_ID_PEF_CONTROL;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = IPMI_CMD_GET_PEF_CONFIG_PARMS;
+ req.msg.data = (uint8_t *)&psel;
+ req.msg.data_len = sizeof(psel);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "PEF control");
+ if (!rsp) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "PEF control");
+ return;
+ }
+ ipmi_pef_print_flags(&pef_b2s_control, P_ABLE, rsp->data[1]);
+
+ psel.id = PEF_CFGPARM_ID_PEF_ACTION;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "PEF action");
+ if (!rsp) {
+ lprintf(LOG_ERR, " **Error retrieving %s",
+ "PEF action");
+ return;
+ }
+ ipmi_pef_print_flags(&pef_b2s_actions, P_ACTV, rsp->data[1]);
+}
+
+static void
+ipmi_pef_get_info(struct ipmi_intf * intf)
+{ /*
+ // report PEF capabilities + System GUID
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct pef_capabilities * pcap;
+ struct pef_cfgparm_selector psel;
+ struct pef_cfgparm_policy_table_entry * ptbl = NULL;
+ uint8_t * uid;
+ uint8_t actions, tbl_size;
+
+ tbl_size = ipmi_pef_get_policy_table(intf, &ptbl);
+ if (!ptbl) {
+ free(ptbl);
+ ptbl = NULL;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = IPMI_CMD_GET_PEF_CAPABILITIES;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "PEF capabilities");
+ if (!rsp)
+ return;
+ pcap = (struct pef_capabilities *)rsp->data;
+
+ ipmi_pef_print_1xd("Version", pcap->version);
+ ipmi_pef_print_dec("PEF table size", pcap->tblsize);
+ ipmi_pef_print_dec("Alert policy table size", tbl_size);
+ actions = pcap->actions;
+
+ memset(&psel, 0, sizeof(psel));
+ psel.id = PEF_CFGPARM_ID_SYSTEM_GUID;
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = IPMI_CMD_GET_PEF_CONFIG_PARMS;
+ req.msg.data = (uint8_t *)&psel;
+ req.msg.data_len = sizeof(psel);
+ rsp = ipmi_pef_msg_exchange(intf, &req, "System GUID");
+ uid = NULL;
+ if (rsp && (rsp->data[1] & PEF_SYSTEM_GUID_USED_IN_PET))
+ uid = &rsp->data[2];
+ else {
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_CMD_GET_SYSTEM_GUID;
+ rsp = ipmi_pef_msg_exchange(intf, &req, "System GUID");
+ if (rsp)
+ uid = &rsp->data[0];
+ }
+ if (uid) { /* got GUID? */
+ if (verbose)
+ printf(pef_fld_fmts[F_UID][0], KYWD_LENGTH, "System GUID",
+ uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7],
+ uid[8], uid[9], uid[10],uid[11],uid[12],uid[13],uid[14],uid[15]);
+ else
+ printf(pef_fld_fmts[F_UID][1],
+ uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7],
+ uid[8], uid[9], uid[10],uid[11],uid[12],uid[13],uid[14],uid[15]);
+ }
+ ipmi_pef_print_flags(&pef_b2s_actions, P_SUPP, actions);
+}
+
+int ipmi_pef_main(struct ipmi_intf * intf, int argc, char ** argv)
+{ /*
+ // PEF subcommand handling
+ */
+ int help = 0;
+ int rc = 0;
+
+ if (!argc || !strncmp(argv[0], "info", 4))
+ ipmi_pef_get_info(intf);
+ else if (!strncmp(argv[0], "help", 4))
+ help = 1;
+ else if (!strncmp(argv[0], "status", 6))
+ ipmi_pef_get_status(intf);
+ else if (!strncmp(argv[0], "policy", 6))
+ ipmi_pef_list_policies(intf);
+ else if (!strncmp(argv[0], "list", 4))
+ ipmi_pef_list_entries(intf);
+ else {
+ help = 1;
+ rc = -1;
+ lprintf(LOG_ERR, "Invalid PEF command: '%s'\n", argv[0]);
+ }
+
+ if (help)
+ lprintf(LOG_NOTICE, "PEF commands: info status policy list");
+ else if (!verbose)
+ printf("\n");
+
+ return rc;
+}
diff --git a/lib/ipmi_picmg.c b/lib/ipmi_picmg.c
new file mode 100644
index 0000000..d1c82b2
--- /dev/null
+++ b/lib/ipmi_picmg.c
@@ -0,0 +1,2371 @@
+/*
+ Copyright (c) Kontron. All right reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Kontron, or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * DELL COMPUTERS ("DELL") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * DELL OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF DELL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_picmg.h>
+#include <ipmitool/ipmi_fru.h> /* for access to link descriptor defines */
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/log.h>
+
+#define PICMG_EXTENSION_ATCA_MAJOR_VERSION 2
+#define PICMG_EXTENSION_AMC0_MAJOR_VERSION 4
+#define PICMG_EXTENSION_UTCA_MAJOR_VERSION 5
+
+
+#define PICMG_EKEY_MODE_QUERY 0
+#define PICMG_EKEY_MODE_PRINT_ALL 1
+#define PICMG_EKEY_MODE_PRINT_ENABLED 2
+#define PICMG_EKEY_MODE_PRINT_DISABLED 3
+
+#define PICMG_EKEY_MAX_CHANNEL 16
+#define PICMG_EKEY_MAX_FABRIC_CHANNEL 15
+#define PICMG_EKEY_MAX_INTERFACE 3
+
+#define PICMG_EKEY_AMC_MAX_CHANNEL 16
+#define PICMG_EKEY_AMC_MAX_DEVICE 15 /* 4 bits */
+
+
+typedef enum picmg_bused_resource_mode {
+ PICMG_BUSED_RESOURCE_SUMMARY,
+} t_picmg_bused_resource_mode ;
+
+
+typedef enum picmg_card_type {
+ PICMG_CARD_TYPE_CPCI,
+ PICMG_CARD_TYPE_ATCA,
+ PICMG_CARD_TYPE_AMC,
+ PICMG_CARD_TYPE_RESERVED
+} t_picmg_card_type ;
+
+/* This is the version of the PICMG Extenstion */
+static t_picmg_card_type PicmgCardType = PICMG_CARD_TYPE_RESERVED;
+
+void
+ipmi_picmg_help (void)
+{
+ lprintf(LOG_NOTICE, "PICMG commands:");
+ lprintf(LOG_NOTICE, " properties - get PICMG properties");
+ lprintf(LOG_NOTICE, " frucontrol - FRU control");
+ lprintf(LOG_NOTICE, " addrinfo - get address information");
+ lprintf(LOG_NOTICE, " activate - activate a FRU");
+ lprintf(LOG_NOTICE, " deactivate - deactivate a FRU");
+ lprintf(LOG_NOTICE, " policy get - get the FRU activation policy");
+ lprintf(LOG_NOTICE, " policy set - set the FRU activation policy");
+ lprintf(LOG_NOTICE, " portstate get - get port state");
+ lprintf(LOG_NOTICE,
+ " portstate getdenied - get all denied[disabled] port description");
+ lprintf(LOG_NOTICE,
+ " portstate getgranted - get all granted[enabled] port description");
+ lprintf(LOG_NOTICE,
+ " portstate getall - get all port state description");
+ lprintf(LOG_NOTICE, " portstate set - set port state");
+ lprintf(LOG_NOTICE, " amcportstate get - get port state");
+ lprintf(LOG_NOTICE, " amcportstate set - set port state");
+ lprintf(LOG_NOTICE, " led prop - get led properties");
+ lprintf(LOG_NOTICE, " led cap - get led color capabilities");
+ lprintf(LOG_NOTICE, " led get - get led state");
+ lprintf(LOG_NOTICE, " led set - set led state");
+ lprintf(LOG_NOTICE, " power get - get power level info");
+ lprintf(LOG_NOTICE, " power set - set power level");
+ lprintf(LOG_NOTICE, " clk get - get clk state");
+ lprintf(LOG_NOTICE,
+ " clk getdenied - get all(up to 16) denied[disabled] clock descriptions");
+ lprintf(LOG_NOTICE,
+ " clk getgranted - get all(up to 16) granted[enabled] clock descriptions");
+ lprintf(LOG_NOTICE,
+ " clk getall - get all(up to 16) clock descriptions");
+ lprintf(LOG_NOTICE, " clk set - set clk state");
+ lprintf(LOG_NOTICE,
+ " busres summary - display brief bused resource status info");
+}
+
+
+struct sAmcAddrMap {
+ unsigned char ipmbLAddr;
+ char* amcBayId;
+ unsigned char siteNum;
+} amcAddrMap[] = {
+ {0xFF, "reserved", 0},
+ {0x72, "A1" , 1},
+ {0x74, "A2" , 2},
+ {0x76, "A3" , 3},
+ {0x78, "A4" , 4},
+ {0x7A, "B1" , 5},
+ {0x7C, "B2" , 6},
+ {0x7E, "B3" , 7},
+ {0x80, "B4" , 8},
+ {0x82, "reserved", 0},
+ {0x84, "reserved", 0},
+ {0x86, "reserved", 0},
+ {0x88, "reserved", 0},
+};
+
+/* is_amc_channel - wrapper to convert user input into integer
+ * AMC Channel range seems to be <0..255>, bits [7:0]
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @amc_chan_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_amc_channel(const char *argv_ptr, uint8_t *amc_chan_ptr)
+{
+ if (!argv_ptr || !amc_chan_ptr) {
+ lprintf(LOG_ERR, "is_amc_channel(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, amc_chan_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given AMC Channel '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_amc_dev - wrapper to convert user input into integer.
+ * AMC Dev ID limits are uknown.
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @amc_dev_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_amc_dev(const char *argv_ptr, int32_t *amc_dev_ptr)
+{
+ if (!argv_ptr || !amc_dev_ptr) {
+ lprintf(LOG_ERR, "is_amc_dev(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2int(argv_ptr, amc_dev_ptr) == 0 && *amc_dev_ptr >= 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given PICMG Device '%s' is invalid.",
+ argv_ptr);
+ return (-1);
+}
+/* is_amc_intf - wrapper to convert user input into integer.
+ * AMC Interface (ID) limits are uknown.
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @amc_intf_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_amc_intf(const char *argv_ptr, int32_t *amc_intf_ptr)
+{
+ if (!argv_ptr || !amc_intf_ptr) {
+ lprintf(LOG_ERR, "is_amc_intf(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2int(argv_ptr, amc_intf_ptr) == 0 && *amc_intf_ptr >= 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given PICMG Interface '%s' is invalid.",
+ argv_ptr);
+ return (-1);
+}
+/* is_amc_port - wrapper to convert user input into integer.
+ * AMC Port limits are uknown.
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @amc_port_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_amc_port(const char *argv_ptr, int32_t *amc_port_ptr)
+{
+ if (!argv_ptr || !amc_port_ptr) {
+ lprintf(LOG_ERR, "is_amc_port(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2int(argv_ptr, amc_port_ptr) == 0 && *amc_port_ptr >= 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given PICMG Port '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_clk_acc - wrapper to convert user input into integer.
+ * Clock Accuracy limits are uknown[1byte by spec].
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @clk_acc_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_clk_acc(const char *argv_ptr, uint8_t *clk_acc_ptr)
+{
+ if (!argv_ptr || !clk_acc_ptr) {
+ lprintf(LOG_ERR, "is_clk_acc(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, clk_acc_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Clock Accuracy '%s' is invalid.",
+ argv_ptr);
+ return (-1);
+}
+/* is_clk_family - wrapper to convert user input into integer.
+ * Clock Family limits are uknown[1byte by spec].
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @clk_family_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_clk_family(const char *argv_ptr, uint8_t *clk_family_ptr)
+{
+ if (!argv_ptr || !clk_family_ptr) {
+ lprintf(LOG_ERR, "is_clk_family(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, clk_family_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Clock Family '%s' is invalid.",
+ argv_ptr);
+ return (-1);
+}
+/* is_clk_freq - wrapper to convert user input into integer.
+ * Clock Frequency limits are uknown, but specification says
+ * 3Bytes + 1B checksum
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @clk_freq_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_clk_freq(const char *argv_ptr, uint32_t *clk_freq_ptr)
+{
+ if (!argv_ptr || !clk_freq_ptr) {
+ lprintf(LOG_ERR, "is_clk_freq(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uint(argv_ptr, clk_freq_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Clock Frequency '%s' is invalid.",
+ argv_ptr);
+ return (-1);
+}
+/* is_clk_id - wrapper to convert user input into integer.
+ * Clock ID limits are uknown, however it's 1B by specification and I've
+ * found two ranges: <1..5> or <0..15>
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @clk_id_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_clk_id(const char *argv_ptr, uint8_t *clk_id_ptr)
+{
+ if (!argv_ptr || !clk_id_ptr) {
+ lprintf(LOG_ERR, "is_clk_id(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, clk_id_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Clock ID '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_clk_index - wrapper to convert user input into integer.
+ * Clock Index limits are uknown[1B by spec]
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @clk_index_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_clk_index(const char *argv_ptr, uint8_t *clk_index_ptr)
+{
+ if (!argv_ptr || !clk_index_ptr) {
+ lprintf(LOG_ERR, "is_clk_index(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, clk_index_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Clock Index '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_clk_resid - wrapper to convert user input into integer.
+ * Clock Resource Index(?) limits are uknown, but maximum seems to be 15.
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @clk_resid_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_clk_resid(const char *argv_ptr, int8_t *clk_resid_ptr)
+{
+ if (!argv_ptr || !clk_resid_ptr) {
+ lprintf(LOG_ERR, "is_clk_resid(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2char(argv_ptr, clk_resid_ptr) == 0
+ && *clk_resid_ptr > (-1)) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Resource ID '%s' is invalid.",
+ clk_resid_ptr);
+ return (-1);
+}
+/* is_clk_setting - wrapper to convert user input into integer.
+ * Clock Setting is a 1B bitfield:
+ * x [7:4] - reserved
+ * x [3] - state - 0/1
+ * x [2] - direction - 0/1
+ * x [1:0] - PLL ctrl - 00/01/10/11[Reserved]
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @clk_setting_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_clk_setting(const char *argv_ptr, uint8_t *clk_setting_ptr)
+{
+ if (!argv_ptr || !clk_setting_ptr) {
+ lprintf(LOG_ERR, "is_clk_setting(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, clk_setting_ptr) == 0) {
+ return 0;
+ }
+ /* FIXME - validate bits 4-7 are 0 ? */
+ lprintf(LOG_ERR, "Given Clock Setting '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_enable - wrapper to convert user input into integer.
+ * Valid input range for Enable is <0..1>.
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @enable_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_enable(const char *argv_ptr, uint8_t *enable_ptr)
+{
+ if (!argv_ptr || !enable_ptr) {
+ lprintf(LOG_ERR, "is_enable(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, enable_ptr) == 0
+ && (*enable_ptr == 0 || *enable_ptr == 1)) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Enable '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_enable - wrapper to convert user input into integer.
+ * LED colors:
+ * - valid <1..6>, <0xE..0xF>
+ * - reserved [0, 7]
+ * - undefined <8..D>
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @enable_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_led_color(const char *argv_ptr, uint8_t *led_color_ptr)
+{
+ if (!argv_ptr || !led_color_ptr) {
+ lprintf(LOG_ERR, "is_led_color(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, led_color_ptr) != 0) {
+ lprintf(LOG_ERR, "Given LED Color '%s' is invalid.",
+ argv_ptr);
+ lprintf(LOG_ERR,
+ "LED Color must be from ranges: <1..6>, <0xE..0xF>");
+ return (-1);
+ }
+ if ((*led_color_ptr >= 1 && *led_color_ptr <= 6)
+ || (*led_color_ptr >= 0xE && *led_color_ptr <= 0xF)) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given LED Color '%s' is out of range.", argv_ptr);
+ lprintf(LOG_ERR, "LED Color must be from ranges: <1..6>, <0xE..0xF>");
+ return (-1);
+}
+/* is_led_duration - wrapper to convert user input into integer.
+ * LED duration range is <1..127>
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @enable_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_led_duration(const char *argv_ptr, uint8_t *led_duration_ptr)
+{
+ if (!argv_ptr || !led_duration_ptr) {
+ lprintf(LOG_ERR, "is_led_duration(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, led_duration_ptr) == 0
+ && *led_duration_ptr > 0 && *led_duration_ptr <= 127) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given LED Duration '%s' is invalid", argv_ptr);
+ return (-1);
+}
+/* is_led_function - wrapper to convert user input into integer.
+ * LED functions, however, might differ by OEM:
+ * - 0x00 - off override
+ * - <0x01..0xFA> - blinking override
+ * - 0xFB - lamp test state
+ * - 0xFC - state restored to local ctrl state
+ * - <0xFD..0xFE> - reserved
+ * - 0xFF - on override
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @led_fn_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_led_function(const char *argv_ptr, uint8_t *led_fn_ptr)
+{
+ if (!argv_ptr || !led_fn_ptr) {
+ lprintf(LOG_ERR, "is_led_function(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, led_fn_ptr) == 0
+ && (*led_fn_ptr < 0xFD || *led_fn_ptr > 0xFE)) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given LED Function '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_led_id - wrapper to convert user input into integer.
+ * LED ID range seems to be <0..255>
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @led_id_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_led_id(const char *argv_ptr, uint8_t *led_id_ptr)
+{
+ if (!argv_ptr || !led_id_ptr) {
+ lprintf(LOG_ERR, "is_led_id(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, led_id_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given LED ID '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_link_group - wrapper to convert user input into integer.
+ * Link Grouping ID limis are unknown, bits [31:24] by spec.
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @link_grp_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_link_group(const char *argv_ptr, uint8_t *link_grp_ptr)
+{
+ if (!argv_ptr || !link_grp_ptr) {
+ lprintf(LOG_ERR, "is_link_group(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, link_grp_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Link Group '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_link_type - wrapper to convert user input into integer.
+ * Link Type limits are unknown, bits [19:12]
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @link_type_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_link_type(const char *argv_ptr, uint8_t *link_type_ptr)
+{
+ if (!argv_ptr || !link_type_ptr) {
+ lprintf(LOG_ERR, "is_link_type(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, link_type_ptr) == 0) {
+ return 0;
+ }
+ lprintf(LOG_ERR, "Given Link Type '%s' is invalid.", argv_ptr);
+ return (-1);
+}
+/* is_link_type_ext - wrapper to convert user input into integer.
+ * Link Type Extension limits are unknown, bits [23:20] => <0..15> ?
+ *
+ * @argv_ptr: source string to convert from; usually argv
+ * @link_type_ext_ptr: pointer where to store result
+ * returns: zero on success, other values mean error
+ */
+int
+is_link_type_ext(const char *argv_ptr, uint8_t *link_type_ext_ptr)
+{
+ if (!argv_ptr || !link_type_ext_ptr) {
+ lprintf(LOG_ERR, "is_link_type_ext(): invalid argument(s).");
+ return (-1);
+ }
+ if (str2uchar(argv_ptr, link_type_ext_ptr) != 0
+ || *link_type_ext_ptr > 15) {
+ lprintf(LOG_ERR,
+ "Given Link Type Extension '%s' is invalid.",
+ argv_ptr);
+ return (-1);
+ }
+ return 0;
+}
+
+int
+ipmi_picmg_getaddr(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char msg_data[5];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+ msg_data[0] = 0; /* picmg identifier */
+ msg_data[1] = 0; /* default fru id */
+
+ if(argc > 0) {
+ if (is_fru_id(argv[0], &msg_data[1]) != 0) {
+ return (-1);
+ }
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp) {
+ lprintf(LOG_ERR, "Error. No valid response received.");
+ return (-1);
+ } else if (rsp->ccode) {
+ lprintf(LOG_ERR, "Error getting address information CC: 0x%02x",
+ rsp->ccode);
+ return (-1);
+ }
+
+ printf("Hardware Address : 0x%02x\n", rsp->data[1]);
+ printf("IPMB-0 Address : 0x%02x\n", rsp->data[2]);
+ printf("FRU ID : 0x%02x\n", rsp->data[4]);
+ printf("Site ID : 0x%02x\n", rsp->data[5]);
+
+ printf("Site Type : ");
+ switch (rsp->data[6]) {
+ case PICMG_ATCA_BOARD:
+ printf("ATCA board\n");
+ break;
+ case PICMG_POWER_ENTRY:
+ printf("Power Entry Module\n");
+ break;
+ case PICMG_SHELF_FRU:
+ printf("Shelf FRU\n");
+ break;
+ case PICMG_DEDICATED_SHMC:
+ printf("Dedicated Shelf Manager\n");
+ break;
+ case PICMG_FAN_TRAY:
+ printf("Fan Tray\n");
+ break;
+ case PICMG_FAN_FILTER_TRAY:
+ printf("Fan Filter Tray\n");
+ break;
+ case PICMG_ALARM:
+ printf("Alarm module\n");
+ break;
+ case PICMG_AMC:
+ printf("AMC");
+ printf(" -> IPMB-L Address: 0x%02x\n", amcAddrMap[rsp->data[5]].ipmbLAddr);
+ break;
+ case PICMG_PMC:
+ printf("PMC\n");
+ break;
+ case PICMG_RTM:
+ printf("RTM\n");
+ break;
+ default:
+ if (rsp->data[6] >= 0xc0 && rsp->data[6] <= 0xcf) {
+ printf("OEM\n");
+ } else {
+ printf("unknown\n");
+ }
+ }
+
+ return 0;
+}
+
+int
+ipmi_picmg_properties(struct ipmi_intf * intf, int show )
+{
+ unsigned char PicmgExtMajorVersion;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char msg_data;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD;
+ req.msg.data = &msg_data;
+ req.msg.data_len = 1;
+ msg_data = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp || rsp->ccode) {
+ lprintf(LOG_ERR, "Error getting address information.");
+ return -1;
+ }
+
+ if( show )
+ {
+ printf("PICMG identifier : 0x%02x\n", rsp->data[0]);
+ printf("PICMG Ext. Version : %i.%i\n", rsp->data[1]&0x0f,
+ (rsp->data[1]&0xf0) >> 4);
+ printf("Max FRU Device ID : 0x%02x\n", rsp->data[2]);
+ printf("FRU Device ID : 0x%02x\n", rsp->data[3]);
+ }
+
+ /* We cache the major extension version ...
+ to know how to format some commands */
+ PicmgExtMajorVersion = rsp->data[1]&0x0f;
+
+ if( PicmgExtMajorVersion == PICMG_CPCI_MAJOR_VERSION ) {
+ PicmgCardType = PICMG_CARD_TYPE_CPCI;
+ }
+ else if( PicmgExtMajorVersion == PICMG_ATCA_MAJOR_VERSION) {
+ PicmgCardType = PICMG_CARD_TYPE_ATCA;
+ }
+ else if( PicmgExtMajorVersion == PICMG_AMC_MAJOR_VERSION) {
+ PicmgCardType = PICMG_CARD_TYPE_AMC;
+ }
+
+ return 0;
+}
+
+
+
+#define PICMG_FRU_DEACTIVATE (unsigned char) 0x00
+#define PICMG_FRU_ACTIVATE (unsigned char) 0x01
+
+int
+ipmi_picmg_fru_activation(struct ipmi_intf * intf, int argc, char ** argv, unsigned char state)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ struct picmg_set_fru_activation_cmd cmd;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_FRU_ACTIVATION_CMD;
+ req.msg.data = (unsigned char*) &cmd;
+ req.msg.data_len = 3;
+
+ cmd.picmg_id = 0; /* PICMG identifier */
+ if (is_fru_id(argv[0], &(cmd.fru_id)) != 0) {
+ return (-1);
+ }
+ cmd.fru_state = state;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp || rsp->ccode) {
+ lprintf(LOG_ERR, "Error activation/deactivation of FRU.");
+ return -1;
+ }
+ if (rsp->data[0] != 0x00) {
+ lprintf(LOG_ERR, "Error activation/deactivation of FRU.");
+ }
+
+ return 0;
+}
+
+
+int
+ipmi_picmg_fru_activation_policy_get(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[4];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_FRU_POLICY_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ msg_data[0] = 0; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0) {
+ return (-1);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "FRU activation policy get failed with CC code 0x%02x",
+ rsp->ccode);
+ return -1;
+ }
+
+ printf(" %s\n", ((rsp->data[1] & 0x01) == 0x01) ?
+ "activation locked" : "activation not locked");
+ printf(" %s\n", ((rsp->data[1] & 0x02) == 0x02) ?
+ "deactivation locked" : "deactivation not locked");
+
+ return 0;
+}
+
+int
+ipmi_picmg_fru_activation_policy_set(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[4];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_SET_FRU_POLICY_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ msg_data[0] = 0; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0) {
+ return (-1);
+ }
+ if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 1) {
+ /* FRU Lock Mask */
+ lprintf(LOG_ERR, "Given FRU Lock Mask '%s' is invalid.",
+ argv[1]);
+ return (-1);
+ }
+ if (str2uchar(argv[2], &msg_data[3]) != 0 || msg_data[3] > 1) {
+ /* FRU Act Policy */
+ lprintf(LOG_ERR,
+ "Given FRU Activation Policy '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ msg_data[2]&= 0x03;
+ msg_data[3]&= 0x03;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "FRU activation policy set failed with CC code 0x%02x",
+ rsp->ccode);
+ return -1;
+ }
+
+ return 0;
+}
+
+#define PICMG_MAX_LINK_PER_CHANNEL 4
+
+int
+ipmi_picmg_portstate_get(struct ipmi_intf * intf, int32_t interface,
+ uint8_t channel, int mode)
+{
+ struct ipmi_rs * rsp = NULL;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[4];
+
+ struct fru_picmgext_link_desc* d; /* descriptor pointer for rec. data */
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_PORT_STATE_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ msg_data[1] = (interface & 0x3)<<6; /* interface */
+ msg_data[1] |= (channel & 0x3F); /* channel number */
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ if( mode == PICMG_EKEY_MODE_QUERY ){
+ lprintf(LOG_ERR, "FRU portstate get failed with CC code 0x%02x",
+ rsp->ccode);
+ }
+ return -1;
+ }
+
+ if (rsp->data_len >= 6) {
+ int index;
+ /* add support for more than one link per channel */
+ for(index=0;index<PICMG_MAX_LINK_PER_CHANNEL;index++){
+ if( rsp->data_len > (1+ (index*5))){
+ d = (struct fru_picmgext_link_desc *) &(rsp->data[1 + (index*5)]);
+
+ if
+ (
+ mode == PICMG_EKEY_MODE_PRINT_ALL
+ ||
+ mode == PICMG_EKEY_MODE_QUERY
+ ||
+ (
+ mode == PICMG_EKEY_MODE_PRINT_ENABLED
+ &&
+ rsp->data[5 + (index*5) ] == 0x01
+ )
+ ||
+ (
+ mode == PICMG_EKEY_MODE_PRINT_DISABLED
+ &&
+ rsp->data[5 + (index*5) ] == 0x00
+ )
+ )
+ {
+ printf(" Link Grouping ID: 0x%02x\n", d->grouping);
+ printf(" Link Type Extension: 0x%02x\n", d->ext);
+ printf(" Link Type: 0x%02x ", d->type);
+ if (d->type == 0 || d->type == 0xff)
+ {
+ printf("Reserved %d\n",d->type);
+ }
+ else if (d->type >= 0x06 && d->type <= 0xef)
+ {
+ printf("Reserved\n");
+ }
+ else if (d->type >= 0xf0 && d->type <= 0xfe)
+ {
+ printf("OEM GUID Definition\n");
+ }
+ else
+ {
+ switch (d->type)
+ {
+ case FRU_PICMGEXT_LINK_TYPE_BASE:
+ printf("PICMG 3.0 Base Interface 10/100/1000\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET:
+ printf("PICMG 3.1 Ethernet Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND:
+ printf("PICMG 3.2 Infiniband Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR:
+ printf("PICMG 3.3 Star Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_LINK_TYPE_PCIE:
+ printf("PCI Express Fabric Interface\n");
+ break;
+ default:
+ printf("Invalid\n");
+ break;
+ }
+ }
+ printf(" Link Designator: \n");
+ printf(" Port Flag: 0x%02x\n", d->desig_port);
+ printf(" Interface: 0x%02x - ", d->desig_if);
+ switch (d->desig_if)
+ {
+ case FRU_PICMGEXT_DESIGN_IF_BASE:
+ printf("Base Interface\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_FABRIC:
+ printf("Fabric Interface\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL:
+ printf("Update Channel\n");
+ break;
+ case FRU_PICMGEXT_DESIGN_IF_RESERVED:
+ printf("Reserved\n");
+ break;
+ default:
+ printf("Invalid");
+ break;
+ }
+ printf(" Channel Number: 0x%02x\n", d->desig_channel);
+ printf(" STATE: %s\n",
+ ( rsp->data[5 +(index*5)] == 0x01) ?"enabled":"disabled");
+ printf("\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Unexpected answer, can't print result.");
+ }
+
+ return 0;
+}
+
+
+int
+ipmi_picmg_portstate_set(struct ipmi_intf * intf, int32_t interface,
+ uint8_t channel, int32_t port, uint8_t type,
+ uint8_t typeext, uint8_t group, uint8_t enable)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_SET_PORT_STATE_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 6;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ msg_data[1] = (channel & 0x3f) | ((interface & 3) << 6);
+ msg_data[2] = (port & 0xf) | ((type & 0xf) << 4);
+ msg_data[3] = ((type >> 4) & 0xf) | ((typeext & 0xf) << 4);
+ msg_data[4] = group & 0xff;
+ msg_data[5] = (enable & 0x01); /* enable/disable */
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Picmg portstate set failed with CC code 0x%02x",
+ rsp->ccode);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/* AMC.0 commands */
+
+#define PICMG_AMC_MAX_LINK_PER_CHANNEL 4
+
+int
+ipmi_picmg_amc_portstate_get(struct ipmi_intf * intf, int32_t device,
+ uint8_t channel, int mode)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[4];
+
+ struct fru_picmgext_amc_link_info* d; /* descriptor pointer for rec. data */
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_AMC_GET_PORT_STATE_CMD;
+ req.msg.data = msg_data;
+
+ /* FIXME : add check for AMC or carrier device */
+ if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){
+ req.msg.data_len = 2; /* for amc only channel */
+ }else{
+ req.msg.data_len = 3; /* for carrier channel and device */
+ }
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ msg_data[1] = channel ;
+ msg_data[2] = device ;
+
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ if( mode == PICMG_EKEY_MODE_QUERY ){
+ lprintf(LOG_ERR, "Amc portstate get failed with CC code 0x%02x",
+ rsp->ccode);
+ }
+ return -1;
+ }
+
+ if (rsp->data_len >= 5) {
+ int index;
+
+ /* add support for more than one link per channel */
+ for(index=0;index<PICMG_AMC_MAX_LINK_PER_CHANNEL;index++){
+
+ if( rsp->data_len > (1+ (index*4))){
+ unsigned char type;
+ unsigned char ext;
+ unsigned char grouping;
+ unsigned char port;
+ unsigned char enabled;
+ d = (struct fru_picmgext_amc_link_info *)&(rsp->data[1 + (index*4)]);
+
+
+ /* Removed endianness check here, probably not required
+ as we dont use bitfields */
+ port = d->linkInfo[0] & 0x0F;
+ type = ((d->linkInfo[0] & 0xF0) >> 4 )|(d->linkInfo[1] & 0x0F );
+ ext = ((d->linkInfo[1] & 0xF0) >> 4 );
+ grouping = d->linkInfo[2];
+
+
+ enabled = rsp->data[4 + (index*4) ];
+
+ if
+ (
+ mode == PICMG_EKEY_MODE_PRINT_ALL
+ ||
+ mode == PICMG_EKEY_MODE_QUERY
+ ||
+ (
+ mode == PICMG_EKEY_MODE_PRINT_ENABLED
+ &&
+ enabled == 0x01
+ )
+ ||
+ (
+ mode == PICMG_EKEY_MODE_PRINT_DISABLED
+ &&
+ enabled == 0x00
+ )
+ )
+ {
+ if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){
+ printf(" Link device : AMC\n");
+ }else{
+ printf(" Link device : 0x%02x\n", device );
+ }
+
+ printf(" Link Grouping ID: 0x%02x\n", grouping);
+
+ if (type == 0 || type == 1 ||type == 0xff)
+ {
+ printf(" Link Type Extension: 0x%02x\n", ext);
+ printf(" Link Type: Reserved\n");
+ }
+ else if (type >= 0xf0 && type <= 0xfe)
+ {
+ printf(" Link Type Extension: 0x%02x\n", ext);
+ printf(" Link Type: OEM GUID Definition\n");
+ }
+ else
+ {
+ if (type <= FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE )
+ {
+ printf(" Link Type Extension: %s\n",
+ amc_link_type_ext_str[type][ext]);
+ printf(" Link Type: %s\n",
+ amc_link_type_str[type]);
+ }
+ else{
+ printf(" Link Type Extension: 0x%02x\n", ext);
+ printf(" Link Type: undefined\n");
+ }
+ }
+ printf(" Link Designator: \n");
+ printf(" Channel Number: 0x%02x\n", channel);
+ printf(" Port Flag: 0x%02x\n", port );
+ printf(" STATE: %s\n",
+ ( enabled == 0x01 )?"enabled":"disabled");
+ printf("\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ lprintf(LOG_NOTICE,"ipmi_picmg_amc_portstate_get"\
+ "Unexpected answer, can't print result");
+ }
+
+ return 0;
+}
+
+
+int
+ipmi_picmg_amc_portstate_set(struct ipmi_intf * intf, uint8_t channel,
+ int32_t port, uint8_t type, uint8_t typeext,
+ uint8_t group, uint8_t enable, int32_t device)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char msg_data[7];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_AMC_SET_PORT_STATE_CMD;
+ req.msg.data = msg_data;
+
+ msg_data[0] = 0x00; /* PICMG identifier*/
+ msg_data[1] = channel; /* channel id */
+ msg_data[2] = port & 0xF; /* port flags */
+ msg_data[2] |= (type & 0x0F)<<4; /* type */
+ msg_data[3] = (type & 0xF0)>>4; /* type */
+ msg_data[3] |= (typeext & 0x0F)<<4; /* extension */
+ msg_data[4] = (group & 0xFF); /* group */
+ msg_data[5] = (enable & 0x01); /* state */
+ req.msg.data_len = 6;
+
+ /* device id - only for carrier needed */
+ if (device >= 0) {
+ msg_data[6] = device;
+ req.msg.data_len = 7;
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Amc portstate set failed with CC code 0x%02x",
+ rsp->ccode);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+ipmi_picmg_get_led_properties(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_FRU_LED_PROPERTIES_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0) {
+ return (-1);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "LED get properties failed with CC code 0x%02x",
+ rsp->ccode);
+ return -1;
+ }
+
+ printf("General Status LED Properties: 0x%2x\n", rsp->data[1] );
+ printf("App. Specific LED Count: 0x%2x\n", rsp->data[2] );
+
+ return 0;
+}
+
+int
+ipmi_picmg_get_led_capabilities(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int i;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_LED_COLOR_CAPABILITIES_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0
+ || is_led_id(argv[1], &msg_data[2]) != 0) {
+ return (-1);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "LED get capabilities failed with CC code 0x%02x",
+ rsp->ccode);
+ return -1;
+ }
+
+ printf("LED Color Capabilities: ");
+ for ( i=0 ; i<8 ; i++ ) {
+ if ( rsp->data[1] & (0x01 << i) ) {
+ printf("%s, ", led_color_str[ i ]);
+ }
+ }
+ printf("\n");
+
+ printf("Default LED Color in\n");
+ printf(" LOCAL control: %s\n", led_color_str[ rsp->data[2] ] );
+ printf(" OVERRIDE state: %s\n", led_color_str[ rsp->data[3] ] );
+
+ return 0;
+}
+
+int
+ipmi_picmg_get_led_state(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_FRU_LED_STATE_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0
+ || is_led_id(argv[1], &msg_data[2]) != 0) {
+ return (-1);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "LED get state failed with CC code 0x%02x", rsp->ccode);
+ return -1;
+ }
+
+ printf("LED states: %x ", rsp->data[1] );
+ if (rsp->data[1] == 0x1)
+ printf("[LOCAL CONTROL]\n");
+ else if (rsp->data[1] == 0x2)
+ printf("[OVERRIDE]\n");
+ else if (rsp->data[1] == 0x4)
+ printf("[LAMPTEST]\n");
+ else
+ printf("\n");
+
+ printf(" Local Control function: %x ", rsp->data[2] );
+ if (rsp->data[2] == 0x0)
+ printf("[OFF]\n");
+ else if (rsp->data[2] == 0xff)
+ printf("[ON]\n");
+ else
+ printf("[BLINKING]\n");
+
+ printf(" Local Control On-Duration: %x\n", rsp->data[3] );
+ printf(" Local Control Color: %x [%s]\n", rsp->data[4], led_color_str[ rsp->data[4] ]);
+
+ /* override state or lamp test */
+ if (rsp->data[1] == 0x02) {
+ printf(" Override function: %x ", rsp->data[5] );
+ if (rsp->data[2] == 0x0)
+ printf("[OFF]\n");
+ else if (rsp->data[2] == 0xff)
+ printf("[ON]\n");
+ else
+ printf("[BLINKING]\n");
+
+ printf(" Override On-Duration: %x\n", rsp->data[6] );
+ printf(" Override Color: %x [%s]\n", rsp->data[7], led_color_str[ rsp->data[7] ]);
+
+ }else if (rsp->data[1] == 0x06) {
+ printf(" Override function: %x ", rsp->data[5] );
+ if (rsp->data[2] == 0x0)
+ printf("[OFF]\n");
+ else if (rsp->data[2] == 0xff)
+ printf("[ON]\n");
+ else
+ printf("[BLINKING]\n");
+ printf(" Override On-Duration: %x\n", rsp->data[6] );
+ printf(" Override Color: %x [%s]\n", rsp->data[7], led_color_str[ rsp->data[7] ]);
+ printf(" Lamp test duration: %x\n", rsp->data[8] );
+ }
+
+ return 0;
+}
+
+int
+ipmi_picmg_set_led_state(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_SET_FRU_LED_STATE_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 6;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0
+ || is_led_id(argv[1], &msg_data[2]) != 0
+ || is_led_function(argv[2], &msg_data[3]) != 0
+ || is_led_duration(argv[3], &msg_data[4]) != 0
+ || is_led_color(argv[4], &msg_data[5]) != 0) {
+ return (-1);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "LED set state failed with CC code 0x%02x", rsp->ccode);
+ return -1;
+ }
+
+
+ return 0;
+}
+
+int
+ipmi_picmg_get_power_level(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int i;
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_POWER_LEVEL_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0) {
+ return (-1);
+ }
+ /* PICMG Power Type - <0..3> */
+ if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 3) {
+ lprintf(LOG_ERR, "Given Power Type '%s' is invalid",
+ argv[1]);
+ return (-1);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Power level get failed with CC code 0x%02x", rsp->ccode);
+ return -1;
+ }
+
+ printf("Dynamic Power Configuration: %s\n", (rsp->data[1]&0x80)==0x80?"enabled":"disabled" );
+ printf("Actual Power Level: %i\n", (rsp->data[1] & 0xf));
+ printf("Delay to stable Power: %i\n", rsp->data[2]);
+ printf("Power Multiplier: %i\n", rsp->data[3]);
+
+
+ for ( i = 1; i+3 < rsp->data_len ; i++ ) {
+ printf(" Power Draw %i: %i\n", i, (rsp->data[i+3]) * rsp->data[3] / 10);
+ }
+ return 0;
+}
+
+int
+ipmi_picmg_set_power_level(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_SET_POWER_LEVEL_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0) {
+ return (-1);
+ }
+ /* PICMG Power Level - <0x00..0x14>, [0xFF] */
+ if (str2uchar(argv[1], &msg_data[2]) != 0
+ || (msg_data[2] > 0x14 && msg_data[2] != 0xFF)) {
+ lprintf(LOG_ERR,
+ "Given PICMG Power Level '%s' is invalid.",
+ argv[1]);
+ return (-1);
+ }
+ /* PICMG Present-to-desired - <0..1> */
+ if (str2uchar(argv[2], &msg_data[3]) != 0 || msg_data[3] > 1) {
+ lprintf(LOG_ERR,
+ "Given PICMG Present-to-desired '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Power level set failed with CC code 0x%02x", rsp->ccode);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ipmi_picmg_bused_resource(struct ipmi_intf * intf, t_picmg_bused_resource_mode mode)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+ memset(&req, 0, sizeof(req));
+
+ int status = 0;
+ switch ( mode ) {
+ case PICMG_BUSED_RESOURCE_SUMMARY:
+ {
+ t_picmg_busres_resource_id resource;
+ t_picmg_busres_board_cmd_types cmd =PICMG_BUSRES_BOARD_CMD_QUERY;
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_BUSED_RESOURCE_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+
+ /* IF BOARD
+ query for all resources
+ */
+ for( resource=PICMG_BUSRES_METAL_TEST_BUS_1;resource<=PICMG_BUSRES_SYNC_CLOCK_GROUP_3;resource+=(t_picmg_busres_resource_id)1 ) {
+ msg_data[0] = 0x00; /* PICMG identifier */
+ msg_data[1] = (unsigned char) cmd;
+ msg_data[2] = (unsigned char) resource;
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ printf("bused resource control: no response\n");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ printf("bused resource control: returned CC code 0x%02x\n", rsp->ccode);
+ return -1;
+ } else {
+ printf("Resource 0x%02x '%-26s' : 0x%02x [%s] \n" ,
+ resource, val2str(resource,picmg_busres_id_vals),
+ rsp->data[1], oemval2str(cmd,rsp->data[1],
+ picmg_busres_board_status_vals));
+ }
+ }
+ }
+ break;
+ default :
+ break;
+ }
+
+ return status;
+}
+
+int
+ipmi_picmg_fru_control(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_FRU_CONTROL_CMD;
+ req.msg.data = msg_data;
+ req.msg.data_len = 3;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_fru_id(argv[0], &msg_data[1]) != 0) {
+ return (-1);
+ }
+ /* FRU Control Option, valid range: <0..4> */
+ if (str2uchar(argv[1], &msg_data[2]) != 0 || msg_data[2] > 4) {
+ lprintf(LOG_ERR,
+ "Given FRU Control Option '%s' is invalid.",
+ argv[1]);
+ return (-1);
+ }
+
+ printf("FRU Device Id: %d FRU Control Option: %s\n", msg_data[1], \
+ val2str( msg_data[2], picmg_frucontrol_vals));
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "frucontrol failed with CC code 0x%02x", rsp->ccode);
+ return -1;
+ } else {
+ printf("frucontrol: ok\n");
+ }
+
+
+
+ return 0;
+}
+
+
+int
+ipmi_picmg_clk_get(struct ipmi_intf * intf, uint8_t clk_id, int8_t clk_res,
+ int mode)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char enabled;
+ unsigned char direction;
+
+ unsigned char msg_data[6];
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_AMC_GET_CLK_STATE_CMD;
+ req.msg.data = msg_data;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ msg_data[1] = clk_id;
+
+ if(clk_res == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){
+ req.msg.data_len = 2; /* for amc only channel */
+ }else{
+ req.msg.data_len = 3; /* for carrier channel and device */
+ msg_data[2] = clk_res;
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode && (mode == PICMG_EKEY_MODE_QUERY) ) {
+ lprintf(LOG_ERR, "Clk get failed with CC code 0x%02x", rsp->ccode);
+ return -1;
+ }
+
+ if (rsp->ccode == 0 ) {
+ enabled = (rsp->data[1]&0x8)!=0;
+ direction = (rsp->data[1]&0x4)!=0;
+
+ if
+ (
+ mode == PICMG_EKEY_MODE_QUERY
+ ||
+ mode == PICMG_EKEY_MODE_PRINT_ALL
+ ||
+ (
+ mode == PICMG_EKEY_MODE_PRINT_DISABLED
+ &&
+ enabled == 0
+ )
+ ||
+ (
+ mode == PICMG_EKEY_MODE_PRINT_ENABLED
+ &&
+ enabled == 1
+ )
+ ) {
+ if( PicmgCardType != PICMG_CARD_TYPE_AMC ) {
+ printf("CLK resource id : %3d [ %s ]\n", clk_res ,
+ oemval2str( ((clk_res>>6)&0x03), (clk_res&0x0F),
+ picmg_clk_resource_vals));
+ } else {
+ printf("CLK resource id : N/A [ AMC Module ]\n");
+ clk_res = 0x40; /* Set */
+ }
+ printf("CLK id : %3d [ %s ]\n", clk_id,
+ oemval2str( ((clk_res>>6)&0x03), clk_id ,
+ picmg_clk_id_vals));
+
+
+ printf("CLK setting : 0x%02x\n", rsp->data[1]);
+ printf(" - state: %s\n", (enabled)?"enabled":"disabled");
+ printf(" - direction: %s\n", (direction)?"Source":"Receiver");
+ printf(" - PLL ctrl: 0x%x\n", rsp->data[1]&0x3);
+
+ if(enabled){
+ unsigned long freq = 0;
+ freq = ( rsp->data[5] << 0
+ | rsp->data[6] << 8
+ | rsp->data[7] << 16
+ | rsp->data[8] << 24 );
+ printf(" - Index: %3d\n", rsp->data[2]);
+ printf(" - Family: %3d [ %s ] \n", rsp->data[3],
+ val2str( rsp->data[3], picmg_clk_family_vals));
+ printf(" - AccLVL: %3d [ %s ] \n", rsp->data[4],
+ oemval2str( rsp->data[3], rsp->data[4],
+ picmg_clk_accuracy_vals));
+
+ printf(" - Freq: %ld\n", freq);
+ }
+ }
+ }
+ return 0;
+}
+
+
+int
+ipmi_picmg_clk_set(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ unsigned char msg_data[11] = {0};
+ uint32_t freq = 0;
+
+ memset(&req, 0, sizeof(req));
+
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_AMC_SET_CLK_STATE_CMD;
+ req.msg.data = msg_data;
+
+ msg_data[0] = 0x00; /* PICMG identifier */
+ if (is_clk_id(argv[0], &msg_data[1]) != 0
+ || is_clk_index(argv[1], &msg_data[2]) != 0
+ || is_clk_setting(argv[2], &msg_data[3]) != 0
+ || is_clk_family(argv[3], &msg_data[4]) != 0
+ || is_clk_acc(argv[4], &msg_data[5]) != 0
+ || is_clk_freq(argv[5], &freq) != 0) {
+ return (-1);
+ }
+
+ msg_data[6] = (freq >> 0)& 0xFF; /* freq */
+ msg_data[7] = (freq >> 8)& 0xFF; /* freq */
+ msg_data[8] = (freq >>16)& 0xFF; /* freq */
+ msg_data[9] = (freq >>24)& 0xFF; /* freq */
+
+ req.msg.data_len = 10;
+ if( PicmgCardType == PICMG_CARD_TYPE_ATCA )
+ {
+ if( argc > 7)
+ {
+ req.msg.data_len = 11;
+ if (is_clk_resid(argv[6], &msg_data[10]) != 0) {
+ return (-1);
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Missing resource id for atca board.");
+ return -1;
+ }
+ }
+
+#if 1
+printf("## ID: %d\n", msg_data[1]);
+printf("## index: %d\n", msg_data[2]);
+printf("## setting: 0x%02x\n", msg_data[3]);
+printf("## family: %d\n", msg_data[4]);
+printf("## acc: %d\n", msg_data[5]);
+printf("## freq: %ld\n", freq );
+printf("## res: %d\n", msg_data[10]);
+#endif
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_ERR, "No valid response received.");
+ return -1;
+ }
+
+ if (rsp->ccode) {
+ lprintf(LOG_ERR, "Clk set failed with CC code 0x%02x", rsp->ccode);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+int
+ipmi_picmg_main (struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+ int showProperties = 0;
+
+ if (argc == 0 || (!strncmp(argv[0], "help", 4))) {
+ ipmi_picmg_help();
+ return 0;
+ }
+
+ /* Get PICMG properties is called to obtain version information */
+ if (argc !=0 && !strncmp(argv[0], "properties", 10)) {
+ showProperties =1;
+ }
+ rc = ipmi_picmg_properties(intf,showProperties);
+
+ /* address info command */
+ if (!strncmp(argv[0], "addrinfo", 8)) {
+ rc = ipmi_picmg_getaddr(intf, argc-1, &argv[1]);
+ }
+ else if (!strncmp(argv[0], "busres", 6)) {
+ if (argc > 1) {
+ if (!strncmp(argv[1], "summary", 7)) {
+ ipmi_picmg_bused_resource(intf, PICMG_BUSED_RESOURCE_SUMMARY );
+ }
+ } else {
+ lprintf(LOG_NOTICE, "usage: busres summary");
+ }
+ }
+ /* fru control command */
+ else if (!strncmp(argv[0], "frucontrol", 10)) {
+ if (argc > 2) {
+ rc = ipmi_picmg_fru_control(intf, argc-1, &(argv[1]));
+ }
+ else {
+ lprintf(LOG_NOTICE, "usage: frucontrol <FRU-ID> <OPTION>");
+ lprintf(LOG_NOTICE, " OPTION:");
+ lprintf(LOG_NOTICE, " 0 - Cold Reset");
+ lprintf(LOG_NOTICE, " 1 - Warm Reset");
+ lprintf(LOG_NOTICE, " 2 - Graceful Reboot");
+ lprintf(LOG_NOTICE, " 3 - Issue Diagnostic Interrupt");
+ lprintf(LOG_NOTICE, " 4 - Quiesce [AMC only]");
+ lprintf(LOG_NOTICE, " 5-255 - Reserved");
+
+ return -1;
+ }
+
+ }
+
+ /* fru activation command */
+ else if (!strncmp(argv[0], "activate", 8)) {
+ if (argc > 1) {
+ rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_ACTIVATE);
+ }
+ else {
+ lprintf(LOG_ERR, "Specify the FRU to activate.");
+ return -1;
+ }
+ }
+
+ /* fru deactivation command */
+ else if (!strncmp(argv[0], "deactivate", 10)) {
+ if (argc > 1) {
+ rc = ipmi_picmg_fru_activation(intf, argc-1, &(argv[1]), PICMG_FRU_DEACTIVATE);
+ }else {
+ lprintf(LOG_ERR, "Specify the FRU to deactivate.");
+ return -1;
+ }
+ }
+
+ /* activation policy command */
+ else if (!strncmp(argv[0], "policy", 6)) {
+ if (argc > 1) {
+ if (!strncmp(argv[1], "get", 3)) {
+ if (argc > 2) {
+ rc = ipmi_picmg_fru_activation_policy_get(intf, argc-1, &(argv[2]));
+ } else {
+ lprintf(LOG_NOTICE, "usage: get <fruid>");
+ }
+ } else if (!strncmp(argv[1], "set", 3)) {
+ if (argc > 4) {
+ rc = ipmi_picmg_fru_activation_policy_set(intf, argc-1, &(argv[2]));
+ } else {
+ lprintf(LOG_NOTICE, "usage: set <fruid> <lockmask> <lock>");
+ lprintf(LOG_NOTICE,
+ " lockmask: [1] affect the deactivation locked bit");
+ lprintf(LOG_NOTICE,
+ " [0] affect the activation locked bit");
+ lprintf(LOG_NOTICE,
+ " lock: [1] set/clear deactivation locked");
+ lprintf(LOG_NOTICE, " [0] set/clear locked");
+ }
+ }
+ else {
+ lprintf(LOG_ERR, "Specify FRU.");
+ return -1;
+ }
+ } else {
+ lprintf(LOG_ERR, "Wrong parameters.");
+ return -1;
+ }
+ }
+
+ /* portstate command */
+ else if (!strncmp(argv[0], "portstate", 9)) {
+
+ lprintf(LOG_DEBUG,"PICMG: portstate API");
+
+ if (argc > 1) {
+ if (!strncmp(argv[1], "get", 3)) {
+ int32_t iface;
+ uint8_t channel = 0;
+
+ lprintf(LOG_DEBUG,"PICMG: get");
+
+ if(!strncmp(argv[1], "getall", 6)) {
+ for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) {
+ for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) {
+ if(!(( iface == FRU_PICMGEXT_DESIGN_IF_FABRIC ) &&
+ ( channel > PICMG_EKEY_MAX_FABRIC_CHANNEL ) ))
+ {
+ rc = ipmi_picmg_portstate_get(intf,iface,channel,
+ PICMG_EKEY_MODE_PRINT_ALL);
+ }
+ }
+ }
+ }
+ else if(!strncmp(argv[1], "getgranted", 10)) {
+ for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) {
+ for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) {
+ rc = ipmi_picmg_portstate_get(intf,iface,channel,
+ PICMG_EKEY_MODE_PRINT_ENABLED);
+ }
+ }
+ }
+ else if(!strncmp(argv[1], "getdenied", 9)){
+ for(iface=0;iface<=PICMG_EKEY_MAX_INTERFACE;iface++) {
+ for(channel=1;channel<=PICMG_EKEY_MAX_CHANNEL;channel++) {
+ rc = ipmi_picmg_portstate_get(intf,iface,channel,
+ PICMG_EKEY_MODE_PRINT_DISABLED);
+ }
+ }
+ }
+ else if (argc > 3){
+ if (is_amc_intf(argv[2], &iface) != 0
+ || is_amc_channel(argv[3], &channel) != 0) {
+ return (-1);
+ }
+ lprintf(LOG_DEBUG,"PICMG: requesting interface %d",iface);
+ lprintf(LOG_DEBUG,"PICMG: requesting channel %d",channel);
+
+ rc = ipmi_picmg_portstate_get(intf,iface,channel,
+ PICMG_EKEY_MODE_QUERY );
+ }
+ else {
+ lprintf(LOG_NOTICE, "<intf> <chn>|getall|getgranted|getdenied");
+ }
+ }
+ else if (!strncmp(argv[1], "set", 3)) {
+ if (argc == 9) {
+ int32_t interface = 0;
+ int32_t port = 0;
+ uint8_t channel = 0;
+ uint8_t enable = 0;
+ uint8_t group = 0;
+ uint8_t type = 0;
+ uint8_t typeext = 0;
+ if (is_amc_intf(argv[2], &interface) != 0
+ || is_amc_channel(argv[3], &channel) != 0
+ || is_amc_port(argv[4], &port) != 0
+ || is_link_type(argv[5], &type) != 0
+ || is_link_type_ext(argv[6], &typeext) != 0
+ || is_link_group(argv[7], &group) != 0
+ || is_enable(argv[8], &enable) != 0) {
+ return (-1);
+ }
+
+ lprintf(LOG_DEBUG,"PICMG: interface %d",interface);
+ lprintf(LOG_DEBUG,"PICMG: channel %d",channel);
+ lprintf(LOG_DEBUG,"PICMG: port %d",port);
+ lprintf(LOG_DEBUG,"PICMG: type %d",type);
+ lprintf(LOG_DEBUG,"PICMG: typeext %d",typeext);
+ lprintf(LOG_DEBUG,"PICMG: group %d",group);
+ lprintf(LOG_DEBUG,"PICMG: enable %d",enable);
+
+ rc = ipmi_picmg_portstate_set(intf, interface,
+ channel, port, type, typeext ,group ,enable);
+ }
+ else {
+ lprintf(LOG_NOTICE,
+ "<intf> <chn> <port> <type> <ext> <group> <1|0>");
+ return -1;
+ }
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE, "<set>|<getall>|<getgranted>|<getdenied>");
+ return -1;
+ }
+ }
+ /* amc portstate command */
+ else if (!strncmp(argv[0], "amcportstate", 12)) {
+
+ lprintf(LOG_DEBUG,"PICMG: amcportstate API");
+
+ if (argc > 1) {
+ if (!strncmp(argv[1], "get", 3)){
+ int32_t device;
+ uint8_t channel;
+
+ lprintf(LOG_DEBUG,"PICMG: get");
+
+ if(!strncmp(argv[1], "getall", 6)){
+ int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE;
+ if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){
+ maxDevice = 0;
+ }
+ for(device=0;device<=maxDevice;device++){
+ for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){
+ rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
+ PICMG_EKEY_MODE_PRINT_ALL);
+ }
+ }
+ }
+ else if(!strncmp(argv[1], "getgranted", 10)){
+ int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE;
+ if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){
+ maxDevice = 0;
+ }
+ for(device=0;device<=maxDevice;device++){
+ for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){
+ rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
+ PICMG_EKEY_MODE_PRINT_ENABLED);
+ }
+ }
+ }
+ else if(!strncmp(argv[1], "getdenied", 9)){
+ int maxDevice = PICMG_EKEY_AMC_MAX_DEVICE;
+ if( PicmgCardType != PICMG_CARD_TYPE_ATCA ){
+ maxDevice = 0;
+ }
+ for(device=0;device<=maxDevice;device++){
+ for(channel=0;channel<=PICMG_EKEY_AMC_MAX_CHANNEL;channel++){
+ rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
+ PICMG_EKEY_MODE_PRINT_DISABLED);
+ }
+ }
+ }
+ else if (argc > 2){
+ if (is_amc_channel(argv[2], &channel) != 0) {
+ return (-1);
+ }
+ if (argc > 3){
+ if (is_amc_dev(argv[3], &device) != 0) {
+ return (-1);
+ }
+ }else{
+ device = -1;
+ }
+ lprintf(LOG_DEBUG,"PICMG: requesting device %d",device);
+ lprintf(LOG_DEBUG,"PICMG: requesting channel %d",channel);
+
+ rc = ipmi_picmg_amc_portstate_get(intf,device,channel,
+ PICMG_EKEY_MODE_QUERY );
+ }
+ else {
+ lprintf(LOG_NOTICE, "<chn> <device>|getall|getgranted|getdenied");
+ }
+ }
+ else if (!strncmp(argv[1], "set", 3)) {
+ if (argc > 7) {
+ int32_t device = -1;
+ int32_t port = 0;
+ uint8_t channel = 0;
+ uint8_t enable = 0;
+ uint8_t group = 0;
+ uint8_t type = 0;
+ uint8_t typeext = 0;
+ if (is_amc_channel(argv[2], &channel) != 0
+ || is_amc_port(argv[3], &port) != 0
+ || is_link_type(argv[4], &type) !=0
+ || is_link_type_ext(argv[5], &typeext) != 0
+ || is_link_group(argv[6], &group) != 0
+ || is_enable(argv[7], &enable) != 0) {
+ return (-1);
+ }
+ if(argc > 8){
+ if (is_amc_dev(argv[8], &device) != 0) {
+ return (-1);
+ }
+ }
+
+ lprintf(LOG_DEBUG,"PICMG: channel %d",channel);
+ lprintf(LOG_DEBUG,"PICMG: portflags %d",port);
+ lprintf(LOG_DEBUG,"PICMG: type %d",type);
+ lprintf(LOG_DEBUG,"PICMG: typeext %d",typeext);
+ lprintf(LOG_DEBUG,"PICMG: group %d",group);
+ lprintf(LOG_DEBUG,"PICMG: enable %d",enable);
+ lprintf(LOG_DEBUG,"PICMG: device %d",device);
+
+ rc = ipmi_picmg_amc_portstate_set(intf, channel, port, type,
+ typeext, group, enable, device);
+ }
+ else {
+ lprintf(LOG_NOTICE,
+ "<chn> <portflags> <type> <ext> <group> <1|0> [<device>]");
+ return -1;
+ }
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>");
+ return -1;
+ }
+ }
+ /* ATCA led commands */
+ else if (!strncmp(argv[0], "led", 3)) {
+ if (argc > 1) {
+ if (!strncmp(argv[1], "prop", 4)) {
+ if (argc > 2) {
+ rc = ipmi_picmg_get_led_properties(intf, argc-1, &(argv[2]));
+ }
+ else {
+ lprintf(LOG_NOTICE, "led prop <FRU-ID>");
+ }
+ }
+ else if (!strncmp(argv[1], "cap", 3)) {
+ if (argc > 3) {
+ rc = ipmi_picmg_get_led_capabilities(intf, argc-1, &(argv[2]));
+ }
+ else {
+ lprintf(LOG_NOTICE, "led cap <FRU-ID> <LED-ID>");
+ }
+ }
+ else if (!strncmp(argv[1], "get", 3)) {
+ if (argc > 3) {
+ rc = ipmi_picmg_get_led_state(intf, argc-1, &(argv[2]));
+ }
+ else {
+ lprintf(LOG_NOTICE, "led get <FRU-ID> <LED-ID>");
+ }
+ }
+ else if (!strncmp(argv[1], "set", 3)) {
+ if (argc > 6) {
+ rc = ipmi_picmg_set_led_state(intf, argc-1, &(argv[2]));
+ }
+ else {
+ lprintf(LOG_NOTICE,
+ "led set <FRU-ID> <LED-ID> <function> <duration> <color>");
+ lprintf(LOG_NOTICE, " <FRU-ID>");
+ lprintf(LOG_NOTICE, " <LED-ID> 0: Blue LED");
+ lprintf(LOG_NOTICE, " 1: LED 1");
+ lprintf(LOG_NOTICE, " 2: LED 2");
+ lprintf(LOG_NOTICE, " 3: LED 3");
+ lprintf(LOG_NOTICE, " 0x04-0xFE: OEM defined");
+ lprintf(LOG_NOTICE,
+ " 0xFF: All LEDs under management control");
+ lprintf(LOG_NOTICE, " <function> 0: LED OFF override");
+ lprintf(LOG_NOTICE,
+ " 1 - 250: LED blinking override (off duration)");
+ lprintf(LOG_NOTICE, " 251: LED Lamp Test");
+ lprintf(LOG_NOTICE,
+ " 252: LED restore to local control");
+ lprintf(LOG_NOTICE, " 255: LED ON override");
+ lprintf(LOG_NOTICE,
+ " <duration> 1 - 127: LED Lamp Test / on duration");
+ lprintf(LOG_NOTICE, " <color> 0: reserved");
+ lprintf(LOG_NOTICE, " 1: BLUE");
+ lprintf(LOG_NOTICE, " 2: RED");
+ lprintf(LOG_NOTICE, " 3: GREEN");
+ lprintf(LOG_NOTICE, " 4: AMBER");
+ lprintf(LOG_NOTICE, " 5: ORANGE");
+ lprintf(LOG_NOTICE, " 6: WHITE");
+ lprintf(LOG_NOTICE, " 7: reserved");
+ lprintf(LOG_NOTICE, " 0xE: do not change");
+ lprintf(LOG_NOTICE, " 0xF: use default color");
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE, "prop | cap | get | set");
+ }
+ }
+ }
+ /* power commands */
+ else if (!strncmp(argv[0], "power", 5)) {
+ if (argc > 1) {
+ if (!strncmp(argv[1], "get", 3)) {
+ if (argc > 3) {
+ rc = ipmi_picmg_get_power_level(intf, argc-1, &(argv[2]));
+ }
+ else {
+ lprintf(LOG_NOTICE, "power get <FRU-ID> <type>");
+ lprintf(LOG_NOTICE, " <type> 0 : steady state power draw levels");
+ lprintf(LOG_NOTICE,
+ " 1 : desired steady state draw levels");
+ lprintf(LOG_NOTICE, " 2 : early power draw levels");
+ lprintf(LOG_NOTICE, " 3 : desired early levels");
+
+ return -1;
+ }
+ }
+ else if (!strncmp(argv[1], "set", 3)) {
+ if (argc > 4) {
+ rc = ipmi_picmg_set_power_level(intf, argc-1, &(argv[2]));
+ }
+ else {
+ lprintf(LOG_NOTICE, "power set <FRU-ID> <level> <present-desired>");
+ lprintf(LOG_NOTICE, " <level> 0 : Power Off");
+ lprintf(LOG_NOTICE, " 0x1-0x14 : Power level");
+ lprintf(LOG_NOTICE, " 0xFF : do not change");
+ lprintf(LOG_NOTICE,
+ "\n <present-desired> 0: do not change present levels");
+ lprintf(LOG_NOTICE,
+ " 1: copy desired to present level");
+
+ return -1;
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE, "<set>|<get>");
+ return -1;
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE, "<set>|<get>");
+ return -1;
+ }
+ }/* clk commands*/
+ else if (!strncmp(argv[0], "clk", 3)) {
+ if (argc > 1) {
+ if (!strncmp(argv[1], "get", 3)) {
+ int8_t clk_res = -1;
+ uint8_t clk_id;
+ uint8_t max_res = 15;
+
+ if( PicmgCardType == PICMG_CARD_TYPE_AMC ) {
+ max_res = 0;
+ }
+
+ if(!strncmp(argv[1], "getall", 6)) {
+ if( verbose ) { printf("Getting all clock state\n") ;}
+ for(clk_res=0;clk_res<=max_res;clk_res++) {
+ for(clk_id=0;clk_id<=15;clk_id++) {
+ rc = ipmi_picmg_clk_get(intf,clk_id,clk_res,
+ PICMG_EKEY_MODE_PRINT_ALL);
+ }
+ }
+ }
+ else if(!strncmp(argv[1], "getdenied", 6)) {
+ if( verbose ) { printf("Getting disabled clocks\n") ;}
+ for(clk_res=0;clk_res<=max_res;clk_res++) {
+ for(clk_id=0;clk_id<=15;clk_id++) {
+ rc = ipmi_picmg_clk_get(intf,clk_id,clk_res,
+ PICMG_EKEY_MODE_PRINT_DISABLED);
+ }
+ }
+ }
+ else if(!strncmp(argv[1], "getgranted", 6)) {
+ if( verbose ) { printf("Getting enabled clocks\n") ;}
+ for(clk_res=0;clk_res<=max_res;clk_res++) {
+ for(clk_id=0;clk_id<=15;clk_id++) {
+ rc = ipmi_picmg_clk_get(intf,clk_id,clk_res,
+ PICMG_EKEY_MODE_PRINT_ENABLED);
+ }
+ }
+ }
+ else if (argc > 2) {
+ if (is_clk_id(argv[2], &clk_id) != 0) {
+ return (-1);
+ }
+ if (argc > 3) {
+ if (is_clk_resid(argv[3], &clk_res) != 0) {
+ return (-1);
+ }
+ }
+
+ rc = ipmi_picmg_clk_get(intf, clk_id, clk_res,
+ PICMG_EKEY_MODE_QUERY );
+ }
+ else {
+ lprintf(LOG_NOTICE, "clk get");
+ lprintf(LOG_NOTICE,
+ "<CLK-ID> [<DEV-ID>] |getall|getgranted|getdenied");
+ return -1;
+ }
+ }
+ else if (!strncmp(argv[1], "set", 3)) {
+ if (argc > 7) {
+ rc = ipmi_picmg_clk_set(intf, argc-1, &(argv[2]));
+ }
+ else {
+ lprintf(LOG_NOTICE,
+ "clk set <CLK-ID> <index> <setting> <family> <acc-lvl> <freq> [<DEV-ID>]");
+
+ return -1;
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>");
+ return -1;
+ }
+ }
+ else {
+ lprintf(LOG_NOTICE, "<set>|<get>|<getall>|<getgranted>|<getdenied>");
+ return -1;
+ }
+ }
+
+ else if(showProperties == 0 ){
+
+ ipmi_picmg_help();
+ return -1;
+ }
+
+ return rc;
+}
+
+uint8_t
+ipmi_picmg_ipmb_address(struct ipmi_intf *intf) {
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ char msg_data;
+
+ if (!intf->picmg_avail) {
+ return 0;
+ }
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD;
+ msg_data = 0x00;
+ req.msg.data = &msg_data;
+ req.msg.data_len = 1;
+ msg_data = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp && !rsp->ccode) {
+ return rsp->data[2];
+ }
+ if (rsp) {
+ lprintf(LOG_DEBUG, "Get Address Info failed: %#x %s",
+ rsp->ccode, val2str(rsp->ccode, completion_code_vals));
+ } else {
+ lprintf(LOG_DEBUG, "Get Address Info failed: No Response");
+ }
+ return 0;
+}
+
+uint8_t
+picmg_discover(struct ipmi_intf *intf) {
+ /* Check if PICMG extension is available to use the function
+ * GetDeviceLocator to retreive i2c address PICMG hack to set
+ * right IPMB address, If extension is not supported, should
+ * not give any problems
+ * PICMG Extension Version 2.0 (PICMG 3.0 Revision 1.0 ATCA) to
+ * PICMG Extension Version 2.3 (PICMG 3.0 Revision 3.0 ATCA)
+ * PICMG Extension Version 4.1 (PICMG 3.0 Revision 3.0 AMC)
+ */
+
+ /* First, check if PICMG extension is available and supported */
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ char msg_data;
+
+ if (intf->picmg_avail == 0) {
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD;
+ msg_data = 0x00;
+ req.msg.data = &msg_data;
+ req.msg.data_len = 1;
+ msg_data = 0;
+
+ lprintf(LOG_INFO, "Running Get PICMG Properties my_addr %#x, transit %#x, target %#x",
+ intf->my_addr, intf->transit_addr, intf->target_addr);
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp && !rsp->ccode) {
+ if ( (rsp->data[0] == 0) &&
+ ((rsp->data[1] & 0x0F) == PICMG_ATCA_MAJOR_VERSION
+ || (rsp->data[1] & 0x0F) == PICMG_AMC_MAJOR_VERSION) ) {
+ intf->picmg_avail = 1;
+ lprintf(LOG_INFO, "Discovered PICMG Extension %d.%d",
+ (rsp->data[1] & 0x0f), (rsp->data[1] >> 4));
+ }
+ } else {
+ if (rsp == NULL) {
+ lprintf(LOG_INFO,"No Response from Get PICMG Properties");
+ } else {
+ lprintf(LOG_INFO,"Error Response %#x from Get PICMG Properities", rsp->ccode);
+ }
+ }
+ }
+ if (intf->picmg_avail == 0) {
+ lprintf(LOG_INFO, "No PICMG Extenstion discovered");
+ }
+ return intf->picmg_avail;
+}
diff --git a/lib/ipmi_raw.c b/lib/ipmi_raw.c
new file mode 100644
index 0000000..6959c1f
--- /dev/null
+++ b/lib/ipmi_raw.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_raw.h>
+#include <ipmitool/ipmi_fru.h>
+#include <ipmitool/ipmi_strings.h>
+
+#define IPMI_I2C_MASTER_MAX_SIZE 0x40 /* 64 bytes */
+
+static int is_valid_param(const char *input_param, uint8_t *uchr_ptr,
+ const char *label);
+
+/* ipmi_master_write_read - Perform I2C write/read transactions
+ *
+ * This function performs an I2C master write-read function through
+ * IPMI interface. It has a maximum transfer size of 32 bytes.
+ *
+ * @intf: ipmi interface
+ * @bus: channel number, i2c bus id and type
+ * @addr: i2c slave address
+ * @wdata: data to write
+ * @wsize: length of data to write (max 64 bytes)
+ * @rsize: length of data to read (max 64 bytes)
+ *
+ * Returns pointer to IPMI Response
+ */
+struct ipmi_rs *
+ipmi_master_write_read(struct ipmi_intf * intf, uint8_t bus, uint8_t addr,
+ uint8_t * wdata, uint8_t wsize, uint8_t rsize)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ uint8_t rqdata[IPMI_I2C_MASTER_MAX_SIZE + 3];
+
+ if (rsize > IPMI_I2C_MASTER_MAX_SIZE) {
+ lprintf(LOG_ERR, "Master Write-Read: Too many bytes (%d) to read", rsize);
+ return NULL;
+ }
+ if (wsize > IPMI_I2C_MASTER_MAX_SIZE) {
+ lprintf(LOG_ERR, "Master Write-Read: Too many bytes (%d) to write", wsize);
+ return NULL;
+ }
+
+ memset(&req, 0, sizeof(struct ipmi_rq));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = 0x52; /* master write-read */
+ req.msg.data = rqdata;
+ req.msg.data_len = 3;
+
+ memset(rqdata, 0, IPMI_I2C_MASTER_MAX_SIZE + 3);
+ rqdata[0] = bus; /* channel number, bus id, bus type */
+ rqdata[1] = addr; /* slave address */
+ rqdata[2] = rsize; /* number of bytes to read */
+
+ if (wsize > 0) {
+ /* copy in data to write */
+ memcpy(rqdata+3, wdata, wsize);
+ req.msg.data_len += wsize;
+ lprintf(LOG_DEBUG, "Writing %d bytes to i2cdev %02Xh", wsize, addr);
+ }
+
+ if (rsize > 0) {
+ lprintf(LOG_DEBUG, "Reading %d bytes from i2cdev %02Xh", rsize, addr);
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "I2C Master Write-Read command failed");
+ return NULL;
+ }
+ else if (rsp->ccode > 0) {
+ switch (rsp->ccode) {
+ case 0x81:
+ lprintf(LOG_ERR, "I2C Master Write-Read command failed: Lost Arbitration");
+ break;
+ case 0x82:
+ lprintf(LOG_ERR, "I2C Master Write-Read command failed: Bus Error");
+ break;
+ case 0x83:
+ lprintf(LOG_ERR, "I2C Master Write-Read command failed: NAK on Write");
+ break;
+ case 0x84:
+ lprintf(LOG_ERR, "I2C Master Write-Read command failed: Truncated Read");
+ break;
+ default:
+ lprintf(LOG_ERR, "I2C Master Write-Read command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ break;
+ }
+ return NULL;
+ }
+
+ return rsp;
+}
+
+#define RAW_SPD_SIZE 256
+
+int
+ipmi_rawspd_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs *rsp;
+ uint8_t msize = IPMI_I2C_MASTER_MAX_SIZE; /* allow to override default */
+ uint8_t channel = 0;
+ uint8_t i2cbus = 0;
+ uint8_t i2caddr = 0;
+ uint8_t spd_data[RAW_SPD_SIZE];
+ int i;
+
+ memset(spd_data, 0, RAW_SPD_SIZE);
+
+ if (argc < 2 || strncmp(argv[0], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "usage: spd <i2cbus> <i2caddr> [channel] [maxread]");
+ return 0;
+ }
+
+ if (is_valid_param(argv[0], &i2cbus, "i2cbus") != 0)
+ return (-1);
+
+ if (is_valid_param(argv[1], &i2caddr, "i2caddr") != 0)
+ return (-1);
+
+ if (argc >= 3) {
+ if (is_valid_param(argv[2], &channel, "channel") != 0)
+ return (-1);
+ }
+
+ if (argc >= 4) {
+ if (is_valid_param(argv[3], &msize, "maxread") != 0)
+ return (-1);
+ }
+
+ i2cbus = ((channel & 0xF) << 4) | ((i2cbus & 7) << 1) | 1;
+
+ for (i = 0; i < RAW_SPD_SIZE; i+= msize) {
+ rsp = ipmi_master_write_read(intf, i2cbus, i2caddr,
+ (uint8_t *)&i, 1, msize );
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
+ return -1;
+ }
+
+ memcpy(spd_data+i, rsp->data, msize);
+ }
+
+ ipmi_spd_print(spd_data, i);
+ return 0;
+}
+
+static void rawi2c_usage(void)
+{
+ lprintf(LOG_NOTICE, "usage: i2c [bus=public|# [chan=#] <i2caddr> <read bytes> [write data]");
+ lprintf(LOG_NOTICE, " bus=public is default");
+ lprintf(LOG_NOTICE, " chan=0 is default, bus= must be specified to use chan=");
+}
+
+int
+ipmi_rawi2c_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ uint8_t wdata[IPMI_I2C_MASTER_MAX_SIZE];
+ uint8_t i2caddr = 0;
+ uint8_t rsize = 0;
+ uint8_t wsize = 0;
+ unsigned int rbus = 0;
+ uint8_t bus = 0;
+ int i = 0;
+
+ /* handle bus= argument */
+ if (argc > 2 && strncmp(argv[0], "bus=", 4) == 0) {
+ i = 1;
+ if (strncmp(argv[0], "bus=public", 10) == 0)
+ bus = 0;
+ else if (sscanf(argv[0], "bus=%u", &rbus) == 1)
+ bus = ((rbus & 7) << 1) | 1;
+ else
+ bus = 0;
+
+ /* handle channel= argument
+ * the bus= argument must be supplied first on command line */
+ if (argc > 3 && strncmp(argv[1], "chan=", 5) == 0) {
+ i = 2;
+ if (sscanf(argv[1], "chan=%u", &rbus) == 1)
+ bus |= rbus << 4;
+ }
+ }
+
+ if ((argc-i) < 2 || strncmp(argv[0], "help", 4) == 0) {
+ rawi2c_usage();
+ return 0;
+ }
+ else if (argc-i-2 > IPMI_I2C_MASTER_MAX_SIZE) {
+ lprintf(LOG_ERR, "Raw command input limit (%d bytes) exceeded",
+ IPMI_I2C_MASTER_MAX_SIZE);
+ return -1;
+ }
+
+ if (is_valid_param(argv[i++], &i2caddr, "i2caddr") != 0)
+ return (-1);
+
+ if (is_valid_param(argv[i++], &rsize, "read size") != 0)
+ return (-1);
+
+ if (i2caddr == 0) {
+ lprintf(LOG_ERR, "Invalid I2C address 0");
+ rawi2c_usage();
+ return -1;
+ }
+
+ memset(wdata, 0, IPMI_I2C_MASTER_MAX_SIZE);
+ for (; i < argc; i++) {
+ uint8_t val = 0;
+
+ if (is_valid_param(argv[i], &val, "parameter") != 0)
+ return (-1);
+
+ wdata[wsize] = val;
+ wsize++;
+ }
+
+ lprintf(LOG_INFO, "RAW I2C REQ (i2caddr=%x readbytes=%d writebytes=%d)",
+ i2caddr, rsize, wsize);
+ printbuf(wdata, wsize, "WRITE DATA");
+
+ rsp = ipmi_master_write_read(intf, bus, i2caddr, wdata, wsize, rsize);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to perform I2C Master Write-Read");
+ return -1;
+ }
+
+ if (wsize > 0) {
+ if (verbose || rsize == 0)
+ printf("Wrote %d bytes to I2C device %02Xh\n", wsize, i2caddr);
+ }
+
+ if (rsize > 0) {
+ if (verbose || wsize == 0)
+ printf("Read %d bytes from I2C device %02Xh\n", rsp->data_len, i2caddr);
+
+ if (rsp->data_len < rsize)
+ return -1;
+
+ /* print the raw response buffer */
+ for (i=0; i<rsp->data_len; i++) {
+ if (((i%16) == 0) && (i != 0))
+ printf("\n");
+ printf(" %2.2x", rsp->data[i]);
+ }
+ printf("\n");
+
+ if (rsp->data_len <= 4) {
+ uint32_t bit;
+ int j;
+ for (i = 0; i < rsp->data_len; i++) {
+ for (j = 1, bit = 0x80; bit > 0; bit /= 2, j++) {
+ printf("%s", (rsp->data[i] & bit) ? "1" : "0");
+ }
+ printf(" ");
+ }
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
+/* ipmi_raw_help() - print 'raw' help text
+ *
+ * returns void
+ */
+void
+ipmi_raw_help()
+{
+ lprintf(LOG_NOTICE, "RAW Commands: raw <netfn> <cmd> [data]");
+ print_valstr(ipmi_netfn_vals, "Network Function Codes", LOG_NOTICE);
+ lprintf(LOG_NOTICE, "(can also use raw hex values)");
+} /* ipmi_raw_help() */
+
+int
+ipmi_raw_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t netfn, cmd, lun;
+ uint16_t netfn_tmp = 0;
+ int i;
+ uint8_t data[256];
+
+ if (argc == 1 && strncmp(argv[0], "help", 4) == 0) {
+ ipmi_raw_help();
+ return 0;
+ }
+ else if (argc < 2) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ ipmi_raw_help();
+ return (-1);
+ }
+ else if (argc > sizeof(data))
+ {
+ lprintf(LOG_NOTICE, "Raw command input limit (256 bytes) exceeded");
+ return -1;
+ }
+
+ ipmi_intf_session_set_timeout(intf, 15);
+ ipmi_intf_session_set_retry(intf, 1);
+
+ lun = intf->target_lun;
+ netfn_tmp = str2val(argv[0], ipmi_netfn_vals);
+ if (netfn_tmp == 0xff) {
+ if (is_valid_param(argv[0], &netfn, "netfn") != 0)
+ return (-1);
+ } else {
+ if (netfn_tmp >= UINT8_MAX) {
+ lprintf(LOG_ERR, "Given netfn \"%s\" is out of range.", argv[0]);
+ return (-1);
+ }
+ netfn = netfn_tmp;
+ }
+
+ if (is_valid_param(argv[1], &cmd, "command") != 0)
+ return (-1);
+
+ memset(data, 0, sizeof(data));
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = netfn;
+ req.msg.lun = lun;
+ req.msg.cmd = cmd;
+ req.msg.data = data;
+
+ for (i=2; i<argc; i++) {
+ uint8_t val = 0;
+
+ if (is_valid_param(argv[i], &val, "data") != 0)
+ return (-1);
+
+ req.msg.data[i-2] = val;
+ req.msg.data_len++;
+ }
+
+ lprintf(LOG_INFO,
+ "RAW REQ (channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x data_len=%d)",
+ intf->target_channel & 0x0f, req.msg.netfn,req.msg.lun ,
+ req.msg.cmd, req.msg.data_len);
+
+ printbuf(req.msg.data, req.msg.data_len, "RAW REQUEST");
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to send RAW command "
+ "(channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x)",
+ intf->target_channel & 0x0f, req.msg.netfn, req.msg.lun, req.msg.cmd);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Unable to send RAW command "
+ "(channel=0x%x netfn=0x%x lun=0x%x cmd=0x%x rsp=0x%x): %s",
+ intf->target_channel & 0x0f, req.msg.netfn, req.msg.lun, req.msg.cmd, rsp->ccode,
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ lprintf(LOG_INFO, "RAW RSP (%d bytes)", rsp->data_len);
+
+ /* print the raw response buffer */
+ for (i=0; i<rsp->data_len; i++) {
+ if (((i%16) == 0) && (i != 0))
+ printf("\n");
+ printf(" %2.2x", rsp->data[i]);
+ }
+ printf("\n");
+
+ return 0;
+}
+
+/* is_valid_param -
+ *
+ * @input_param: string to convert from
+ * @uchr_ptr: pointer where to store converted value
+ * @label: string used in error message
+ *
+ * returns 0 if parameter is valid
+ * returns (-1) if parameter is invalid/on error
+ */
+int
+is_valid_param(const char *input_param, uint8_t *uchr_ptr, const char *label) {
+ if (input_param == NULL || label == NULL) {
+ lprintf(LOG_ERROR, "ERROR: NULL pointer passed.");
+ return (-1);
+ }
+ if (str2uchar(input_param, uchr_ptr) == 0)
+ return 0;
+
+ lprintf(LOG_ERR, "Given %s \"%s\" is invalid.", label, input_param);
+ return (-1);
+}
diff --git a/lib/ipmi_sdr.c b/lib/ipmi_sdr.c
new file mode 100644
index 0000000..fa7b082
--- /dev/null
+++ b/lib/ipmi_sdr.c
@@ -0,0 +1,4835 @@
+/*
+ * Copyright (c) 2012 Hewlett-Packard Development Company, L.P.
+ *
+ * Based on code from
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_sdradd.h>
+#include <ipmitool/ipmi_sensor.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_entity.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/ipmi_strings.h>
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+extern int verbose;
+static int use_built_in; /* Uses DeviceSDRs instead of SDRR */
+static int sdr_max_read_len = 0;
+static int sdr_extended = 0;
+static long sdriana = 0;
+
+static struct sdr_record_list *sdr_list_head = NULL;
+static struct sdr_record_list *sdr_list_tail = NULL;
+static struct ipmi_sdr_iterator *sdr_list_itr = NULL;
+
+void printf_sdr_usage();
+
+/* ipmi_sdr_get_unit_string - return units for base/modifier
+ *
+ * @pct: units are a percentage
+ * @type: unit type
+ * @base: base
+ * @modifier: modifier
+ *
+ * returns pointer to static string
+ */
+const char *
+ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifier)
+{
+ static char unitstr[16];
+ /*
+ * By default, if units are supposed to be percent, we will pre-pend
+ * the percent string to the textual representation of the units.
+ */
+ char *pctstr = pct ? "% " : "";
+ memset(unitstr, 0, sizeof (unitstr));
+ switch (type) {
+ case 2:
+ snprintf(unitstr, sizeof (unitstr), "%s%s * %s",
+ pctstr, unit_desc[base], unit_desc[modifier]);
+ break;
+ case 1:
+ snprintf(unitstr, sizeof (unitstr), "%s%s/%s",
+ pctstr, unit_desc[base], unit_desc[modifier]);
+ break;
+ case 0:
+ default:
+ /*
+ * Display the text "percent" only when the Base unit is
+ * "unspecified" and the caller specified to print percent.
+ */
+ if (base == 0 && pct) {
+ snprintf(unitstr, sizeof(unitstr), "percent");
+ } else {
+ snprintf(unitstr, sizeof (unitstr), "%s%s",
+ pctstr, unit_desc[base]);
+ }
+ break;
+ }
+ return unitstr;
+}
+
+/* sdr_sensor_has_analog_reading - Determine if sensor has an analog reading
+ *
+ */
+static int
+sdr_sensor_has_analog_reading(struct ipmi_intf *intf,
+ struct sensor_reading *sr)
+{
+ /* Compact sensors can't return analog values so we false */
+ if (!sr->full) {
+ return 0;
+ }
+ /*
+ * Per the IPMI Specification:
+ * Only Full Threshold sensors are identified as providing
+ * analog readings.
+ *
+ * But... HP didn't interpret this as meaning that "Only Threshold
+ * Sensors" can provide analog readings. So, HP packed analog
+ * readings into some of their non-Threshold Sensor. There is
+ * nothing that explictly prohibits this in the spec, so if
+ * an Analog reading is available in a Non-Threshod sensor and
+ * there are units specified for identifying the reading then
+ * we do an analog conversion even though the sensor is
+ * non-Threshold. To be safe, we provide this extension for
+ * HP.
+ *
+ */
+ if ( UNITS_ARE_DISCRETE(&sr->full->cmn) ) {
+ return 0;/* Sensor specified as not having Analog Units */
+ }
+ if ( !IS_THRESHOLD_SENSOR(&sr->full->cmn) ) {
+ /* Non-Threshold Sensors are not defined as having analog */
+ /* But.. We have one with defined with Analog Units */
+ if ( (sr->full->cmn.unit.pct | sr->full->cmn.unit.modifier |
+ sr->full->cmn.unit.type.base |
+ sr->full->cmn.unit.type.modifier)) {
+ /* And it does have the necessary units specs */
+ if ( !(intf->manufacturer_id == IPMI_OEM_HP) ) {
+ /* But to be safe we only do this for HP */
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ /*
+ * If sensor has linearization, then we should be able to update the
+ * reading factors and if we cannot fail the conversion.
+ */
+ if (sr->full->linearization >= SDR_SENSOR_L_NONLINEAR &&
+ sr->full->linearization <= 0x7F) {
+ if (ipmi_sensor_get_sensor_reading_factors(intf, sr->full, sr->s_reading) < 0){
+ sr->s_reading_valid = 0;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* sdr_convert_sensor_reading - convert raw sensor reading
+ *
+ * @sensor: sensor record
+ * @val: raw sensor reading
+ *
+ * returns floating-point sensor reading
+ */
+double
+sdr_convert_sensor_reading(struct sdr_record_full_sensor *sensor, uint8_t val)
+{
+ int m, b, k1, k2;
+ double result;
+
+ m = __TO_M(sensor->mtol);
+ b = __TO_B(sensor->bacc);
+ k1 = __TO_B_EXP(sensor->bacc);
+ k2 = __TO_R_EXP(sensor->bacc);
+
+ switch (sensor->cmn.unit.analog) {
+ case 0:
+ result = (double) (((m * val) +
+ (b * pow(10, k1))) * pow(10, k2));
+ break;
+ case 1:
+ if (val & 0x80)
+ val++;
+ /* Deliberately fall through to case 2. */
+ case 2:
+ result = (double) (((m * (int8_t) val) +
+ (b * pow(10, k1))) * pow(10, k2));
+ break;
+ default:
+ /* Oops! This isn't an analog sensor. */
+ return 0.0;
+ }
+
+ switch (sensor->linearization & 0x7f) {
+ case SDR_SENSOR_L_LN:
+ result = log(result);
+ break;
+ case SDR_SENSOR_L_LOG10:
+ result = log10(result);
+ break;
+ case SDR_SENSOR_L_LOG2:
+ result = (double) (log(result) / log(2.0));
+ break;
+ case SDR_SENSOR_L_E:
+ result = exp(result);
+ break;
+ case SDR_SENSOR_L_EXP10:
+ result = pow(10.0, result);
+ break;
+ case SDR_SENSOR_L_EXP2:
+ result = pow(2.0, result);
+ break;
+ case SDR_SENSOR_L_1_X:
+ result = pow(result, -1.0); /*1/x w/o exception */
+ break;
+ case SDR_SENSOR_L_SQR:
+ result = pow(result, 2.0);
+ break;
+ case SDR_SENSOR_L_CUBE:
+ result = pow(result, 3.0);
+ break;
+ case SDR_SENSOR_L_SQRT:
+ result = sqrt(result);
+ break;
+ case SDR_SENSOR_L_CUBERT:
+ result = cbrt(result);
+ break;
+ case SDR_SENSOR_L_LINEAR:
+ default:
+ break;
+ }
+ return result;
+}
+/* sdr_convert_sensor_hysterisis - convert raw sensor hysterisis
+ *
+ * Even though spec says histerisis should be computed using Mx+B
+ * formula, B is irrelevant when doing raw comparison
+ *
+ * threshold rearm point is computed using threshold +/- hysterisis
+ * with the full formula however B can't be applied in raw comparisons
+ *
+ * @sensor: sensor record
+ * @val: raw sensor reading
+ *
+ * returns floating-point sensor reading
+ */
+double
+sdr_convert_sensor_hysterisis(struct sdr_record_full_sensor *sensor, uint8_t val)
+{
+ int m, k2;
+ double result;
+
+ m = __TO_M(sensor->mtol);
+
+ k2 = __TO_R_EXP(sensor->bacc);
+
+ switch (sensor->cmn.unit.analog) {
+ case 0:
+ result = (double) (((m * val)) * pow(10, k2));
+ break;
+ case 1:
+ if (val & 0x80)
+ val++;
+ /* Deliberately fall through to case 2. */
+ case 2:
+ result = (double) (((m * (int8_t) val) ) * pow(10, k2));
+ break;
+ default:
+ /* Oops! This isn't an analog sensor. */
+ return 0.0;
+ }
+
+ switch (sensor->linearization & 0x7f) {
+ case SDR_SENSOR_L_LN:
+ result = log(result);
+ break;
+ case SDR_SENSOR_L_LOG10:
+ result = log10(result);
+ break;
+ case SDR_SENSOR_L_LOG2:
+ result = (double) (log(result) / log(2.0));
+ break;
+ case SDR_SENSOR_L_E:
+ result = exp(result);
+ break;
+ case SDR_SENSOR_L_EXP10:
+ result = pow(10.0, result);
+ break;
+ case SDR_SENSOR_L_EXP2:
+ result = pow(2.0, result);
+ break;
+ case SDR_SENSOR_L_1_X:
+ result = pow(result, -1.0); /*1/x w/o exception */
+ break;
+ case SDR_SENSOR_L_SQR:
+ result = pow(result, 2.0);
+ break;
+ case SDR_SENSOR_L_CUBE:
+ result = pow(result, 3.0);
+ break;
+ case SDR_SENSOR_L_SQRT:
+ result = sqrt(result);
+ break;
+ case SDR_SENSOR_L_CUBERT:
+ result = cbrt(result);
+ break;
+ case SDR_SENSOR_L_LINEAR:
+ default:
+ break;
+ }
+ return result;
+}
+
+
+/* sdr_convert_sensor_tolerance - convert raw sensor reading
+ *
+ * @sensor: sensor record
+ * @val: raw sensor reading
+ *
+ * returns floating-point sensor tolerance(interpreted)
+ */
+double
+sdr_convert_sensor_tolerance(struct sdr_record_full_sensor *sensor, uint8_t val)
+{
+ int m, k2;
+ double result;
+
+ m = __TO_M(sensor->mtol);
+ k2 = __TO_R_EXP(sensor->bacc);
+
+ switch (sensor->cmn.unit.analog) {
+ case 0:
+ /* as suggested in section 30.4.1 of IPMI 1.5 spec */
+ result = (double) ((((m * (double)val/2)) ) * pow(10, k2));
+ break;
+ case 1:
+ if (val & 0x80)
+ val++;
+ /* Deliberately fall through to case 2. */
+ case 2:
+ result = (double) (((m * ((double)((int8_t) val)/2))) * pow(10, k2));
+ break;
+ default:
+ /* Oops! This isn't an analog sensor. */
+ return 0.0;
+ }
+
+ switch (sensor->linearization & 0x7f) {
+ case SDR_SENSOR_L_LN:
+ result = log(result);
+ break;
+ case SDR_SENSOR_L_LOG10:
+ result = log10(result);
+ break;
+ case SDR_SENSOR_L_LOG2:
+ result = (double) (log(result) / log(2.0));
+ break;
+ case SDR_SENSOR_L_E:
+ result = exp(result);
+ break;
+ case SDR_SENSOR_L_EXP10:
+ result = pow(10.0, result);
+ break;
+ case SDR_SENSOR_L_EXP2:
+ result = pow(2.0, result);
+ break;
+ case SDR_SENSOR_L_1_X:
+ result = pow(result, -1.0); /*1/x w/o exception */
+ break;
+ case SDR_SENSOR_L_SQR:
+ result = pow(result, 2.0);
+ break;
+ case SDR_SENSOR_L_CUBE:
+ result = pow(result, 3.0);
+ break;
+ case SDR_SENSOR_L_SQRT:
+ result = sqrt(result);
+ break;
+ case SDR_SENSOR_L_CUBERT:
+ result = cbrt(result);
+ break;
+ case SDR_SENSOR_L_LINEAR:
+ default:
+ break;
+ }
+ return result;
+}
+
+/* sdr_convert_sensor_value_to_raw - convert sensor reading back to raw
+ *
+ * @sensor: sensor record
+ * @val: converted sensor reading
+ *
+ * returns raw sensor reading
+ */
+uint8_t
+sdr_convert_sensor_value_to_raw(struct sdr_record_full_sensor * sensor,
+ double val)
+{
+ int m, b, k1, k2;
+ double result;
+
+ /* only works for analog sensors */
+ if (UNITS_ARE_DISCRETE((&sensor->cmn)))
+ return 0;
+
+ m = __TO_M(sensor->mtol);
+ b = __TO_B(sensor->bacc);
+ k1 = __TO_B_EXP(sensor->bacc);
+ k2 = __TO_R_EXP(sensor->bacc);
+
+ /* don't divide by zero */
+ if (m == 0)
+ return 0;
+
+ result = (((val / pow(10, k2)) - (b * pow(10, k1))) / m);
+
+ if ((result - (int) result) >= .5)
+ return (uint8_t) ceil(result);
+ else
+ return (uint8_t) result;
+}
+
+/* ipmi_sdr_get_sensor_thresholds - return thresholds for sensor
+ *
+ * @intf: ipmi interface
+ * @sensor: sensor number
+ * @target: sensor owner ID
+ * @lun: sensor lun
+ * @channel: channel number
+ *
+ * returns pointer to ipmi response
+ */
+struct ipmi_rs *
+ipmi_sdr_get_sensor_thresholds(struct ipmi_intf *intf, uint8_t sensor,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ uint8_t bridged_request = 0;
+ uint32_t save_addr;
+ uint32_t save_channel;
+
+ if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
+ bridged_request = 1;
+ save_addr = intf->target_addr;
+ intf->target_addr = target;
+ save_channel = intf->target_channel;
+ intf->target_channel = channel;
+ }
+
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = lun;
+ req.msg.cmd = GET_SENSOR_THRESHOLDS;
+ req.msg.data = &sensor;
+ req.msg.data_len = sizeof (sensor);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (bridged_request) {
+ intf->target_addr = save_addr;
+ intf->target_channel = save_channel;
+ }
+ return rsp;
+}
+
+/* ipmi_sdr_get_sensor_hysteresis - return hysteresis for sensor
+ *
+ * @intf: ipmi interface
+ * @sensor: sensor number
+ * @target: sensor owner ID
+ * @lun: sensor lun
+ * @channel: channel number
+ *
+ * returns pointer to ipmi response
+ */
+struct ipmi_rs *
+ipmi_sdr_get_sensor_hysteresis(struct ipmi_intf *intf, uint8_t sensor,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rq req;
+ uint8_t rqdata[2];
+ struct ipmi_rs *rsp;
+ uint8_t bridged_request = 0;
+ uint32_t save_addr;
+ uint32_t save_channel;
+
+ if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
+ bridged_request = 1;
+ save_addr = intf->target_addr;
+ intf->target_addr = target;
+ save_channel = intf->target_channel;
+ intf->target_channel = channel;
+ }
+
+ rqdata[0] = sensor;
+ rqdata[1] = 0xff; /* reserved */
+
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = lun;
+ req.msg.cmd = GET_SENSOR_HYSTERESIS;
+ req.msg.data = rqdata;
+ req.msg.data_len = 2;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (bridged_request) {
+ intf->target_addr = save_addr;
+ intf->target_channel = save_channel;
+ }
+ return rsp;
+}
+
+/* ipmi_sdr_get_sensor_reading - retrieve a raw sensor reading
+ *
+ * @intf: ipmi interface
+ * @sensor: sensor id
+ *
+ * returns ipmi response structure
+ */
+struct ipmi_rs *
+ipmi_sdr_get_sensor_reading(struct ipmi_intf *intf, uint8_t sensor)
+{
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = GET_SENSOR_READING;
+ req.msg.data = &sensor;
+ req.msg.data_len = 1;
+
+ return intf->sendrecv(intf, &req);
+}
+
+
+/* ipmi_sdr_get_sensor_reading_ipmb - retrieve a raw sensor reading from ipmb
+ *
+ * @intf: ipmi interface
+ * @sensor: sensor id
+ * @target: IPMB target address
+ * @lun: sensor lun
+ * @channel: channel number
+ *
+ * returns ipmi response structure
+ */
+struct ipmi_rs *
+ipmi_sdr_get_sensor_reading_ipmb(struct ipmi_intf *intf, uint8_t sensor,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ uint8_t bridged_request = 0;
+ uint32_t save_addr;
+ uint32_t save_channel;
+
+ if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
+ lprintf(LOG_DEBUG,
+ "Bridge to Sensor "
+ "Intf my/%#x tgt/%#x:%#x Sdr tgt/%#x:%#x\n",
+ intf->my_addr, intf->target_addr, intf->target_channel,
+ target, channel);
+ bridged_request = 1;
+ save_addr = intf->target_addr;
+ intf->target_addr = target;
+ save_channel = intf->target_channel;
+ intf->target_channel = channel;
+ }
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = lun;
+ req.msg.cmd = GET_SENSOR_READING;
+ req.msg.data = &sensor;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (bridged_request) {
+ intf->target_addr = save_addr;
+ intf->target_channel = save_channel;
+ }
+ return rsp;
+}
+
+/* ipmi_sdr_get_sensor_event_status - retrieve sensor event status
+ *
+ * @intf: ipmi interface
+ * @sensor: sensor id
+ * @target: sensor owner ID
+ * @lun: sensor lun
+ * @channel: channel number
+ *
+ * returns ipmi response structure
+ */
+struct ipmi_rs *
+ipmi_sdr_get_sensor_event_status(struct ipmi_intf *intf, uint8_t sensor,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ uint8_t bridged_request = 0;
+ uint32_t save_addr;
+ uint32_t save_channel;
+
+ if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
+ bridged_request = 1;
+ save_addr = intf->target_addr;
+ intf->target_addr = target;
+ save_channel = intf->target_channel;
+ intf->target_channel = channel;
+ }
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = lun;
+ req.msg.cmd = GET_SENSOR_EVENT_STATUS;
+ req.msg.data = &sensor;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (bridged_request) {
+ intf->target_addr = save_addr;
+ intf->target_channel = save_channel;
+ }
+ return rsp;
+}
+
+/* ipmi_sdr_get_sensor_event_enable - retrieve sensor event enables
+ *
+ * @intf: ipmi interface
+ * @sensor: sensor id
+ * @target: sensor owner ID
+ * @lun: sensor lun
+ * @channel: channel number
+ *
+ * returns ipmi response structure
+ */
+struct ipmi_rs *
+ipmi_sdr_get_sensor_event_enable(struct ipmi_intf *intf, uint8_t sensor,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ uint8_t bridged_request = 0;
+ uint32_t save_addr;
+ uint32_t save_channel;
+
+ if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
+ bridged_request = 1;
+ save_addr = intf->target_addr;
+ intf->target_addr = target;
+ save_channel = intf->target_channel;
+ intf->target_channel = channel;
+ }
+
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = lun;
+ req.msg.cmd = GET_SENSOR_EVENT_ENABLE;
+ req.msg.data = &sensor;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (bridged_request) {
+ intf->target_addr = save_addr;
+ intf->target_channel = save_channel;
+ }
+ return rsp;
+}
+
+/* ipmi_sdr_get_sensor_type_desc - Get sensor type descriptor
+ *
+ * @type: ipmi sensor type
+ *
+ * returns
+ * string from sensor_type_desc
+ * or "reserved"
+ * or "OEM reserved"
+ */
+const char *
+ipmi_sdr_get_sensor_type_desc(const uint8_t type)
+{
+ static char desc[32];
+ memset(desc, 0, 32);
+ if (type <= SENSOR_TYPE_MAX)
+ return sensor_type_desc[type];
+ if (type < 0xc0)
+ snprintf(desc, 32, "reserved #%02x", type);
+ else
+ {
+ snprintf(desc, 32, oemval2str(sdriana,type,ipmi_oem_sdr_type_vals),
+ type);
+ }
+ return desc;
+}
+
+/* ipmi_sdr_get_thresh_status - threshold status indicator
+ *
+ * @rsp: response from Get Sensor Reading comand
+ * @validread: validity of the status field argument
+ * @invalidstr: string to return if status field is not valid
+ *
+ * returns
+ * cr = critical
+ * nc = non-critical
+ * nr = non-recoverable
+ * ok = ok
+ * ns = not specified
+ */
+const char *
+ipmi_sdr_get_thresh_status(struct sensor_reading *sr, const char *invalidstr)
+{
+ uint8_t stat;
+ if (!sr->s_reading_valid) {
+ return invalidstr;
+ }
+ stat = sr->s_data2;
+ if (stat & SDR_SENSOR_STAT_LO_NR) {
+ if (verbose)
+ return "Lower Non-Recoverable";
+ else if (sdr_extended)
+ return "lnr";
+ else
+ return "nr";
+ } else if (stat & SDR_SENSOR_STAT_HI_NR) {
+ if (verbose)
+ return "Upper Non-Recoverable";
+ else if (sdr_extended)
+ return "unr";
+ else
+ return "nr";
+ } else if (stat & SDR_SENSOR_STAT_LO_CR) {
+ if (verbose)
+ return "Lower Critical";
+ else if (sdr_extended)
+ return "lcr";
+ else
+ return "cr";
+ } else if (stat & SDR_SENSOR_STAT_HI_CR) {
+ if (verbose)
+ return "Upper Critical";
+ else if (sdr_extended)
+ return "ucr";
+ else
+ return "cr";
+ } else if (stat & SDR_SENSOR_STAT_LO_NC) {
+ if (verbose)
+ return "Lower Non-Critical";
+ else if (sdr_extended)
+ return "lnc";
+ else
+ return "nc";
+ } else if (stat & SDR_SENSOR_STAT_HI_NC) {
+ if (verbose)
+ return "Upper Non-Critical";
+ else if (sdr_extended)
+ return "unc";
+ else
+ return "nc";
+ }
+ return "ok";
+}
+
+/* ipmi_sdr_get_header - retreive SDR record header
+ *
+ * @intf: ipmi interface
+ * @itr: sdr iterator
+ *
+ * returns pointer to static sensor retrieval struct
+ * returns NULL on error
+ */
+static struct sdr_get_rs *
+ipmi_sdr_get_header(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ struct sdr_get_rq sdr_rq;
+ static struct sdr_get_rs sdr_rs;
+ int try = 0;
+
+ memset(&sdr_rq, 0, sizeof (sdr_rq));
+ sdr_rq.reserve_id = itr->reservation;
+ sdr_rq.id = itr->next;
+ sdr_rq.offset = 0;
+ sdr_rq.length = 5; /* only get the header */
+
+ memset(&req, 0, sizeof (req));
+ if (itr->use_built_in == 0) {
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_SDR;
+ } else {
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = GET_DEVICE_SDR;
+ }
+ req.msg.data = (uint8_t *) & sdr_rq;
+ req.msg.data_len = sizeof (sdr_rq);
+
+ for (try = 0; try < 5; try++) {
+ sdr_rq.reserve_id = itr->reservation;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get SDR %04x command failed",
+ itr->next);
+ continue;
+ } else if (rsp->ccode == 0xc5) {
+ /* lost reservation */
+ lprintf(LOG_DEBUG, "SDR reservation %04x cancelled. "
+ "Sleeping a bit and retrying...",
+ itr->reservation);
+
+ sleep(rand() & 3);
+
+ if (ipmi_sdr_get_reservation(intf, itr->use_built_in,
+ &(itr->reservation)) < 0) {
+ lprintf(LOG_ERR,
+ "Unable to renew SDR reservation");
+ return NULL;
+ }
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get SDR %04x command failed: %s",
+ itr->next, val2str(rsp->ccode,
+ completion_code_vals));
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (try == 5)
+ return NULL;
+
+ if (!rsp)
+ return NULL;
+
+ lprintf(LOG_DEBUG, "SDR record ID : 0x%04x", itr->next);
+
+ memcpy(&sdr_rs, rsp->data, sizeof (sdr_rs));
+
+ if (sdr_rs.length == 0) {
+ lprintf(LOG_ERR, "SDR record id 0x%04x: invalid length %d",
+ itr->next, sdr_rs.length);
+ return NULL;
+ }
+
+ /* achu (chu11 at llnl dot gov): - Some boards are stupid and
+ * return a record id from the Get SDR Record command
+ * different than the record id passed in. If we find this
+ * situation, we cheat and put the original record id back in.
+ * Otherwise, a later Get SDR Record command will fail with
+ * completion code CBh = "Requested Sensor, data, or record
+ * not present"
+ */
+ if (sdr_rs.id != itr->next) {
+ lprintf(LOG_DEBUG, "SDR record id mismatch: 0x%04x", sdr_rs.id);
+ sdr_rs.id = itr->next;
+ }
+
+ lprintf(LOG_DEBUG, "SDR record type : 0x%02x", sdr_rs.type);
+ lprintf(LOG_DEBUG, "SDR record next : 0x%04x", sdr_rs.next);
+ lprintf(LOG_DEBUG, "SDR record bytes: %d", sdr_rs.length);
+
+ return &sdr_rs;
+}
+
+/* ipmi_sdr_get_next_header - retreive next SDR header
+ *
+ * @intf: ipmi interface
+ * @itr: sdr iterator
+ *
+ * returns pointer to sensor retrieval struct
+ * returns NULL on error
+ */
+struct sdr_get_rs *
+ipmi_sdr_get_next_header(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr)
+{
+ struct sdr_get_rs *header;
+
+ if (itr->next == 0xffff)
+ return NULL;
+
+ header = ipmi_sdr_get_header(intf, itr);
+ if (header == NULL)
+ return NULL;
+
+ itr->next = header->next;
+
+ return header;
+}
+
+/*
+ * This macro is used to print nominal, normal and threshold settings,
+ * but it is not compatible with PRINT_NORMAL/PRINT_THRESH since it does
+ * not have the sensor.init.thresholds setting qualifier as is done in
+ * PRINT_THRESH. This means CSV output can be different than non CSV
+ * output if sensor.init.thresholds is ever zero
+ */
+/* helper macro for printing CSV output for Full SDR Threshold reading */
+#define SENSOR_PRINT_CSV(FULLSENS, FLAG, READ) \
+ if ((FLAG)) { \
+ if (UNITS_ARE_DISCRETE((&FULLSENS->cmn))) \
+ printf("0x%02X,", READ); \
+ else \
+ printf("%.3f,", sdr_convert_sensor_reading( \
+ (FULLSENS), READ)); \
+ } else { \
+ printf(","); \
+ }
+
+/* helper macro for printing analog values for Full SDR Threshold readings */
+#define SENSOR_PRINT_NORMAL(FULLSENS, NAME, READ) \
+ if ((FULLSENS)->analog_flag.READ != 0) { \
+ printf(" %-21s : ", NAME); \
+ if (UNITS_ARE_DISCRETE((&FULLSENS->cmn))) \
+ printf("0x%02X\n", \
+ (FULLSENS)->READ); \
+ else \
+ printf("%.3f\n", sdr_convert_sensor_reading( \
+ (FULLSENS), (FULLSENS)->READ));\
+ }
+
+/* helper macro for printing Full SDR sensor Thresholds */
+#define SENSOR_PRINT_THRESH(FULLSENS, NAME, READ, FLAG) \
+ if ((FULLSENS)->cmn.sensor.init.thresholds && \
+ (FULLSENS)->cmn.mask.type.threshold.read.FLAG != 0) { \
+ printf(" %-21s : ", NAME); \
+ if (UNITS_ARE_DISCRETE((&FULLSENS->cmn))) \
+ printf("0x%02X\n", \
+ (FULLSENS)->threshold.READ); \
+ else \
+ printf("%.3f\n", sdr_convert_sensor_reading( \
+ (FULLSENS), (FULLSENS)->threshold.READ)); \
+ }
+
+int
+ipmi_sdr_print_sensor_event_status(struct ipmi_intf *intf,
+ uint8_t sensor_num,
+ uint8_t sensor_type,
+ uint8_t event_type, int numeric_fmt,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rs *rsp;
+ int i;
+ const struct valstr assert_cond_1[] = {
+ {0x80, "unc+"},
+ {0x40, "unc-"},
+ {0x20, "lnr+"},
+ {0x10, "lnr-"},
+ {0x08, "lcr+"},
+ {0x04, "lcr-"},
+ {0x02, "lnc+"},
+ {0x01, "lnc-"},
+ {0x00, NULL},
+ };
+ const struct valstr assert_cond_2[] = {
+ {0x08, "unr+"},
+ {0x04, "unr-"},
+ {0x02, "ucr+"},
+ {0x01, "ucr-"},
+ {0x00, NULL},
+ };
+
+ rsp = ipmi_sdr_get_sensor_event_status(intf, sensor_num,
+ target, lun, channel);
+
+ if (rsp == NULL) {
+ lprintf(LOG_DEBUG,
+ "Error reading event status for sensor #%02x",
+ sensor_num);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_DEBUG,
+ "Error reading event status for sensor #%02x: %s",
+ sensor_num, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ /* There is an assumption here that data_len >= 1 */
+ if (IS_READING_UNAVAILABLE(rsp->data[0])) {
+ printf(" Event Status : Unavailable\n");
+ return 0;
+ }
+ if (IS_SCANNING_DISABLED(rsp->data[0])) {
+ //printf(" Event Status : Scanning Disabled\n");
+ //return 0;
+ }
+ if (IS_EVENT_MSG_DISABLED(rsp->data[0])) {
+ printf(" Event Status : Event Messages Disabled\n");
+ //return 0;
+ }
+
+ switch (numeric_fmt) {
+ case DISCRETE_SENSOR:
+ if (rsp->data_len == 2) {
+ ipmi_sdr_print_discrete_state("Assertion Events",
+ sensor_type, event_type,
+ rsp->data[1], 0);
+ } else if (rsp->data_len > 2) {
+ ipmi_sdr_print_discrete_state("Assertion Events",
+ sensor_type, event_type,
+ rsp->data[1],
+ rsp->data[2]);
+ }
+ if (rsp->data_len == 4) {
+ ipmi_sdr_print_discrete_state("Deassertion Events",
+ sensor_type, event_type,
+ rsp->data[3], 0);
+ } else if (rsp->data_len > 4) {
+ ipmi_sdr_print_discrete_state("Deassertion Events",
+ sensor_type, event_type,
+ rsp->data[3],
+ rsp->data[4]);
+ }
+ break;
+
+ case ANALOG_SENSOR:
+ printf(" Assertion Events : ");
+ for (i = 0; i < 8; i++) {
+ if (rsp->data[1] & (1 << i))
+ printf("%s ", val2str(1 << i, assert_cond_1));
+ }
+ if (rsp->data_len > 2) {
+ for (i = 0; i < 4; i++) {
+ if (rsp->data[2] & (1 << i))
+ printf("%s ",
+ val2str(1 << i, assert_cond_2));
+ }
+ printf("\n");
+ if ((rsp->data_len == 4 && rsp->data[3] != 0) ||
+ (rsp->data_len > 4
+ && (rsp->data[3] != 0 && rsp->data[4] != 0))) {
+ printf(" Deassertion Events : ");
+ for (i = 0; i < 8; i++) {
+ if (rsp->data[3] & (1 << i))
+ printf("%s ",
+ val2str(1 << i,
+ assert_cond_1));
+ }
+ if (rsp->data_len > 4) {
+ for (i = 0; i < 4; i++) {
+ if (rsp->data[4] & (1 << i))
+ printf("%s ",
+ val2str(1 << i,
+ assert_cond_2));
+ }
+ }
+ printf("\n");
+ }
+ } else {
+ printf("\n");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int
+ipmi_sdr_print_sensor_mask(struct sdr_record_mask *mask,
+ uint8_t sensor_type,
+ uint8_t event_type, int numeric_fmt)
+{
+ /* iceblink - don't print some event status fields - CVS rev1.53 */
+ return 0;
+
+ switch (numeric_fmt) {
+ case DISCRETE_SENSOR:
+ ipmi_sdr_print_discrete_state("Assert Event Mask", sensor_type,
+ event_type,
+ mask->type.discrete.
+ assert_event & 0xff,
+ (mask->type.discrete.
+ assert_event & 0xff00) >> 8);
+ ipmi_sdr_print_discrete_state("Deassert Event Mask",
+ sensor_type, event_type,
+ mask->type.discrete.
+ deassert_event & 0xff,
+ (mask->type.discrete.
+ deassert_event & 0xff00) >> 8);
+ break;
+
+ case ANALOG_SENSOR:
+ printf(" Assert Event Mask : ");
+ if (mask->type.threshold.assert_lnr_high)
+ printf("lnr+ ");
+ if (mask->type.threshold.assert_lnr_low)
+ printf("lnr- ");
+ if (mask->type.threshold.assert_lcr_high)
+ printf("lcr+ ");
+ if (mask->type.threshold.assert_lcr_low)
+ printf("lcr- ");
+ if (mask->type.threshold.assert_lnc_high)
+ printf("lnc+ ");
+ if (mask->type.threshold.assert_lnc_low)
+ printf("lnc- ");
+ if (mask->type.threshold.assert_unc_high)
+ printf("unc+ ");
+ if (mask->type.threshold.assert_unc_low)
+ printf("unc- ");
+ if (mask->type.threshold.assert_ucr_high)
+ printf("ucr+ ");
+ if (mask->type.threshold.assert_ucr_low)
+ printf("ucr- ");
+ if (mask->type.threshold.assert_unr_high)
+ printf("unr+ ");
+ if (mask->type.threshold.assert_unr_low)
+ printf("unr- ");
+ printf("\n");
+
+ printf(" Deassert Event Mask : ");
+ if (mask->type.threshold.deassert_lnr_high)
+ printf("lnr+ ");
+ if (mask->type.threshold.deassert_lnr_low)
+ printf("lnr- ");
+ if (mask->type.threshold.deassert_lcr_high)
+ printf("lcr+ ");
+ if (mask->type.threshold.deassert_lcr_low)
+ printf("lcr- ");
+ if (mask->type.threshold.deassert_lnc_high)
+ printf("lnc+ ");
+ if (mask->type.threshold.deassert_lnc_low)
+ printf("lnc- ");
+ if (mask->type.threshold.deassert_unc_high)
+ printf("unc+ ");
+ if (mask->type.threshold.deassert_unc_low)
+ printf("unc- ");
+ if (mask->type.threshold.deassert_ucr_high)
+ printf("ucr+ ");
+ if (mask->type.threshold.deassert_ucr_low)
+ printf("ucr- ");
+ if (mask->type.threshold.deassert_unr_high)
+ printf("unr+ ");
+ if (mask->type.threshold.deassert_unr_low)
+ printf("unr- ");
+ printf("\n");
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int
+ipmi_sdr_print_sensor_event_enable(struct ipmi_intf *intf,
+ uint8_t sensor_num,
+ uint8_t sensor_type,
+ uint8_t event_type, int numeric_fmt,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rs *rsp;
+ int i;
+ const struct valstr assert_cond_1[] = {
+ {0x80, "unc+"},
+ {0x40, "unc-"},
+ {0x20, "lnr+"},
+ {0x10, "lnr-"},
+ {0x08, "lcr+"},
+ {0x04, "lcr-"},
+ {0x02, "lnc+"},
+ {0x01, "lnc-"},
+ {0x00, NULL},
+ };
+ const struct valstr assert_cond_2[] = {
+ {0x08, "unr+"},
+ {0x04, "unr-"},
+ {0x02, "ucr+"},
+ {0x01, "ucr-"},
+ {0x00, NULL},
+ };
+
+ rsp = ipmi_sdr_get_sensor_event_enable(intf, sensor_num,
+ target, lun, channel);
+
+ if (rsp == NULL) {
+ lprintf(LOG_DEBUG,
+ "Error reading event enable for sensor #%02x",
+ sensor_num);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_DEBUG,
+ "Error reading event enable for sensor #%02x: %s",
+ sensor_num, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ if (IS_SCANNING_DISABLED(rsp->data[0])) {
+ //printf(" Event Enable : Scanning Disabled\n");
+ //return 0;
+ }
+ if (IS_EVENT_MSG_DISABLED(rsp->data[0])) {
+ printf(" Event Enable : Event Messages Disabled\n");
+ //return 0;
+ }
+
+ switch (numeric_fmt) {
+ case DISCRETE_SENSOR:
+ /* discrete */
+ if (rsp->data_len == 2) {
+ ipmi_sdr_print_discrete_state("Assertions Enabled",
+ sensor_type, event_type,
+ rsp->data[1], 0);
+ } else if (rsp->data_len > 2) {
+ ipmi_sdr_print_discrete_state("Assertions Enabled",
+ sensor_type, event_type,
+ rsp->data[1],
+ rsp->data[2]);
+ }
+ if (rsp->data_len == 4) {
+ ipmi_sdr_print_discrete_state("Deassertions Enabled",
+ sensor_type, event_type,
+ rsp->data[3], 0);
+ } else if (rsp->data_len > 4) {
+ ipmi_sdr_print_discrete_state("Deassertions Enabled",
+ sensor_type, event_type,
+ rsp->data[3],
+ rsp->data[4]);
+ }
+ break;
+
+ case ANALOG_SENSOR:
+ /* analog */
+ printf(" Assertions Enabled : ");
+ for (i = 0; i < 8; i++) {
+ if (rsp->data[1] & (1 << i))
+ printf("%s ", val2str(1 << i, assert_cond_1));
+ }
+ if (rsp->data_len > 2) {
+ for (i = 0; i < 4; i++) {
+ if (rsp->data[2] & (1 << i))
+ printf("%s ",
+ val2str(1 << i, assert_cond_2));
+ }
+ printf("\n");
+ if ((rsp->data_len == 4 && rsp->data[3] != 0) ||
+ (rsp->data_len > 4
+ && (rsp->data[3] != 0 || rsp->data[4] != 0))) {
+ printf(" Deassertions Enabled : ");
+ for (i = 0; i < 8; i++) {
+ if (rsp->data[3] & (1 << i))
+ printf("%s ",
+ val2str(1 << i,
+ assert_cond_1));
+ }
+ if (rsp->data_len > 4) {
+ for (i = 0; i < 4; i++) {
+ if (rsp->data[4] & (1 << i))
+ printf("%s ",
+ val2str(1 << i,
+ assert_cond_2));
+ }
+ }
+ printf("\n");
+ }
+ } else {
+ printf("\n");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* ipmi_sdr_print_sensor_hysteresis - print hysteresis for Discrete & Analog
+ *
+ * @sensor: Common Sensor Record SDR pointer
+ * @full: Full Sensor Record SDR pointer (if applicable)
+ * @hysteresis_value: Actual hysteresis value
+ * @hvstr: hysteresis value Identifier String
+ *
+ * returns void
+ */
+void
+ipmi_sdr_print_sensor_hysteresis(struct sdr_record_common_sensor *sensor,
+ struct sdr_record_full_sensor *full,
+ uint8_t hysteresis_value,
+ const char *hvstr)
+{
+ /*
+ * compact can have pos/neg hysteresis, but they cannot be analog!
+ * We use not full in addition to our discrete units check just in
+ * case a compact sensor is incorrectly identified as analog.
+ */
+ if (!full || UNITS_ARE_DISCRETE(sensor)) {
+ if ( hysteresis_value == 0x00 || hysteresis_value == 0xff ) {
+ printf(" %s : Unspecified\n", hvstr);
+ } else {
+ printf(" %s : 0x%02X\n", hvstr, hysteresis_value);
+ }
+ return;
+ }
+ /* A Full analog sensor */
+ double creading = sdr_convert_sensor_hysterisis(full, hysteresis_value);
+ if ( hysteresis_value == 0x00 || hysteresis_value == 0xff ||
+ creading == 0.0 ) {
+ printf(" %s : Unspecified\n", hvstr);
+ } else {
+ printf(" %s : %.3f\n", hvstr, creading);
+ }
+}
+
+/* print_sensor_min_max - print Discrete & Analog Minimum/Maximum Sensor Range
+ *
+ * @full: Full Sensor Record SDR pointer
+ *
+ * returns void
+ */
+static void
+print_sensor_min_max(struct sdr_record_full_sensor *full)
+{
+ if (!full) { /* No min/max for compact SDR record */
+ return;
+ }
+
+ double creading = 0.0;
+ uint8_t is_analog = !UNITS_ARE_DISCRETE(&full->cmn);
+ if (is_analog)
+ creading = sdr_convert_sensor_reading(full, full->sensor_min);
+ if ((full->cmn.unit.analog == 0 && full->sensor_min == 0x00) ||
+ (full->cmn.unit.analog == 1 && full->sensor_min == 0xff) ||
+ (full->cmn.unit.analog == 2 && full->sensor_min == 0x80) ||
+ (is_analog && (creading == 0.0)))
+ printf(" Minimum sensor range : Unspecified\n");
+ else {
+ if (is_analog)
+ printf(" Minimum sensor range : %.3f\n", creading);
+ else
+ printf(" Minimum sensor range : 0x%02X\n", full->sensor_min);
+
+ }
+ if (is_analog)
+ creading = sdr_convert_sensor_reading(full, full->sensor_max);
+ if ((full->cmn.unit.analog == 0 && full->sensor_max == 0xff) ||
+ (full->cmn.unit.analog == 1 && full->sensor_max == 0x00) ||
+ (full->cmn.unit.analog == 2 && full->sensor_max == 0x7f) ||
+ (is_analog && (creading == 0.0)))
+ printf(" Maximum sensor range : Unspecified\n");
+ else {
+ if (is_analog)
+ printf(" Maximum sensor range : %.3f\n", creading);
+ else
+ printf(" Maximum sensor range : 0x%02X\n", full->sensor_max);
+ }
+}
+
+/* print_csv_discrete - print csv formatted discrete sensor
+ *
+ * @sensor: common sensor structure
+ * @sr: sensor reading
+ *
+ * returns void
+ */
+static void
+print_csv_discrete(struct sdr_record_common_sensor *sensor,
+ const struct sensor_reading *sr)
+{
+ if (!sr->s_reading_valid || sr->s_reading_unavailable) {
+ printf("%02Xh,ns,%d.%d,No Reading",
+ sensor->keys.sensor_num,
+ sensor->entity.id,
+ sensor->entity.instance);
+ return;
+ }
+
+ if (sr->s_has_analog_value) { /* Sensor has an analog value */
+ printf("%s,%s,", sr->s_a_str, sr->s_a_units);
+ } else { /* Sensor has a discrete value */
+ printf("%02Xh,", sensor->keys.sensor_num);
+ }
+ printf("ok,%d.%d,",
+ sensor->entity.id,
+ sensor->entity.instance);
+ ipmi_sdr_print_discrete_state_mini(NULL, ", ",
+ sensor->sensor.type,
+ sensor->event_type,
+ sr->s_data2,
+ sr->s_data3);
+}
+
+/* ipmi_sdr_read_sensor_value - read sensor value
+ *
+ * @intf Interface pointer
+ * @sensor Common sensor component pointer
+ * @sdr_record_type Type of sdr sensor record
+ * @precision decimal precision for analog format conversion
+ *
+ * returns a pointer to sensor value reading data structure
+ */
+struct sensor_reading *
+ipmi_sdr_read_sensor_value(struct ipmi_intf *intf,
+ struct sdr_record_common_sensor *sensor,
+ uint8_t sdr_record_type, int precision)
+{
+ static struct sensor_reading sr;
+
+ if (sensor == NULL)
+ return NULL;
+
+ /* Initialize to reading valid value of zero */
+ memset(&sr, 0, sizeof(sr));
+
+ switch (sdr_record_type) {
+ int idlen;
+ case (SDR_RECORD_TYPE_FULL_SENSOR):
+ sr.full = (struct sdr_record_full_sensor *)sensor;
+ idlen = sr.full->id_code & 0x1f;
+ idlen = idlen < sizeof(sr.s_id) ?
+ idlen : sizeof(sr.s_id) - 1;
+ memcpy(sr.s_id, sr.full->id_string, idlen);
+ break;
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sr.compact = (struct sdr_record_compact_sensor *)sensor;
+ idlen = sr.compact->id_code & 0x1f;
+ idlen = idlen < sizeof(sr.s_id) ?
+ idlen : sizeof(sr.s_id) - 1;
+ memcpy(sr.s_id, sr.compact->id_string, idlen);
+ break;
+ default:
+ return NULL;
+ }
+
+ /*
+ * Get current reading via IPMI interface
+ */
+ struct ipmi_rs *rsp;
+ rsp = ipmi_sdr_get_sensor_reading_ipmb(intf,
+ sensor->keys.sensor_num,
+ sensor->keys.owner_id,
+ sensor->keys.lun,
+ sensor->keys.channel);
+ sr.s_a_val = 0.0; /* init analog value to a floating point 0 */
+ sr.s_a_str[0] = '\0'; /* no converted analog value string */
+ sr.s_a_units = ""; /* no converted analog units units */
+
+
+ if (rsp == NULL) {
+ lprintf(LOG_DEBUG, "Error reading sensor %s (#%02x)",
+ sr.s_id, sensor->keys.sensor_num);
+ return &sr;
+ }
+
+ if (rsp->ccode) {
+ if ( !((sr.full && rsp->ccode == 0xcb) ||
+ (sr.compact && rsp->ccode == 0xcd)) ) {
+ lprintf(LOG_DEBUG,
+ "Error reading sensor %s (#%02x): %s", sr.s_id,
+ sensor->keys.sensor_num,
+ val2str(rsp->ccode, completion_code_vals));
+ }
+ return &sr;
+ }
+
+ if (rsp->data_len < 2) {
+ /*
+ * We must be returned both a value (data[0]), and the validity
+ * of the value (data[1]), in order to correctly interpret
+ * the reading. If we don't have both of these we can't have
+ * a valid sensor reading.
+ */
+ lprintf(LOG_DEBUG, "Error reading sensor %s invalid len %d",
+ sr.s_id, rsp->data_len);
+ return &sr;
+ }
+
+
+ if (IS_READING_UNAVAILABLE(rsp->data[1]))
+ sr.s_reading_unavailable = 1;
+
+ if (IS_SCANNING_DISABLED(rsp->data[1])) {
+ sr.s_scanning_disabled = 1;
+ lprintf(LOG_DEBUG, "Sensor %s (#%02x) scanning disabled",
+ sr.s_id, sensor->keys.sensor_num);
+ return &sr;
+ }
+ if ( !sr.s_reading_unavailable ) {
+ sr.s_reading_valid = 1;
+ sr.s_reading = rsp->data[0];
+ }
+ if (rsp->data_len > 2)
+ sr.s_data2 = rsp->data[2];
+ if (rsp->data_len > 3)
+ sr.s_data3 = rsp->data[3];
+ if (sdr_sensor_has_analog_reading(intf, &sr)) {
+ sr.s_has_analog_value = 1;
+ if (sr.s_reading_valid) {
+ sr.s_a_val = sdr_convert_sensor_reading(sr.full, sr.s_reading);
+ }
+ /* determine units string with possible modifiers */
+ sr.s_a_units = ipmi_sdr_get_unit_string(sr.full->cmn.unit.pct,
+ sr.full->cmn.unit.modifier,
+ sr.full->cmn.unit.type.base,
+ sr.full->cmn.unit.type.modifier);
+ snprintf(sr.s_a_str, sizeof(sr.s_a_str), "%.*f",
+ (sr.s_a_val == (int) sr.s_a_val) ? 0 :
+ precision, sr.s_a_val);
+ }
+ return &sr;
+}
+
+/* ipmi_sdr_print_sensor_fc - print full & compact SDR records
+ *
+ * @intf: ipmi interface
+ * @sensor: common sensor structure
+ * @sdr_record_type: type of sdr record, either full or compact
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_sensor_fc(struct ipmi_intf *intf,
+ struct sdr_record_common_sensor *sensor,
+ uint8_t sdr_record_type)
+{
+ char sval[16];
+ int i = 0;
+ uint8_t target, lun, channel;
+ struct sensor_reading *sr;
+
+
+ sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 2);
+
+ if (sr == NULL)
+ return -1;
+
+ target = sensor->keys.owner_id;
+ lun = sensor->keys.lun;
+ channel = sensor->keys.channel;
+
+ /*
+ * CSV OUTPUT
+ */
+
+ if (csv_output) {
+ /*
+ * print sensor name, reading, unit, state
+ */
+ printf("%s,", sr->s_id);
+ if (!IS_THRESHOLD_SENSOR(sensor)) {
+ /* Discrete/Non-Threshold */
+ print_csv_discrete(sensor, sr);
+ printf("\n");
+ }
+ else {
+ /* Threshold Analog & Discrete*/
+ if (sr->s_reading_valid) {
+ if (sr->s_has_analog_value) {
+ /* Analog/Threshold */
+ printf("%.*f,", (sr->s_a_val ==
+ (int) sr->s_a_val) ? 0 : 3,
+ sr->s_a_val);
+ printf("%s,%s", sr->s_a_units,
+ ipmi_sdr_get_thresh_status(sr, "ns"));
+ } else { /* Discrete/Threshold */
+ print_csv_discrete(sensor, sr);
+ }
+ } else {
+ printf(",,ns");
+ }
+
+ if (verbose) {
+ printf(",%d.%d,%s,%s,",
+ sensor->entity.id, sensor->entity.instance,
+ val2str(sensor->entity.id, entity_id_vals),
+ ipmi_sdr_get_sensor_type_desc(sensor->sensor.
+ type));
+
+ if (sr->full) {
+ SENSOR_PRINT_CSV(sr->full, sr->full->analog_flag.nominal_read,
+ sr->full->nominal_read);
+ SENSOR_PRINT_CSV(sr->full, sr->full->analog_flag.normal_min,
+ sr->full->normal_min);
+ SENSOR_PRINT_CSV(sr->full, sr->full->analog_flag.normal_max,
+ sr->full->normal_max);
+ SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.unr,
+ sr->full->threshold.upper.non_recover);
+ SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.ucr,
+ sr->full->threshold.upper.critical);
+ SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.unc,
+ sr->full->threshold.upper.non_critical);
+ SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.lnr,
+ sr->full->threshold.lower.non_recover);
+ SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.lcr,
+ sr->full->threshold.lower.critical);
+ SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.lnc,
+ sr->full->threshold.lower.non_critical);
+
+ if (UNITS_ARE_DISCRETE(sensor)) {
+ printf("0x%02X,0x%02X", sr->full->sensor_min, sr->full->sensor_max);
+ }
+ else {
+ printf("%.3f,%.3f",
+ sdr_convert_sensor_reading(sr->full,
+ sr->full->sensor_min),
+ sdr_convert_sensor_reading(sr->full,
+ sr->full->sensor_max));
+ }
+ } else {
+ printf(",,,,,,,,,,");
+ }
+ }
+ printf("\n");
+ }
+
+ return 0; /* done */
+ }
+
+ /*
+ * NORMAL OUTPUT
+ */
+
+ if (verbose == 0 && sdr_extended == 0) {
+ /*
+ * print sensor name, reading, state
+ */
+ printf("%-16s | ", sr->s_id);
+
+ memset(sval, 0, sizeof (sval));
+
+ if (sr->s_reading_valid) {
+ if( sr->s_has_analog_value ) {
+ snprintf(sval, sizeof (sval), "%s %s",
+ sr->s_a_str,
+ sr->s_a_units);
+ } else /* Discrete */
+ snprintf(sval, sizeof(sval),
+ "0x%02x", sr->s_reading);
+ }
+ else if (sr->s_scanning_disabled)
+ snprintf(sval, sizeof (sval), sr->full ? "disabled" : "Not Readable");
+ else
+ snprintf(sval, sizeof (sval), sr->full ? "no reading" : "Not Readable");
+
+ printf("%s", sval);
+
+ for (i = strlen(sval); i <= sizeof (sval); i++)
+ printf(" ");
+ printf(" | ");
+
+ if (IS_THRESHOLD_SENSOR(sensor)) {
+ printf("%s", ipmi_sdr_get_thresh_status(sr, "ns"));
+ }
+ else {
+ printf("%s", sr->s_reading_valid ? "ok" : "ns");
+ }
+
+ printf("\n");
+
+ return 0; /* done */
+ } else if (verbose == 0 && sdr_extended == 1) {
+ /*
+ * print sensor name, number, state, entity, reading
+ */
+ printf("%-16s | %02Xh | ",
+ sr->s_id, sensor->keys.sensor_num);
+
+ if (IS_THRESHOLD_SENSOR(sensor)) {
+ /* Threshold Analog & Discrete */
+ printf("%-3s | %2d.%1d | ",
+ ipmi_sdr_get_thresh_status(sr, "ns"),
+ sensor->entity.id, sensor->entity.instance);
+ }
+ else {
+ /* Non Threshold Analog & Discrete */
+ printf("%-3s | %2d.%1d | ",
+ (sr->s_reading_valid ? "ok" : "ns"),
+ sensor->entity.id, sensor->entity.instance);
+ }
+
+ memset(sval, 0, sizeof (sval));
+
+ if (sr->s_reading_valid) {
+ if (IS_THRESHOLD_SENSOR(sensor) &&
+ sr->s_has_analog_value ) {
+ /* Threshold Analog */
+ snprintf(sval, sizeof (sval), "%s %s",
+ sr->s_a_str,
+ sr->s_a_units);
+ } else {
+ /* Analog & Discrete & Threshold/Discrete */
+ char *header = NULL;
+ if (sr->s_has_analog_value) { /* Sensor has an analog value */
+ printf("%s %s", sr->s_a_str, sr->s_a_units);
+ header = ", ";
+ }
+ ipmi_sdr_print_discrete_state_mini(header, ", ",
+ sensor->sensor.type,
+ sensor->event_type,
+ sr->s_data2,
+ sr->s_data3);
+ }
+ }
+ else if (sr->s_scanning_disabled)
+ snprintf(sval, sizeof (sval), "Disabled");
+ else
+ snprintf(sval, sizeof (sval), "No Reading");
+
+ printf("%s\n", sval);
+ return 0; /* done */
+ }
+ /*
+ * VERBOSE OUTPUT
+ */
+
+ printf("Sensor ID : %s (0x%x)\n",
+ sr->s_id, sensor->keys.sensor_num);
+ printf(" Entity ID : %d.%d (%s)\n",
+ sensor->entity.id, sensor->entity.instance,
+ val2str(sensor->entity.id, entity_id_vals));
+
+ if (!IS_THRESHOLD_SENSOR(sensor)) {
+ /* Discrete */
+ printf(" Sensor Type (Discrete): %s (0x%02x)\n",
+ ipmi_sdr_get_sensor_type_desc(sensor->sensor.type),
+ sensor->sensor.type);
+ lprintf(LOG_DEBUG, " Event Type Code : 0x%02x",
+ sensor->event_type);
+
+ printf(" Sensor Reading : ");
+ if (sr->s_reading_valid) {
+ if (sr->s_has_analog_value) { /* Sensor has an analog value */
+ printf("%s %s\n", sr->s_a_str, sr->s_a_units);
+ } else {
+ printf("%xh\n", sr->s_reading);
+ }
+ }
+ else if (sr->s_scanning_disabled)
+ printf("Disabled\n");
+ else {
+ /* Used to be 'Not Reading' */
+ printf("No Reading\n");
+ }
+
+ printf(" Event Message Control : ");
+ switch (sensor->sensor.capabilities.event_msg) {
+ case 0:
+ printf("Per-threshold\n");
+ break;
+ case 1:
+ printf("Entire Sensor Only\n");
+ break;
+ case 2:
+ printf("Global Disable Only\n");
+ break;
+ case 3:
+ printf("No Events From Sensor\n");
+ break;
+ }
+
+ ipmi_sdr_print_discrete_state("States Asserted",
+ sensor->sensor.type,
+ sensor->event_type,
+ sr->s_data2,
+ sr->s_data3);
+ ipmi_sdr_print_sensor_mask(&sensor->mask, sensor->sensor.type,
+ sensor->event_type, DISCRETE_SENSOR);
+ ipmi_sdr_print_sensor_event_status(intf,
+ sensor->keys.sensor_num,
+ sensor->sensor.type,
+ sensor->event_type,
+ DISCRETE_SENSOR,
+ target,
+ lun, channel);
+ ipmi_sdr_print_sensor_event_enable(intf,
+ sensor->keys.sensor_num,
+ sensor->sensor.type,
+ sensor->event_type,
+ DISCRETE_SENSOR,
+ target,
+ lun, channel);
+ printf(" OEM : %X\n",
+ sr->full ? sr->full->oem : sr->compact->oem);
+ printf("\n");
+
+ return 0; /* done */
+ }
+ printf(" Sensor Type (Threshold) : %s (0x%02x)\n",
+ ipmi_sdr_get_sensor_type_desc(sensor->sensor.type),
+ sensor->sensor.type);
+
+ printf(" Sensor Reading : ");
+ if (sr->s_reading_valid) {
+ if (sr->full) {
+ uint16_t raw_tol = __TO_TOL(sr->full->mtol);
+ if (UNITS_ARE_DISCRETE(sensor)) {
+ printf("0x%02X (+/- 0x%02X) %s\n",
+ sr->s_reading, raw_tol, sr->s_a_units);
+ }
+ else {
+ double tol = sdr_convert_sensor_tolerance(sr->full, raw_tol);
+ printf("%.*f (+/- %.*f) %s\n",
+ (sr->s_a_val == (int) sr->s_a_val) ? 0 : 3,
+ sr->s_a_val, (tol == (int) tol) ? 0 :
+ 3, tol, sr->s_a_units);
+ }
+ } else {
+ printf("0x%02X %s\n", sr->s_reading, sr->s_a_units);
+ }
+ } else if (sr->s_scanning_disabled)
+ printf("Disabled\n");
+ else
+ printf("No Reading\n");
+
+ printf(" Status : %s\n",
+ ipmi_sdr_get_thresh_status(sr, "Not Available"));
+
+ if(sr->full) {
+ SENSOR_PRINT_NORMAL(sr->full, "Nominal Reading", nominal_read);
+ SENSOR_PRINT_NORMAL(sr->full, "Normal Minimum", normal_min);
+ SENSOR_PRINT_NORMAL(sr->full, "Normal Maximum", normal_max);
+
+ SENSOR_PRINT_THRESH(sr->full, "Upper non-recoverable", upper.non_recover, unr);
+ SENSOR_PRINT_THRESH(sr->full, "Upper critical", upper.critical, ucr);
+ SENSOR_PRINT_THRESH(sr->full, "Upper non-critical", upper.non_critical, unc);
+ SENSOR_PRINT_THRESH(sr->full, "Lower non-recoverable", lower.non_recover, lnr);
+ SENSOR_PRINT_THRESH(sr->full, "Lower critical", lower.critical, lcr);
+ SENSOR_PRINT_THRESH(sr->full, "Lower non-critical", lower.non_critical, lnc);
+ }
+ ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
+ sr->full ? sr->full->threshold.hysteresis.positive :
+ sr->compact->threshold.hysteresis.positive, "Positive Hysteresis");
+
+ ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
+ sr->full ? sr->full->threshold.hysteresis.negative :
+ sr->compact->threshold.hysteresis.negative, "Negative Hysteresis");
+
+ print_sensor_min_max(sr->full);
+
+ printf(" Event Message Control : ");
+ switch (sensor->sensor.capabilities.event_msg) {
+ case 0:
+ printf("Per-threshold\n");
+ break;
+ case 1:
+ printf("Entire Sensor Only\n");
+ break;
+ case 2:
+ printf("Global Disable Only\n");
+ break;
+ case 3:
+ printf("No Events From Sensor\n");
+ break;
+ }
+
+ printf(" Readable Thresholds : ");
+ switch (sensor->sensor.capabilities.threshold) {
+ case 0:
+ printf("No Thresholds\n");
+ break;
+ case 1: /* readable according to mask */
+ case 2: /* readable and settable according to mask */
+ if (sensor->mask.type.threshold.read.lnr)
+ printf("lnr ");
+ if (sensor->mask.type.threshold.read.lcr)
+ printf("lcr ");
+ if (sensor->mask.type.threshold.read.lnc)
+ printf("lnc ");
+ if (sensor->mask.type.threshold.read.unc)
+ printf("unc ");
+ if (sensor->mask.type.threshold.read.ucr)
+ printf("ucr ");
+ if (sensor->mask.type.threshold.read.unr)
+ printf("unr ");
+ printf("\n");
+ break;
+ case 3:
+ printf("Thresholds Fixed\n");
+ break;
+ }
+
+ printf(" Settable Thresholds : ");
+ switch (sensor->sensor.capabilities.threshold) {
+ case 0:
+ printf("No Thresholds\n");
+ break;
+ case 1: /* readable according to mask */
+ case 2: /* readable and settable according to mask */
+ if (sensor->mask.type.threshold.set.lnr)
+ printf("lnr ");
+ if (sensor->mask.type.threshold.set.lcr)
+ printf("lcr ");
+ if (sensor->mask.type.threshold.set.lnc)
+ printf("lnc ");
+ if (sensor->mask.type.threshold.set.unc)
+ printf("unc ");
+ if (sensor->mask.type.threshold.set.ucr)
+ printf("ucr ");
+ if (sensor->mask.type.threshold.set.unr)
+ printf("unr ");
+ printf("\n");
+ break;
+ case 3:
+ printf("Thresholds Fixed\n");
+ break;
+ }
+
+ if (sensor->mask.type.threshold.status_lnr ||
+ sensor->mask.type.threshold.status_lcr ||
+ sensor->mask.type.threshold.status_lnc ||
+ sensor->mask.type.threshold.status_unc ||
+ sensor->mask.type.threshold.status_ucr ||
+ sensor->mask.type.threshold.status_unr) {
+ printf(" Threshold Read Mask : ");
+ if (sensor->mask.type.threshold.status_lnr)
+ printf("lnr ");
+ if (sensor->mask.type.threshold.status_lcr)
+ printf("lcr ");
+ if (sensor->mask.type.threshold.status_lnc)
+ printf("lnc ");
+ if (sensor->mask.type.threshold.status_unc)
+ printf("unc ");
+ if (sensor->mask.type.threshold.status_ucr)
+ printf("ucr ");
+ if (sensor->mask.type.threshold.status_unr)
+ printf("unr ");
+ printf("\n");
+ }
+
+ ipmi_sdr_print_sensor_mask(&sensor->mask,
+ sensor->sensor.type,
+ sensor->event_type, ANALOG_SENSOR);
+ ipmi_sdr_print_sensor_event_status(intf,
+ sensor->keys.sensor_num,
+ sensor->sensor.type,
+ sensor->event_type, ANALOG_SENSOR,
+ target,
+ lun, channel);
+
+ ipmi_sdr_print_sensor_event_enable(intf,
+ sensor->keys.sensor_num,
+ sensor->sensor.type,
+ sensor->event_type, ANALOG_SENSOR,
+ target,
+ lun, channel);
+
+ printf("\n");
+ return 0;
+}
+
+static inline int
+get_offset(uint8_t x)
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ if (x >> i == 1)
+ return i;
+ return 0;
+}
+
+/* ipmi_sdr_print_discrete_state_mini - print list of asserted states
+ * for a discrete sensor
+ *
+ * @header : header string if necessary
+ * @separator : field separator string
+ * @sensor_type : sensor type code
+ * @event_type : event type code
+ * @state : mask of asserted states
+ *
+ * no meaningful return value
+ */
+void
+ipmi_sdr_print_discrete_state_mini(const char *header, const char *separator,
+ uint8_t sensor_type, uint8_t event_type,
+ uint8_t state1, uint8_t state2)
+{
+ uint8_t typ;
+ struct ipmi_event_sensor_types *evt;
+ int pre = 0, c = 0;
+
+ if (state1 == 0 && (state2 & 0x7f) == 0)
+ return;
+
+ if (event_type == 0x6f) {
+ evt = sensor_specific_types;
+ typ = sensor_type;
+ } else {
+ evt = generic_event_types;
+ typ = event_type;
+ }
+
+ if (header)
+ printf("%s", header);
+
+ for (; evt->type != NULL; evt++) {
+ if ((evt->code != typ) ||
+ (evt->data != 0xFF))
+ continue;
+
+ if (evt->offset > 7) {
+ if ((1 << (evt->offset - 8)) & (state2 & 0x7f)) {
+ if (pre++ != 0)
+ printf("%s", separator);
+ if (evt->desc)
+ printf("%s", evt->desc);
+ }
+ } else {
+ if ((1 << evt->offset) & state1) {
+ if (pre++ != 0)
+ printf("%s", separator);
+ if (evt->desc)
+ printf("%s", evt->desc);
+ }
+ }
+ c++;
+ }
+}
+
+/* ipmi_sdr_print_discrete_state - print list of asserted states
+ * for a discrete sensor
+ *
+ * @desc : description for this line
+ * @sensor_type : sensor type code
+ * @event_type : event type code
+ * @state : mask of asserted states
+ *
+ * no meaningful return value
+ */
+void
+ipmi_sdr_print_discrete_state(const char *desc,
+ uint8_t sensor_type, uint8_t event_type,
+ uint8_t state1, uint8_t state2)
+{
+ uint8_t typ;
+ struct ipmi_event_sensor_types *evt;
+ int pre = 0, c = 0;
+
+ if (state1 == 0 && (state2 & 0x7f) == 0)
+ return;
+
+ if (event_type == 0x6f) {
+ evt = sensor_specific_types;
+ typ = sensor_type;
+ } else {
+ evt = generic_event_types;
+ typ = event_type;
+ }
+
+ for (; evt->type != NULL; evt++) {
+ if ((evt->code != typ) ||
+ (evt->data != 0xFF))
+ continue;
+
+ if (pre == 0) {
+ printf(" %-21s : %s\n", desc, evt->type);
+ pre = 1;
+ }
+
+ if (evt->offset > 7) {
+ if ((1 << (evt->offset - 8)) & (state2 & 0x7f)) {
+ if (evt->desc) {
+ printf(" "
+ "[%s]\n",
+ evt->desc);
+ } else {
+ printf(" "
+ "[no description]\n");
+ }
+ }
+ } else {
+ if ((1 << evt->offset) & state1) {
+ if (evt->desc) {
+ printf(" "
+ "[%s]\n",
+ evt->desc);
+ } else {
+ printf(" "
+ "[no description]\n");
+ }
+ }
+ }
+ c++;
+ }
+}
+
+
+/* ipmi_sdr_print_sensor_eventonly - print SDR event only record
+ *
+ * @intf: ipmi interface
+ * @sensor: event only sdr record
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_sensor_eventonly(struct ipmi_intf *intf,
+ struct sdr_record_eventonly_sensor *sensor)
+{
+ char desc[17];
+
+ if (sensor == NULL)
+ return -1;
+
+ memset(desc, 0, sizeof (desc));
+ snprintf(desc, (sensor->id_code & 0x1f) + 1, "%s", sensor->id_string);
+
+ if (verbose) {
+ printf("Sensor ID : %s (0x%x)\n",
+ sensor->id_code ? desc : "", sensor->keys.sensor_num);
+ printf("Entity ID : %d.%d (%s)\n",
+ sensor->entity.id, sensor->entity.instance,
+ val2str(sensor->entity.id, entity_id_vals));
+ printf("Sensor Type : %s (0x%02x)\n",
+ ipmi_sdr_get_sensor_type_desc(sensor->sensor_type),
+ sensor->sensor_type);
+ lprintf(LOG_DEBUG, "Event Type Code : 0x%02x",
+ sensor->event_type);
+ printf("\n");
+ } else {
+ if (csv_output)
+ printf("%s,%02Xh,ns,%d.%d,Event-Only\n",
+ sensor->id_code ? desc : "",
+ sensor->keys.sensor_num,
+ sensor->entity.id, sensor->entity.instance);
+ else if (sdr_extended)
+ printf("%-16s | %02Xh | ns | %2d.%1d | Event-Only\n",
+ sensor->id_code ? desc : "",
+ sensor->keys.sensor_num,
+ sensor->entity.id, sensor->entity.instance);
+ else
+ printf("%-16s | Event-Only | ns\n",
+ sensor->id_code ? desc : "");
+ }
+
+ return 0;
+}
+
+/* ipmi_sdr_print_sensor_mc_locator - print SDR MC locator record
+ *
+ * @intf: ipmi interface
+ * @mc: mc locator sdr record
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_sensor_mc_locator(struct ipmi_intf *intf,
+ struct sdr_record_mc_locator *mc)
+{
+ char desc[17];
+
+ if (mc == NULL)
+ return -1;
+
+ memset(desc, 0, sizeof (desc));
+ snprintf(desc, (mc->id_code & 0x1f) + 1, "%s", mc->id_string);
+
+ if (verbose == 0) {
+ if (csv_output)
+ printf("%s,00h,ok,%d.%d\n",
+ mc->id_code ? desc : "",
+ mc->entity.id, mc->entity.instance);
+ else if (sdr_extended) {
+ printf("%-16s | 00h | ok | %2d.%1d | ",
+ mc->id_code ? desc : "",
+ mc->entity.id, mc->entity.instance);
+
+ printf("%s MC @ %02Xh\n",
+ (mc->
+ pwr_state_notif & 0x1) ? "Static" : "Dynamic",
+ mc->dev_slave_addr);
+ } else {
+ printf("%-16s | %s MC @ %02Xh %s | ok\n",
+ mc->id_code ? desc : "",
+ (mc->
+ pwr_state_notif & 0x1) ? "Static" : "Dynamic",
+ mc->dev_slave_addr,
+ (mc->pwr_state_notif & 0x1) ? " " : "");
+ }
+
+ return 0; /* done */
+ }
+
+ printf("Device ID : %s\n", mc->id_string);
+ printf("Entity ID : %d.%d (%s)\n",
+ mc->entity.id, mc->entity.instance,
+ val2str(mc->entity.id, entity_id_vals));
+
+ printf("Device Slave Address : %02Xh\n", mc->dev_slave_addr);
+ printf("Channel Number : %01Xh\n", mc->channel_num);
+
+ printf("ACPI System P/S Notif : %sRequired\n",
+ (mc->pwr_state_notif & 0x4) ? "" : "Not ");
+ printf("ACPI Device P/S Notif : %sRequired\n",
+ (mc->pwr_state_notif & 0x2) ? "" : "Not ");
+ printf("Controller Presence : %s\n",
+ (mc->pwr_state_notif & 0x1) ? "Static" : "Dynamic");
+ printf("Logs Init Agent Errors : %s\n",
+ (mc->global_init & 0x8) ? "Yes" : "No");
+
+ printf("Event Message Gen : ");
+ if (!(mc->global_init & 0x3))
+ printf("Enable\n");
+ else if ((mc->global_init & 0x3) == 0x1)
+ printf("Disable\n");
+ else if ((mc->global_init & 0x3) == 0x2)
+ printf("Do Not Init Controller\n");
+ else
+ printf("Reserved\n");
+
+ printf("Device Capabilities\n");
+ printf(" Chassis Device : %s\n",
+ (mc->dev_support & 0x80) ? "Yes" : "No");
+ printf(" Bridge : %s\n",
+ (mc->dev_support & 0x40) ? "Yes" : "No");
+ printf(" IPMB Event Generator : %s\n",
+ (mc->dev_support & 0x20) ? "Yes" : "No");
+ printf(" IPMB Event Receiver : %s\n",
+ (mc->dev_support & 0x10) ? "Yes" : "No");
+ printf(" FRU Inventory Device : %s\n",
+ (mc->dev_support & 0x08) ? "Yes" : "No");
+ printf(" SEL Device : %s\n",
+ (mc->dev_support & 0x04) ? "Yes" : "No");
+ printf(" SDR Repository : %s\n",
+ (mc->dev_support & 0x02) ? "Yes" : "No");
+ printf(" Sensor Device : %s\n",
+ (mc->dev_support & 0x01) ? "Yes" : "No");
+
+ printf("\n");
+
+ return 0;
+}
+
+/* ipmi_sdr_print_sensor_generic_locator - print generic device locator record
+ *
+ * @intf: ipmi interface
+ * @gen: generic device locator sdr record
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_sensor_generic_locator(struct ipmi_intf *intf,
+ struct sdr_record_generic_locator *dev)
+{
+ char desc[17];
+
+ memset(desc, 0, sizeof (desc));
+ snprintf(desc, (dev->id_code & 0x1f) + 1, "%s", dev->id_string);
+
+ if (!verbose) {
+ if (csv_output)
+ printf("%s,00h,ns,%d.%d\n",
+ dev->id_code ? desc : "",
+ dev->entity.id, dev->entity.instance);
+ else if (sdr_extended)
+ printf
+ ("%-16s | 00h | ns | %2d.%1d | Generic Device @%02Xh:%02Xh.%1d\n",
+ dev->id_code ? desc : "", dev->entity.id,
+ dev->entity.instance, dev->dev_access_addr,
+ dev->dev_slave_addr, dev->oem);
+ else
+ printf("%-16s | Generic @%02X:%02X.%-2d | ok\n",
+ dev->id_code ? desc : "",
+ dev->dev_access_addr,
+ dev->dev_slave_addr, dev->oem);
+
+ return 0;
+ }
+
+ printf("Device ID : %s\n", dev->id_string);
+ printf("Entity ID : %d.%d (%s)\n",
+ dev->entity.id, dev->entity.instance,
+ val2str(dev->entity.id, entity_id_vals));
+
+ printf("Device Access Address : %02Xh\n", dev->dev_access_addr);
+ printf("Device Slave Address : %02Xh\n", dev->dev_slave_addr);
+ printf("Address Span : %02Xh\n", dev->addr_span);
+ printf("Channel Number : %01Xh\n", dev->channel_num);
+ printf("LUN.Bus : %01Xh.%01Xh\n", dev->lun, dev->bus);
+ printf("Device Type.Modifier : %01Xh.%01Xh (%s)\n",
+ dev->dev_type, dev->dev_type_modifier,
+ val2str(dev->dev_type << 8 | dev->dev_type_modifier,
+ entity_device_type_vals));
+ printf("OEM : %02Xh\n", dev->oem);
+ printf("\n");
+
+ return 0;
+}
+
+/* ipmi_sdr_print_sensor_fru_locator - print FRU locator record
+ *
+ * @intf: ipmi interface
+ * @fru: fru locator sdr record
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_sensor_fru_locator(struct ipmi_intf *intf,
+ struct sdr_record_fru_locator *fru)
+{
+ char desc[17];
+
+ memset(desc, 0, sizeof (desc));
+ snprintf(desc, (fru->id_code & 0x1f) + 1, "%s", fru->id_string);
+
+ if (!verbose) {
+ if (csv_output)
+ printf("%s,00h,ns,%d.%d\n",
+ fru->id_code ? desc : "",
+ fru->entity.id, fru->entity.instance);
+ else if (sdr_extended)
+ printf("%-16s | 00h | ns | %2d.%1d | %s FRU @%02Xh\n",
+ fru->id_code ? desc : "",
+ fru->entity.id, fru->entity.instance,
+ (fru->logical) ? "Logical" : "Physical",
+ fru->device_id);
+ else
+ printf("%-16s | %s FRU @%02Xh %02x.%x | ok\n",
+ fru->id_code ? desc : "",
+ (fru->logical) ? "Log" : "Phy",
+ fru->device_id,
+ fru->entity.id, fru->entity.instance);
+
+ return 0;
+ }
+
+ printf("Device ID : %s\n", fru->id_string);
+ printf("Entity ID : %d.%d (%s)\n",
+ fru->entity.id, fru->entity.instance,
+ val2str(fru->entity.id, entity_id_vals));
+
+ printf("Device Access Address : %02Xh\n", fru->dev_slave_addr);
+ printf("%s: %02Xh\n",
+ fru->logical ? "Logical FRU Device " :
+ "Slave Address ", fru->device_id);
+ printf("Channel Number : %01Xh\n", fru->channel_num);
+ printf("LUN.Bus : %01Xh.%01Xh\n", fru->lun, fru->bus);
+ printf("Device Type.Modifier : %01Xh.%01Xh (%s)\n",
+ fru->dev_type, fru->dev_type_modifier,
+ val2str(fru->dev_type << 8 | fru->dev_type_modifier,
+ entity_device_type_vals));
+ printf("OEM : %02Xh\n", fru->oem);
+ printf("\n");
+
+ return 0;
+}
+
+/* ipmi_sdr_print_sensor_entity_assoc - print SDR entity association record
+ *
+ * @intf: ipmi interface
+ * @mc: entity association sdr record
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_sensor_entity_assoc(struct ipmi_intf *intf,
+ struct sdr_record_entity_assoc *assoc)
+{
+ return 0;
+}
+
+/* ipmi_sdr_print_sensor_oem_intel - print Intel OEM sensors
+ *
+ * @intf: ipmi interface
+ * @oem: oem sdr record
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_sdr_print_sensor_oem_intel(struct ipmi_intf *intf,
+ struct sdr_record_oem *oem)
+{
+ switch (oem->data[3]) { /* record sub-type */
+ case 0x02: /* Power Unit Map */
+ if (verbose) {
+ printf
+ ("Sensor ID : Power Unit Redundancy (0x%x)\n",
+ oem->data[4]);
+ printf
+ ("Sensor Type : Intel OEM - Power Unit Map\n");
+ printf("Redundant Supplies : %d", oem->data[6]);
+ if (oem->data[5])
+ printf(" (flags %xh)", oem->data[5]);
+ printf("\n");
+ }
+
+ switch (oem->data_len) {
+ case 7: /* SR1300, non-redundant */
+ if (verbose)
+ printf("Power Redundancy : No\n");
+ else if (csv_output)
+ printf("Power Redundancy,Not Available,nr\n");
+ else
+ printf
+ ("Power Redundancy | Not Available | nr\n");
+ break;
+ case 8: /* SR2300, redundant, PS1 & PS2 present */
+ if (verbose) {
+ printf("Power Redundancy : No\n");
+ printf("Power Supply 2 Sensor : %x\n",
+ oem->data[8]);
+ } else if (csv_output) {
+ printf("Power Redundancy,PS@%02xh,nr\n",
+ oem->data[8]);
+ } else {
+ printf
+ ("Power Redundancy | PS@%02xh | nr\n",
+ oem->data[8]);
+ }
+ break;
+ case 9: /* SR2300, non-redundant, PSx present */
+ if (verbose) {
+ printf("Power Redundancy : Yes\n");
+ printf("Power Supply Sensor : %x\n",
+ oem->data[7]);
+ printf("Power Supply Sensor : %x\n",
+ oem->data[8]);
+ } else if (csv_output) {
+ printf
+ ("Power Redundancy,PS@%02xh + PS@%02xh,ok\n",
+ oem->data[7], oem->data[8]);
+ } else {
+ printf
+ ("Power Redundancy | PS@%02xh + PS@%02xh | ok\n",
+ oem->data[7], oem->data[8]);
+ }
+ break;
+ }
+ if (verbose)
+ printf("\n");
+ break;
+ case 0x03: /* Fan Speed Control */
+ break;
+ case 0x06: /* System Information */
+ break;
+ case 0x07: /* Ambient Temperature Fan Speed Control */
+ break;
+ default:
+ lprintf(LOG_DEBUG, "Unknown Intel OEM SDR Record type %02x",
+ oem->data[3]);
+ }
+
+ return 0;
+}
+
+/* ipmi_sdr_print_sensor_oem - print OEM sensors
+ *
+ * This function is generally only filled out by decoding what
+ * a particular BMC might stuff into its OEM records. The
+ * records are keyed off manufacturer ID and record subtypes.
+ *
+ * @intf: ipmi interface
+ * @oem: oem sdr record
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_sdr_print_sensor_oem(struct ipmi_intf *intf, struct sdr_record_oem *oem)
+{
+ int rc = 0;
+
+ if (oem == NULL)
+ return -1;
+ if (oem->data_len == 0 || oem->data == NULL)
+ return -1;
+
+ if (verbose > 2)
+ printbuf(oem->data, oem->data_len, "OEM Record");
+
+ /* intel manufacturer id */
+ if (oem->data[0] == 0x57 &&
+ oem->data[1] == 0x01 && oem->data[2] == 0x00) {
+ rc = ipmi_sdr_print_sensor_oem_intel(intf, oem);
+ }
+
+ return rc;
+}
+
+/* ipmi_sdr_print_name_from_rawentry - Print SDR name from raw data
+ *
+ * @intf: ipmi interface
+ * @type: sensor type
+ * @raw: raw sensor data
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_name_from_rawentry(struct ipmi_intf *intf,uint16_t id,
+ uint8_t type,uint8_t * raw)
+{
+ union {
+ struct sdr_record_full_sensor *full;
+ struct sdr_record_compact_sensor *compact;
+ struct sdr_record_eventonly_sensor *eventonly;
+ struct sdr_record_generic_locator *genloc;
+ struct sdr_record_fru_locator *fruloc;
+ struct sdr_record_mc_locator *mcloc;
+ struct sdr_record_entity_assoc *entassoc;
+ struct sdr_record_oem *oem;
+ } record;
+
+ int rc =0;
+ char desc[17];
+ memset(desc, ' ', sizeof (desc));
+
+ switch ( type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ record.full = (struct sdr_record_full_sensor *) raw;
+ snprintf(desc, (record.full->id_code & 0x1f) +1, "%s",
+ (const char *)record.full->id_string);
+ break;
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ record.compact = (struct sdr_record_compact_sensor *) raw ;
+ snprintf(desc, (record.compact->id_code & 0x1f) +1, "%s",
+ (const char *)record.compact->id_string);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ record.eventonly = (struct sdr_record_eventonly_sensor *) raw ;
+ snprintf(desc, (record.eventonly->id_code & 0x1f) +1, "%s",
+ (const char *)record.eventonly->id_string);
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ record.mcloc = (struct sdr_record_mc_locator *) raw ;
+ snprintf(desc, (record.mcloc->id_code & 0x1f) +1, "%s",
+ (const char *)record.mcloc->id_string);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ lprintf(LOG_INFO, "ID: 0x%04x , NAME: %-16s", id, desc);
+ return rc;
+}
+
+/* ipmi_sdr_print_rawentry - Print SDR entry from raw data
+ *
+ * @intf: ipmi interface
+ * @type: sensor type
+ * @raw: raw sensor data
+ * @len: length of raw sensor data
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_rawentry(struct ipmi_intf *intf, uint8_t type,
+ uint8_t * raw, int len)
+{
+ int rc = 0;
+
+ switch (type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ rc = ipmi_sdr_print_sensor_fc(intf,
+ (struct sdr_record_common_sensor *) raw,
+ type);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ rc = ipmi_sdr_print_sensor_eventonly(intf,
+ (struct
+ sdr_record_eventonly_sensor
+ *) raw);
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ rc = ipmi_sdr_print_sensor_generic_locator(intf,
+ (struct
+ sdr_record_generic_locator
+ *) raw);
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ rc = ipmi_sdr_print_sensor_fru_locator(intf,
+ (struct
+ sdr_record_fru_locator
+ *) raw);
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ rc = ipmi_sdr_print_sensor_mc_locator(intf,
+ (struct
+ sdr_record_mc_locator *)
+ raw);
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ rc = ipmi_sdr_print_sensor_entity_assoc(intf,
+ (struct
+ sdr_record_entity_assoc
+ *) raw);
+ break;
+ case SDR_RECORD_TYPE_OEM:{
+ struct sdr_record_oem oem;
+ oem.data = raw;
+ oem.data_len = len;
+ rc = ipmi_sdr_print_sensor_oem(intf,
+ (struct sdr_record_oem *)
+ &oem);
+ break;
+ }
+ case SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC:
+ case SDR_RECORD_TYPE_MC_CONFIRMATION:
+ case SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO:
+ /* not implemented */
+ break;
+ }
+
+ return rc;
+}
+
+/* ipmi_sdr_print_listentry - Print SDR entry from list
+ *
+ * @intf: ipmi interface
+ * @entry: sdr record list entry
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_listentry(struct ipmi_intf *intf, struct sdr_record_list *entry)
+{
+ int rc = 0;
+
+ switch (entry->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ rc = ipmi_sdr_print_sensor_fc(intf, entry->record.common, entry->type);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ rc = ipmi_sdr_print_sensor_eventonly(intf,
+ entry->record.eventonly);
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ rc = ipmi_sdr_print_sensor_generic_locator(intf,
+ entry->record.
+ genloc);
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ rc = ipmi_sdr_print_sensor_fru_locator(intf,
+ entry->record.fruloc);
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ rc = ipmi_sdr_print_sensor_mc_locator(intf,
+ entry->record.mcloc);
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ rc = ipmi_sdr_print_sensor_entity_assoc(intf,
+ entry->record.entassoc);
+ break;
+ case SDR_RECORD_TYPE_OEM:
+ rc = ipmi_sdr_print_sensor_oem(intf, entry->record.oem);
+ break;
+ case SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC:
+ case SDR_RECORD_TYPE_MC_CONFIRMATION:
+ case SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO:
+ /* not implemented yet */
+ break;
+ }
+
+ return rc;
+}
+
+/* ipmi_sdr_print_sdr - iterate through SDR printing records
+ *
+ * intf: ipmi interface
+ * type: record type to print
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_sdr(struct ipmi_intf *intf, uint8_t type)
+{
+ struct sdr_get_rs *header;
+ struct sdr_record_list *e;
+ int rc = 0;
+
+ lprintf(LOG_DEBUG, "Querying SDR for sensor list");
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = ipmi_sdr_start(intf, 0);
+ if (sdr_list_itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return -1;
+ }
+ }
+
+ for (e = sdr_list_head; e != NULL; e = e->next) {
+ if (type != e->type && type != 0xff && type != 0xfe)
+ continue;
+ if (type == 0xfe &&
+ e->type != SDR_RECORD_TYPE_FULL_SENSOR &&
+ e->type != SDR_RECORD_TYPE_COMPACT_SENSOR)
+ continue;
+ if (ipmi_sdr_print_listentry(intf, e) < 0)
+ rc = -1;
+ }
+
+ while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
+ uint8_t *rec;
+ struct sdr_record_list *sdrr;
+
+ rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
+ if (rec == NULL) {
+ lprintf(LOG_ERR, "ipmitool: ipmi_sdr_get_record() failed");
+ rc = -1;
+ continue;
+ }
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ if (rec != NULL) {
+ free(rec);
+ rec = NULL;
+ }
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+ sdrr->id = header->id;
+ sdrr->type = header->type;
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.common =
+ (struct sdr_record_common_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ lprintf(LOG_DEBUG, "SDR record ID : 0x%04x", sdrr->id);
+
+ if (type == header->type || type == 0xff ||
+ (type == 0xfe &&
+ (header->type == SDR_RECORD_TYPE_FULL_SENSOR ||
+ header->type == SDR_RECORD_TYPE_COMPACT_SENSOR))) {
+ if (ipmi_sdr_print_rawentry(intf, header->type,
+ rec, header->length) < 0)
+ rc = -1;
+ }
+
+ /* add to global record liset */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+ }
+
+ return rc;
+}
+
+/* ipmi_sdr_get_reservation - Obtain SDR reservation ID
+ *
+ * @intf: ipmi interface
+ * @reserve_id: pointer to short int for storing the id
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_get_reservation(struct ipmi_intf *intf, int use_builtin,
+ uint16_t * reserve_id)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+
+ /* obtain reservation ID */
+ memset(&req, 0, sizeof (req));
+
+ if (use_builtin == 0) {
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ } else {
+ req.msg.netfn = IPMI_NETFN_SE;
+ }
+
+ req.msg.cmd = GET_SDR_RESERVE_REPO;
+ rsp = intf->sendrecv(intf, &req);
+
+ /* be slient for errors, they are handled by calling function */
+ if (rsp == NULL)
+ return -1;
+ if (rsp->ccode > 0)
+ return -1;
+
+ *reserve_id = ((struct sdr_reserve_repo_rs *) &(rsp->data))->reserve_id;
+ lprintf(LOG_DEBUG, "SDR reservation ID %04x", *reserve_id);
+
+ return 0;
+}
+
+/* ipmi_sdr_start - setup sdr iterator
+ *
+ * @intf: ipmi interface
+ *
+ * returns sdr iterator structure pointer
+ * returns NULL on error
+ */
+struct ipmi_sdr_iterator *
+ipmi_sdr_start(struct ipmi_intf *intf, int use_builtin)
+{
+ struct ipmi_sdr_iterator *itr;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+
+ struct ipm_devid_rsp *devid;
+
+ itr = malloc(sizeof (struct ipmi_sdr_iterator));
+ if (itr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+
+ /* check SDRR capability */
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Device ID command failed");
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Device ID command failed: %#x %s",
+ rsp->ccode, val2str(rsp->ccode, completion_code_vals));
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+ devid = (struct ipm_devid_rsp *) rsp->data;
+
+ sdriana = (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id);
+
+ if (!use_builtin && (devid->device_revision & IPM_DEV_DEVICE_ID_SDR_MASK)) {
+ if ((devid->adtl_device_support & 0x02) == 0) {
+ if ((devid->adtl_device_support & 0x01)) {
+ lprintf(LOG_DEBUG, "Using Device SDRs\n");
+ use_built_in = 1;
+ } else {
+ lprintf(LOG_ERR, "Error obtaining SDR info");
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+ } else {
+ lprintf(LOG_DEBUG, "Using SDR from Repository \n");
+ }
+ }
+ itr->use_built_in = use_builtin ? 1 : use_built_in;
+ /***********************/
+ if (itr->use_built_in == 0) {
+ struct sdr_repo_info_rs sdr_info;
+ /* get sdr repository info */
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_SDR_REPO_INFO;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error obtaining SDR info");
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error obtaining SDR info: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+
+ memcpy(&sdr_info, rsp->data, sizeof (sdr_info));
+ /* IPMIv1.0 == 0x01
+ * IPMIv1.5 == 0x51
+ * IPMIv2.0 == 0x02
+ */
+ if ((sdr_info.version != 0x51) &&
+ (sdr_info.version != 0x01) &&
+ (sdr_info.version != 0x02)) {
+ lprintf(LOG_WARN, "WARNING: Unknown SDR repository "
+ "version 0x%02x", sdr_info.version);
+ }
+
+ itr->total = sdr_info.count;
+ itr->next = 0;
+
+ lprintf(LOG_DEBUG, "SDR free space: %d", sdr_info.free);
+ lprintf(LOG_DEBUG, "SDR records : %d", sdr_info.count);
+
+ /* Build SDRR if there is no record in repository */
+ if( sdr_info.count == 0 ) {
+ lprintf(LOG_DEBUG, "Rebuilding SDRR...");
+
+ if( ipmi_sdr_add_from_sensors( intf, 0 ) != 0 ) {
+ lprintf(LOG_ERR, "Could not build SDRR!");
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+ }
+ } else {
+ struct sdr_device_info_rs sdr_info;
+ /* get device sdr info */
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = GET_DEVICE_SDR_INFO;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp || !rsp->data_len || rsp->ccode) {
+ printf("Err in cmd get sensor sdr info\n");
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+ memcpy(&sdr_info, rsp->data, sizeof (sdr_info));
+
+ itr->total = sdr_info.count;
+ itr->next = 0;
+ lprintf(LOG_DEBUG, "SDR records : %d", sdr_info.count);
+ }
+
+ if (ipmi_sdr_get_reservation(intf, itr->use_built_in,
+ &(itr->reservation)) < 0) {
+ lprintf(LOG_ERR, "Unable to obtain SDR reservation");
+ free(itr);
+ itr = NULL;
+ return NULL;
+ }
+
+ return itr;
+}
+
+/* ipmi_sdr_get_record - return RAW SDR record
+ *
+ * @intf: ipmi interface
+ * @header: SDR header
+ * @itr: SDR iterator
+ *
+ * returns raw SDR data
+ * returns NULL on error
+ */
+uint8_t *
+ipmi_sdr_get_record(struct ipmi_intf * intf, struct sdr_get_rs * header,
+ struct ipmi_sdr_iterator * itr)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ struct sdr_get_rq sdr_rq;
+ uint8_t *data;
+ int i = 0, len = header->length;
+
+ if (len < 1)
+ return NULL;
+
+ data = malloc(len + 1);
+ if (data == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+ memset(data, 0, len + 1);
+
+ memset(&sdr_rq, 0, sizeof (sdr_rq));
+ sdr_rq.reserve_id = itr->reservation;
+ sdr_rq.id = header->id;
+ sdr_rq.offset = 0;
+
+ memset(&req, 0, sizeof (req));
+ if (itr->use_built_in == 0) {
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = GET_SDR;
+ } else {
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.cmd = GET_DEVICE_SDR;
+ }
+ req.msg.data = (uint8_t *) & sdr_rq;
+ req.msg.data_len = sizeof (sdr_rq);
+
+ /* check if max length is null */
+ if ( sdr_max_read_len == 0 ) {
+ /* get maximum response size */
+ sdr_max_read_len = ipmi_intf_get_max_response_data_size(intf) - 2;
+
+ /* cap the number of bytes to read */
+ if (sdr_max_read_len > 0xFE) {
+ sdr_max_read_len = 0xFE;
+ }
+ }
+
+ /* read SDR record with partial reads
+ * because a full read usually exceeds the maximum
+ * transport buffer size. (completion code 0xca)
+ */
+ while (i < len) {
+ sdr_rq.length = (len - i < sdr_max_read_len) ?
+ len - i : sdr_max_read_len;
+ sdr_rq.offset = i + 5; /* 5 header bytes */
+
+ lprintf(LOG_DEBUG, "Getting %d bytes from SDR at offset %d",
+ sdr_rq.length, sdr_rq.offset);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ sdr_max_read_len = sdr_rq.length - 1;
+ if (sdr_max_read_len > 0) {
+ /* no response may happen if requests are bridged
+ and too many bytes are requested */
+ continue;
+ } else {
+ free(data);
+ data = NULL;
+ return NULL;
+ }
+ }
+
+ switch (rsp->ccode) {
+ case 0xca:
+ /* read too many bytes at once */
+ sdr_max_read_len = sdr_rq.length - 1;
+ continue;
+ case 0xc5:
+ /* lost reservation */
+ lprintf(LOG_DEBUG, "SDR reservation cancelled. "
+ "Sleeping a bit and retrying...");
+
+ sleep(rand() & 3);
+
+ if (ipmi_sdr_get_reservation(intf, itr->use_built_in,
+ &(itr->reservation)) < 0) {
+ free(data);
+ data = NULL;
+ return NULL;
+ }
+ sdr_rq.reserve_id = itr->reservation;
+ continue;
+ }
+
+ /* special completion codes handled above */
+ if (rsp->ccode > 0 || rsp->data_len == 0) {
+ free(data);
+ data = NULL;
+ return NULL;
+ }
+
+ memcpy(data + i, rsp->data + 2, sdr_rq.length);
+ i += sdr_max_read_len;
+ }
+
+ return data;
+}
+
+/* ipmi_sdr_end - cleanup SDR iterator
+ *
+ * @intf: ipmi interface
+ * @itr: SDR iterator
+ *
+ * no meaningful return code
+ */
+void
+ipmi_sdr_end(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr)
+{
+ if (itr) {
+ free(itr);
+ itr = NULL;
+ }
+}
+
+/* __sdr_list_add - helper function to add SDR record to list
+ *
+ * @head: list head
+ * @entry: new entry to add to end of list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+__sdr_list_add(struct sdr_record_list *head, struct sdr_record_list *entry)
+{
+ struct sdr_record_list *e;
+ struct sdr_record_list *new;
+
+ if (head == NULL)
+ return -1;
+
+ new = malloc(sizeof (struct sdr_record_list));
+ if (new == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+ memcpy(new, entry, sizeof (struct sdr_record_list));
+
+ e = head;
+ while (e->next)
+ e = e->next;
+ e->next = new;
+ new->next = NULL;
+
+ return 0;
+}
+
+/* __sdr_list_empty - low-level handler to clean up record list
+ *
+ * @head: list head to clean
+ *
+ * no meaningful return code
+ */
+static void
+__sdr_list_empty(struct sdr_record_list *head)
+{
+ struct sdr_record_list *e, *f;
+ for (e = head; e != NULL; e = f) {
+ f = e->next;
+ free(e);
+ e = NULL;
+ }
+ head = NULL;
+}
+
+/* ipmi_sdr_list_empty - clean global SDR list
+ *
+ * @intf: ipmi interface
+ *
+ * no meaningful return code
+ */
+void
+ipmi_sdr_list_empty(struct ipmi_intf *intf)
+{
+ struct sdr_record_list *list, *next;
+
+ ipmi_sdr_end(intf, sdr_list_itr);
+
+ for (list = sdr_list_head; list != NULL; list = next) {
+ switch (list->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ if (list->record.common) {
+ free(list->record.common);
+ list->record.common = NULL;
+ }
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ if (list->record.eventonly) {
+ free(list->record.eventonly);
+ list->record.eventonly = NULL;
+ }
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ if (list->record.genloc) {
+ free(list->record.genloc);
+ list->record.genloc = NULL;
+ }
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ if (list->record.fruloc) {
+ free(list->record.fruloc);
+ list->record.fruloc = NULL;
+ }
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ if (list->record.mcloc) {
+ free(list->record.mcloc);
+ list->record.mcloc = NULL;
+ }
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ if (list->record.entassoc) {
+ free(list->record.entassoc);
+ list->record.entassoc = NULL;
+ }
+ break;
+ }
+ next = list->next;
+ free(list);
+ list = NULL;
+ }
+
+ sdr_list_head = NULL;
+ sdr_list_tail = NULL;
+ sdr_list_itr = NULL;
+}
+
+/* ipmi_sdr_find_sdr_bynumtype - lookup SDR entry by number/type
+ *
+ * @intf: ipmi interface
+ * @gen_id: sensor owner ID/LUN - SEL generator ID
+ * @num: sensor number to search for
+ * @type: sensor type to search for
+ *
+ * returns pointer to SDR list
+ * returns NULL on error
+ */
+struct sdr_record_list *
+ipmi_sdr_find_sdr_bynumtype(struct ipmi_intf *intf, uint16_t gen_id, uint8_t num, uint8_t type)
+{
+ struct sdr_get_rs *header;
+ struct sdr_record_list *e;
+ int found = 0;
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = ipmi_sdr_start(intf, 0);
+ if (sdr_list_itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return NULL;
+ }
+ }
+
+ /* check what we've already read */
+ for (e = sdr_list_head; e != NULL; e = e->next) {
+ switch (e->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ if (e->record.common->keys.sensor_num == num &&
+ e->record.common->keys.owner_id == (gen_id & 0x00ff) &&
+ e->record.common->sensor.type == type)
+ return e;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ if (e->record.eventonly->keys.sensor_num == num &&
+ e->record.eventonly->keys.owner_id == (gen_id & 0x00ff) &&
+ e->record.eventonly->sensor_type == type)
+ return e;
+ break;
+ }
+ }
+
+ /* now keep looking */
+ while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
+ uint8_t *rec;
+ struct sdr_record_list *sdrr;
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+ sdrr->id = header->id;
+ sdrr->type = header->type;
+
+ rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
+ if (rec == NULL) {
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.common =
+ (struct sdr_record_common_sensor *) rec;
+ if (sdrr->record.common->keys.sensor_num == num
+ && sdrr->record.common->keys.owner_id == (gen_id & 0x00ff)
+ && sdrr->record.common->sensor.type == type)
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ if (sdrr->record.eventonly->keys.sensor_num == num
+ && sdrr->record.eventonly->keys.owner_id == (gen_id & 0x00ff)
+ && sdrr->record.eventonly->sensor_type == type)
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ /* put in the global record list */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+
+ if (found)
+ return sdrr;
+ }
+
+ return NULL;
+}
+
+/* ipmi_sdr_find_sdr_bysensortype - lookup SDR entry by sensor type
+ *
+ * @intf: ipmi interface
+ * @type: sensor type to search for
+ *
+ * returns pointer to SDR list
+ * returns NULL on error
+ */
+struct sdr_record_list *
+ipmi_sdr_find_sdr_bysensortype(struct ipmi_intf *intf, uint8_t type)
+{
+ struct sdr_record_list *head;
+ struct sdr_get_rs *header;
+ struct sdr_record_list *e;
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = ipmi_sdr_start(intf, 0);
+ if (sdr_list_itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return NULL;
+ }
+ }
+
+ /* check what we've already read */
+ head = malloc(sizeof (struct sdr_record_list));
+ if (head == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+ memset(head, 0, sizeof (struct sdr_record_list));
+
+ for (e = sdr_list_head; e != NULL; e = e->next) {
+ switch (e->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ if (e->record.common->sensor.type == type)
+ __sdr_list_add(head, e);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ if (e->record.eventonly->sensor_type == type)
+ __sdr_list_add(head, e);
+ break;
+ }
+ }
+
+ /* now keep looking */
+ while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
+ uint8_t *rec;
+ struct sdr_record_list *sdrr;
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+ sdrr->id = header->id;
+ sdrr->type = header->type;
+
+ rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
+ if (rec == NULL) {
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.common =
+ (struct sdr_record_common_sensor *) rec;
+ if (sdrr->record.common->sensor.type == type)
+ __sdr_list_add(head, sdrr);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ if (sdrr->record.eventonly->sensor_type == type)
+ __sdr_list_add(head, sdrr);
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ /* put in the global record list */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+ }
+
+ return head;
+}
+
+/* ipmi_sdr_find_sdr_byentity - lookup SDR entry by entity association
+ *
+ * @intf: ipmi interface
+ * @entity: entity id/instance to search for
+ *
+ * returns pointer to SDR list
+ * returns NULL on error
+ */
+struct sdr_record_list *
+ipmi_sdr_find_sdr_byentity(struct ipmi_intf *intf, struct entity_id *entity)
+{
+ struct sdr_get_rs *header;
+ struct sdr_record_list *e;
+ struct sdr_record_list *head;
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = ipmi_sdr_start(intf, 0);
+ if (sdr_list_itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return NULL;
+ }
+ }
+
+ head = malloc(sizeof (struct sdr_record_list));
+ if (head == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+ memset(head, 0, sizeof (struct sdr_record_list));
+
+ /* check what we've already read */
+ for (e = sdr_list_head; e != NULL; e = e->next) {
+ switch (e->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ if (e->record.common->entity.id == entity->id &&
+ (entity->instance == 0x7f ||
+ e->record.common->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, e);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ if (e->record.eventonly->entity.id == entity->id &&
+ (entity->instance == 0x7f ||
+ e->record.eventonly->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, e);
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ if (e->record.genloc->entity.id == entity->id &&
+ (entity->instance == 0x7f ||
+ e->record.genloc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, e);
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ if (e->record.fruloc->entity.id == entity->id &&
+ (entity->instance == 0x7f ||
+ e->record.fruloc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, e);
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ if (e->record.mcloc->entity.id == entity->id &&
+ (entity->instance == 0x7f ||
+ e->record.mcloc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, e);
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ if (e->record.entassoc->entity.id == entity->id &&
+ (entity->instance == 0x7f ||
+ e->record.entassoc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, e);
+ break;
+ }
+ }
+
+ /* now keep looking */
+ while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
+ uint8_t *rec;
+ struct sdr_record_list *sdrr;
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+ sdrr->id = header->id;
+ sdrr->type = header->type;
+
+ rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
+ if (rec == NULL) {
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.common =
+ (struct sdr_record_common_sensor *) rec;
+ if (sdrr->record.common->entity.id == entity->id
+ && (entity->instance == 0x7f
+ || sdrr->record.common->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, sdrr);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ if (sdrr->record.eventonly->entity.id == entity->id
+ && (entity->instance == 0x7f
+ || sdrr->record.eventonly->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, sdrr);
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ if (sdrr->record.genloc->entity.id == entity->id
+ && (entity->instance == 0x7f
+ || sdrr->record.genloc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, sdrr);
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ if (sdrr->record.fruloc->entity.id == entity->id
+ && (entity->instance == 0x7f
+ || sdrr->record.fruloc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, sdrr);
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ if (sdrr->record.mcloc->entity.id == entity->id
+ && (entity->instance == 0x7f
+ || sdrr->record.mcloc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, sdrr);
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ if (sdrr->record.entassoc->entity.id == entity->id
+ && (entity->instance == 0x7f
+ || sdrr->record.entassoc->entity.instance ==
+ entity->instance))
+ __sdr_list_add(head, sdrr);
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ /* add to global record list */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+ }
+
+ return head;
+}
+
+/* ipmi_sdr_find_sdr_bytype - lookup SDR entries by type
+ *
+ * @intf: ipmi interface
+ * @type: type of sensor record to search for
+ *
+ * returns pointer to SDR list with all matching entities
+ * returns NULL on error
+ */
+struct sdr_record_list *
+ipmi_sdr_find_sdr_bytype(struct ipmi_intf *intf, uint8_t type)
+{
+ struct sdr_get_rs *header;
+ struct sdr_record_list *e;
+ struct sdr_record_list *head;
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = ipmi_sdr_start(intf, 0);
+ if (sdr_list_itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return NULL;
+ }
+ }
+
+ head = malloc(sizeof (struct sdr_record_list));
+ if (head == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+ memset(head, 0, sizeof (struct sdr_record_list));
+
+ /* check what we've already read */
+ for (e = sdr_list_head; e != NULL; e = e->next)
+ if (e->type == type)
+ __sdr_list_add(head, e);
+
+ /* now keep looking */
+ while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
+ uint8_t *rec;
+ struct sdr_record_list *sdrr;
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+ sdrr->id = header->id;
+ sdrr->type = header->type;
+
+ rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
+ if (rec == NULL) {
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.common =
+ (struct sdr_record_common_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ if (header->type == type)
+ __sdr_list_add(head, sdrr);
+
+ /* add to global record list */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+ }
+
+ return head;
+}
+
+/* ipmi_sdr_find_sdr_byid - lookup SDR entry by ID string
+ *
+ * @intf: ipmi interface
+ * @id: string to match for sensor name
+ *
+ * returns pointer to SDR list
+ * returns NULL on error
+ */
+struct sdr_record_list *
+ipmi_sdr_find_sdr_byid(struct ipmi_intf *intf, char *id)
+{
+ struct sdr_get_rs *header;
+ struct sdr_record_list *e;
+ int found = 0;
+ int idlen;
+
+ if (id == NULL)
+ return NULL;
+
+ idlen = strlen(id);
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = ipmi_sdr_start(intf, 0);
+ if (sdr_list_itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return NULL;
+ }
+ }
+
+ /* check what we've already read */
+ for (e = sdr_list_head; e != NULL; e = e->next) {
+ switch (e->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ if (!strncmp((const char *)e->record.full->id_string,
+ (const char *)id,
+ __max(e->record.full->id_code & 0x1f, idlen)))
+ return e;
+ break;
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ if (!strncmp((const char *)e->record.compact->id_string,
+ (const char *)id,
+ __max(e->record.compact->id_code & 0x1f, idlen)))
+ return e;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ if (!strncmp((const char *)e->record.eventonly->id_string,
+ (const char *)id,
+ __max(e->record.eventonly->id_code & 0x1f, idlen)))
+ return e;
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ if (!strncmp((const char *)e->record.genloc->id_string,
+ (const char *)id,
+ __max(e->record.genloc->id_code & 0x1f, idlen)))
+ return e;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ if (!strncmp((const char *)e->record.fruloc->id_string,
+ (const char *)id,
+ __max(e->record.fruloc->id_code & 0x1f, idlen)))
+ return e;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ if (!strncmp((const char *)e->record.mcloc->id_string,
+ (const char *)id,
+ __max(e->record.mcloc->id_code & 0x1f, idlen)))
+ return e;
+ break;
+ }
+ }
+
+ /* now keep looking */
+ while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
+ uint8_t *rec;
+ struct sdr_record_list *sdrr;
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+ sdrr->id = header->id;
+ sdrr->type = header->type;
+
+ rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
+ if (rec == NULL) {
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ sdrr->record.full =
+ (struct sdr_record_full_sensor *) rec;
+ if (!strncmp(
+ (const char *)sdrr->record.full->id_string,
+ (const char *)id,
+ __max(sdrr->record.full->id_code & 0x1f, idlen)))
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.compact =
+ (struct sdr_record_compact_sensor *) rec;
+ if (!strncmp(
+ (const char *)sdrr->record.compact->id_string,
+ (const char *)id,
+ __max(sdrr->record.compact->id_code & 0x1f,
+ idlen)))
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ if (!strncmp(
+ (const char *)sdrr->record.eventonly->id_string,
+ (const char *)id,
+ __max(sdrr->record.eventonly->id_code & 0x1f,
+ idlen)))
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ if (!strncmp(
+ (const char *)sdrr->record.genloc->id_string,
+ (const char *)id,
+ __max(sdrr->record.genloc->id_code & 0x1f, idlen)))
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ if (!strncmp(
+ (const char *)sdrr->record.fruloc->id_string,
+ (const char *)id,
+ __max(sdrr->record.fruloc->id_code & 0x1f, idlen)))
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ if (!strncmp(
+ (const char *)sdrr->record.mcloc->id_string,
+ (const char *)id,
+ __max(sdrr->record.mcloc->id_code & 0x1f, idlen)))
+ found = 1;
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ /* add to global record liset */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+
+ if (found)
+ return sdrr;
+ }
+
+ return NULL;
+}
+
+/* ipmi_sdr_list_cache_fromfile - generate SDR cache for fast lookup from local file
+ *
+ * @intf: ipmi interface
+ * @ifile: input filename
+ *
+ * returns pointer to SDR list
+ * returns NULL on error
+ */
+int
+ipmi_sdr_list_cache_fromfile(struct ipmi_intf *intf, const char *ifile)
+{
+ FILE *fp;
+ struct __sdr_header {
+ uint16_t id;
+ uint8_t version;
+ uint8_t type;
+ uint8_t length;
+ } header;
+ struct sdr_record_list *sdrr;
+ uint8_t *rec;
+ int ret = 0, count = 0, bc = 0;
+
+ if (ifile == NULL) {
+ lprintf(LOG_ERR, "No SDR cache filename given");
+ return -1;
+ }
+
+ fp = ipmi_open_file_read(ifile);
+ if (fp == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR cache %s for reading",
+ ifile);
+ return -1;
+ }
+
+ while (feof(fp) == 0) {
+ memset(&header, 0, 5);
+ bc = fread(&header, 1, 5, fp);
+ if (bc <= 0)
+ break;
+
+ if (bc != 5) {
+ lprintf(LOG_ERR, "header read %d bytes, expected 5",
+ bc);
+ ret = -1;
+ break;
+ }
+
+ if (header.length == 0)
+ continue;
+
+ if (header.version != 0x51 &&
+ header.version != 0x01 &&
+ header.version != 0x02) {
+ lprintf(LOG_WARN, "invalid sdr header version %02x",
+ header.version);
+ ret = -1;
+ break;
+ }
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ ret = -1;
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+
+ sdrr->id = header.id;
+ sdrr->type = header.type;
+
+ rec = malloc(header.length + 1);
+ if (rec == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ ret = -1;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ break;
+ }
+ memset(rec, 0, header.length + 1);
+
+ bc = fread(rec, 1, header.length, fp);
+ if (bc != header.length) {
+ lprintf(LOG_ERR,
+ "record %04x read %d bytes, expected %d",
+ header.id, bc, header.length);
+ ret = -1;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ if (rec != NULL) {
+ free(rec);
+ rec = NULL;
+ }
+ break;
+ }
+
+ switch (header.type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.common =
+ (struct sdr_record_common_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ /* add to global record liset */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+
+ count++;
+
+ lprintf(LOG_DEBUG, "Read record %04x from file into cache",
+ sdrr->id);
+ }
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = malloc(sizeof (struct ipmi_sdr_iterator));
+ if (sdr_list_itr != NULL) {
+ sdr_list_itr->reservation = 0;
+ sdr_list_itr->total = count;
+ sdr_list_itr->next = 0xffff;
+ }
+ }
+
+ fclose(fp);
+ return ret;
+}
+
+/* ipmi_sdr_list_cache - generate SDR cache for fast lookup
+ *
+ * @intf: ipmi interface
+ *
+ * returns pointer to SDR list
+ * returns NULL on error
+ */
+int
+ipmi_sdr_list_cache(struct ipmi_intf *intf)
+{
+ struct sdr_get_rs *header;
+
+ if (sdr_list_itr == NULL) {
+ sdr_list_itr = ipmi_sdr_start(intf, 0);
+ if (sdr_list_itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return -1;
+ }
+ }
+
+ while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
+ uint8_t *rec;
+ struct sdr_record_list *sdrr;
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ break;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+ sdrr->id = header->id;
+ sdrr->type = header->type;
+
+ rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
+ if (rec == NULL) {
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ sdrr->record.common =
+ (struct sdr_record_common_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ sdrr->record.eventonly =
+ (struct sdr_record_eventonly_sensor *) rec;
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ sdrr->record.genloc =
+ (struct sdr_record_generic_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ sdrr->record.fruloc =
+ (struct sdr_record_fru_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ sdrr->record.mcloc =
+ (struct sdr_record_mc_locator *) rec;
+ break;
+ case SDR_RECORD_TYPE_ENTITY_ASSOC:
+ sdrr->record.entassoc =
+ (struct sdr_record_entity_assoc *) rec;
+ break;
+ default:
+ free(rec);
+ rec = NULL;
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ continue;
+ }
+
+ /* add to global record liset */
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+ }
+
+ return 0;
+}
+
+/*
+ * ipmi_sdr_get_info
+ *
+ * Execute the GET SDR REPOSITORY INFO command, and populate the sdr_info
+ * structure.
+ * See section 33.9 of the IPMI v2 specification for details
+ *
+ * returns 0 on success
+ * -1 on transport error
+ * > 0 for other errors
+ */
+int
+ipmi_sdr_get_info(struct ipmi_intf *intf,
+ struct get_sdr_repository_info_rsp *sdr_repository_info)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof (req));
+
+ req.msg.netfn = IPMI_NETFN_STORAGE; // 0x0A
+ req.msg.cmd = IPMI_GET_SDR_REPOSITORY_INFO; // 0x20
+ req.msg.data = 0;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get SDR Repository Info command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get SDR Repository Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(sdr_repository_info,
+ rsp->data,
+ __min(sizeof (struct get_sdr_repository_info_rsp),
+ rsp->data_len));
+
+ return 0;
+}
+
+/* ipmi_sdr_timestamp - return string from timestamp value
+ *
+ * @stamp: 32bit timestamp
+ *
+ * returns pointer to static buffer
+ */
+static char *
+ipmi_sdr_timestamp(uint32_t stamp)
+{
+ static char tbuf[40];
+ time_t s = (time_t) stamp;
+ memset(tbuf, 0, 40);
+ if (stamp)
+ strftime(tbuf, sizeof (tbuf), "%m/%d/%Y %H:%M:%S",
+ gmtime(&s));
+ return tbuf;
+}
+
+/*
+ * ipmi_sdr_print_info
+ *
+ * Display the return data of the GET SDR REPOSITORY INFO command
+ * See section 33.9 of the IPMI v2 specification for details
+ *
+ * returns 0 on success
+ * -1 on error
+ */
+int
+ipmi_sdr_print_info(struct ipmi_intf *intf)
+{
+ uint32_t timestamp;
+ uint16_t free_space;
+
+ struct get_sdr_repository_info_rsp sdr_repository_info;
+
+ if (ipmi_sdr_get_info(intf, &sdr_repository_info) != 0)
+ return -1;
+
+ printf("SDR Version : 0x%x\n",
+ sdr_repository_info.sdr_version);
+ printf("Record Count : %d\n",
+ (sdr_repository_info.record_count_msb << 8) |
+ sdr_repository_info.record_count_lsb);
+
+ free_space =
+ (sdr_repository_info.free_space[1] << 8) |
+ sdr_repository_info.free_space[0];
+
+ printf("Free Space : ");
+ switch (free_space) {
+ case 0x0000:
+ printf("none (full)\n");
+ break;
+ case 0xFFFF:
+ printf("unspecified\n");
+ break;
+ case 0xFFFE:
+ printf("> 64Kb - 2 bytes\n");
+ break;
+ default:
+ printf("%d bytes\n", free_space);
+ break;
+ }
+
+ timestamp =
+ (sdr_repository_info.most_recent_addition_timestamp[3] << 24) |
+ (sdr_repository_info.most_recent_addition_timestamp[2] << 16) |
+ (sdr_repository_info.most_recent_addition_timestamp[1] << 8) |
+ sdr_repository_info.most_recent_addition_timestamp[0];
+ printf("Most recent Addition : %s\n",
+ ipmi_sdr_timestamp(timestamp));
+
+ timestamp =
+ (sdr_repository_info.most_recent_erase_timestamp[3] << 24) |
+ (sdr_repository_info.most_recent_erase_timestamp[2] << 16) |
+ (sdr_repository_info.most_recent_erase_timestamp[1] << 8) |
+ sdr_repository_info.most_recent_erase_timestamp[0];
+ printf("Most recent Erase : %s\n",
+ ipmi_sdr_timestamp(timestamp));
+
+ printf("SDR overflow : %s\n",
+ (sdr_repository_info.overflow_flag ? "yes" : "no"));
+
+ printf("SDR Repository Update Support : ");
+ switch (sdr_repository_info.modal_update_support) {
+ case 0:
+ printf("unspecified\n");
+ break;
+ case 1:
+ printf("non-modal\n");
+ break;
+ case 2:
+ printf("modal\n");
+ break;
+ case 3:
+ printf("modal and non-modal\n");
+ break;
+ default:
+ printf("error in response\n");
+ break;
+ }
+
+ printf("Delete SDR supported : %s\n",
+ sdr_repository_info.delete_sdr_supported ? "yes" : "no");
+ printf("Partial Add SDR supported : %s\n",
+ sdr_repository_info.partial_add_sdr_supported ? "yes" : "no");
+ printf("Reserve SDR repository supported : %s\n",
+ sdr_repository_info.
+ reserve_sdr_repository_supported ? "yes" : "no");
+ printf("SDR Repository Alloc info supported : %s\n",
+ sdr_repository_info.
+ get_sdr_repository_allo_info_supported ? "yes" : "no");
+
+ return 0;
+}
+
+/* ipmi_sdr_dump_bin - Write raw SDR to binary file
+ *
+ * used for post-processing by other utilities
+ *
+ * @intf: ipmi interface
+ * @ofile: output filename
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_sdr_dump_bin(struct ipmi_intf *intf, const char *ofile)
+{
+ struct sdr_get_rs *header;
+ struct ipmi_sdr_iterator *itr;
+ struct sdr_record_list *sdrr;
+ FILE *fp;
+ int rc = 0;
+
+ /* open connection to SDR */
+ itr = ipmi_sdr_start(intf, 0);
+ if (itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return -1;
+ }
+
+ printf("Dumping Sensor Data Repository to '%s'\n", ofile);
+
+ /* generate list of records */
+ while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
+ sdrr = malloc(sizeof(struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+ memset(sdrr, 0, sizeof(struct sdr_record_list));
+
+ lprintf(LOG_INFO, "Record ID %04x (%d bytes)",
+ header->id, header->length);
+
+ sdrr->id = header->id;
+ sdrr->version = header->version;
+ sdrr->type = header->type;
+ sdrr->length = header->length;
+ sdrr->raw = ipmi_sdr_get_record(intf, header, itr);
+
+ if (sdrr->raw == NULL) {
+ lprintf(LOG_ERR, "ipmitool: cannot obtain SDR record %04x", header->id);
+ if (sdrr != NULL) {
+ free(sdrr);
+ sdrr = NULL;
+ }
+ return -1;
+ }
+
+ if (sdr_list_head == NULL)
+ sdr_list_head = sdrr;
+ else
+ sdr_list_tail->next = sdrr;
+
+ sdr_list_tail = sdrr;
+ }
+
+ ipmi_sdr_end(intf, itr);
+
+ /* now write to file */
+ fp = ipmi_open_file_write(ofile);
+ if (fp == NULL)
+ return -1;
+
+ for (sdrr = sdr_list_head; sdrr != NULL; sdrr = sdrr->next) {
+ int r;
+ uint8_t h[5];
+
+ /* build and write sdr header */
+ h[0] = sdrr->id & 0xff; // LS Byte first
+ h[1] = (sdrr->id >> 8) & 0xff;
+ h[2] = sdrr->version;
+ h[3] = sdrr->type;
+ h[4] = sdrr->length;
+
+ r = fwrite(h, 1, 5, fp);
+ if (r != 5) {
+ lprintf(LOG_ERR, "Error writing header "
+ "to output file %s", ofile);
+ rc = -1;
+ break;
+ }
+
+ /* write sdr entry */
+ if (!sdrr->raw) {
+ lprintf(LOG_ERR, "Error: raw data is null (length=%d)",
+ sdrr->length);
+ rc = -1;
+ break;
+ }
+ r = fwrite(sdrr->raw, 1, sdrr->length, fp);
+ if (r != sdrr->length) {
+ lprintf(LOG_ERR, "Error writing %d record bytes "
+ "to output file %s", sdrr->length, ofile);
+ rc = -1;
+ break;
+ }
+ }
+ fclose(fp);
+
+ return rc;
+}
+
+/* ipmi_sdr_print_type - print all sensors of specified type
+ *
+ * @intf: ipmi interface
+ * @type: sensor type
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_type(struct ipmi_intf *intf, char *type)
+{
+ struct sdr_record_list *list, *entry;
+ int rc = 0;
+ int x;
+ uint8_t sensor_type = 0;
+
+ if (type == NULL ||
+ strncasecmp(type, "help", 4) == 0 ||
+ strncasecmp(type, "list", 4) == 0) {
+ printf("Sensor Types:\n");
+ for (x = 1; x < SENSOR_TYPE_MAX; x += 2) {
+ printf("\t%-25s (0x%02x) %-25s (0x%02x)\n",
+ sensor_type_desc[x], x,
+ sensor_type_desc[x + 1], x + 1);
+ }
+ return 0;
+ }
+
+ if (strncmp(type, "0x", 2) == 0) {
+ /* begins with 0x so let it be entered as raw hex value */
+ if (str2uchar(type, &sensor_type) != 0) {
+ lprintf(LOG_ERR,
+ "Given type of sensor \"%s\" is either invalid or out of range.",
+ type);
+ return (-1);
+ }
+ } else {
+ for (x = 1; x < SENSOR_TYPE_MAX; x++) {
+ if (strncasecmp(sensor_type_desc[x], type,
+ __maxlen(type,
+ sensor_type_desc[x])) == 0) {
+ sensor_type = x;
+ break;
+ }
+ }
+ if (sensor_type != x) {
+ lprintf(LOG_ERR, "Sensor Type \"%s\" not found.",
+ type);
+ printf("Sensor Types:\n");
+ for (x = 1; x < SENSOR_TYPE_MAX; x += 2) {
+ printf("\t%-25s (0x%02x) %-25s (0x%02x)\n",
+ sensor_type_desc[x], x,
+ sensor_type_desc[x + 1], x + 1);
+ }
+ return 0;
+ }
+ }
+
+ list = ipmi_sdr_find_sdr_bysensortype(intf, sensor_type);
+
+ for (entry = list; entry != NULL; entry = entry->next) {
+ rc = ipmi_sdr_print_listentry(intf, entry);
+ }
+
+ __sdr_list_empty(list);
+
+ return rc;
+}
+
+/* ipmi_sdr_print_entity - print entity's for an id/instance
+ *
+ * @intf: ipmi interface
+ * @entitystr: entity id/instance string, i.e. "1.1"
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_print_entity(struct ipmi_intf *intf, char *entitystr)
+{
+ struct sdr_record_list *list, *entry;
+ struct entity_id entity;
+ unsigned id = 0;
+ unsigned instance = 0;
+ int rc = 0;
+
+ if (entitystr == NULL ||
+ strncasecmp(entitystr, "help", 4) == 0 ||
+ strncasecmp(entitystr, "list", 4) == 0) {
+ print_valstr_2col(entity_id_vals, "Entity IDs", -1);
+ return 0;
+ }
+
+ if (sscanf(entitystr, "%u.%u", &id, &instance) != 2) {
+ /* perhaps no instance was passed
+ * in which case we want all instances for this entity
+ * so set entity.instance = 0x7f to indicate this
+ */
+ if (sscanf(entitystr, "%u", &id) != 1) {
+ int i, j=0;
+
+ /* now try string input */
+ for (i = 0; entity_id_vals[i].str != NULL; i++) {
+ if (strncasecmp(entitystr, entity_id_vals[i].str,
+ __maxlen(entitystr, entity_id_vals[i].str)) == 0) {
+ entity.id = entity_id_vals[i].val;
+ entity.instance = 0x7f;
+ j=1;
+ }
+ }
+ if (j == 0) {
+ lprintf(LOG_ERR, "Invalid entity: %s", entitystr);
+ return -1;
+ }
+ } else {
+ entity.id = id;
+ entity.instance = 0x7f;
+ }
+ } else {
+ entity.id = id;
+ entity.instance = instance;
+ }
+
+ list = ipmi_sdr_find_sdr_byentity(intf, &entity);
+
+ for (entry = list; entry != NULL; entry = entry->next) {
+ rc = ipmi_sdr_print_listentry(intf, entry);
+ }
+
+ __sdr_list_empty(list);
+
+ return rc;
+}
+
+/* ipmi_sdr_print_entry_byid - print sdr entries identified by sensor id
+ *
+ * @intf: ipmi interface
+ * @argc: number of entries to print
+ * @argv: list of sensor ids
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+static int
+ipmi_sdr_print_entry_byid(struct ipmi_intf *intf, int argc, char **argv)
+{
+ struct sdr_record_list *sdr;
+ int rc = 0;
+ int v, i;
+
+ if (argc < 1) {
+ lprintf(LOG_ERR, "No Sensor ID supplied");
+ return -1;
+ }
+
+ v = verbose;
+ verbose = 1;
+
+ for (i = 0; i < argc; i++) {
+ sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
+ if (sdr == NULL) {
+ lprintf(LOG_ERR, "Unable to find sensor id '%s'",
+ argv[i]);
+ } else {
+ if (ipmi_sdr_print_listentry(intf, sdr) < 0)
+ rc = -1;
+ }
+ }
+
+ verbose = v;
+
+ return rc;
+}
+
+/* ipmi_sdr_main - top-level handler for SDR subsystem
+ *
+ * @intf: ipmi interface
+ * @argc: number of arguments
+ * @argv: argument list
+ *
+ * returns 0 on success
+ * returns -1 on error
+ */
+int
+ipmi_sdr_main(struct ipmi_intf *intf, int argc, char **argv)
+{
+ int rc = 0;
+
+ /* initialize random numbers used later */
+ srand(time(NULL));
+
+ if (argc == 0)
+ return ipmi_sdr_print_sdr(intf, 0xfe);
+ else if (strncmp(argv[0], "help", 4) == 0) {
+ printf_sdr_usage();
+ } else if (strncmp(argv[0], "list", 4) == 0
+ || strncmp(argv[0], "elist", 5) == 0) {
+
+ if (strncmp(argv[0], "elist", 5) == 0)
+ sdr_extended = 1;
+ else
+ sdr_extended = 0;
+
+ if (argc <= 1)
+ rc = ipmi_sdr_print_sdr(intf, 0xfe);
+ else if (strncmp(argv[1], "all", 3) == 0)
+ rc = ipmi_sdr_print_sdr(intf, 0xff);
+ else if (strncmp(argv[1], "full", 4) == 0)
+ rc = ipmi_sdr_print_sdr(intf,
+ SDR_RECORD_TYPE_FULL_SENSOR);
+ else if (strncmp(argv[1], "compact", 7) == 0)
+ rc = ipmi_sdr_print_sdr(intf,
+ SDR_RECORD_TYPE_COMPACT_SENSOR);
+ else if (strncmp(argv[1], "event", 5) == 0)
+ rc = ipmi_sdr_print_sdr(intf,
+ SDR_RECORD_TYPE_EVENTONLY_SENSOR);
+ else if (strncmp(argv[1], "mcloc", 5) == 0)
+ rc = ipmi_sdr_print_sdr(intf,
+ SDR_RECORD_TYPE_MC_DEVICE_LOCATOR);
+ else if (strncmp(argv[1], "fru", 3) == 0)
+ rc = ipmi_sdr_print_sdr(intf,
+ SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR);
+ else if (strncmp(argv[1], "generic", 7) == 0)
+ rc = ipmi_sdr_print_sdr(intf,
+ SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
+ else if (strcmp(argv[1], "help") == 0) {
+ lprintf(LOG_NOTICE,
+ "usage: sdr %s [all|full|compact|event|mcloc|fru|generic]",
+ argv[0]);
+ return 0;
+ }
+ else {
+ lprintf(LOG_ERR,
+ "Invalid SDR %s command: %s",
+ argv[0], argv[1]);
+ lprintf(LOG_NOTICE,
+ "usage: sdr %s [all|full|compact|event|mcloc|fru|generic]",
+ argv[0]);
+ return (-1);
+ }
+ } else if (strncmp(argv[0], "type", 4) == 0) {
+ sdr_extended = 1;
+ rc = ipmi_sdr_print_type(intf, argv[1]);
+ } else if (strncmp(argv[0], "entity", 6) == 0) {
+ sdr_extended = 1;
+ rc = ipmi_sdr_print_entity(intf, argv[1]);
+ } else if (strncmp(argv[0], "info", 4) == 0) {
+ rc = ipmi_sdr_print_info(intf);
+ } else if (strncmp(argv[0], "get", 3) == 0) {
+ rc = ipmi_sdr_print_entry_byid(intf, argc - 1, &argv[1]);
+ } else if (strncmp(argv[0], "dump", 4) == 0) {
+ if (argc < 2) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ lprintf(LOG_NOTICE, "usage: sdr dump <file>");
+ return (-1);
+ }
+ rc = ipmi_sdr_dump_bin(intf, argv[1]);
+ } else if (strncmp(argv[0], "fill", 4) == 0) {
+ if (argc <= 1) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ lprintf(LOG_NOTICE, "usage: sdr fill sensors");
+ lprintf(LOG_NOTICE, "usage: sdr fill file <file>");
+ lprintf(LOG_NOTICE, "usage: sdr fill range <range>");
+ return (-1);
+ } else if (strncmp(argv[1], "sensors", 7) == 0) {
+ rc = ipmi_sdr_add_from_sensors(intf, 21);
+ } else if (strncmp(argv[1], "nosat", 5) == 0) {
+ rc = ipmi_sdr_add_from_sensors(intf, 0);
+ } else if (strncmp(argv[1], "file", 4) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_ERR,
+ "Not enough parameters given.");
+ lprintf(LOG_NOTICE,
+ "usage: sdr fill file <file>");
+ return (-1);
+ }
+ rc = ipmi_sdr_add_from_file(intf, argv[2]);
+ } else if (strncmp(argv[1], "range", 4) == 0) {
+ if (argc < 3) {
+ lprintf(LOG_ERR,
+ "Not enough parameters given.");
+ lprintf(LOG_NOTICE,
+ "usage: sdr fill range <range>");
+ return (-1);
+ }
+ rc = ipmi_sdr_add_from_list(intf, argv[2]);
+ } else {
+ lprintf(LOG_ERR,
+ "Invalid SDR %s command: %s",
+ argv[0], argv[1]);
+ lprintf(LOG_NOTICE,
+ "usage: sdr %s <sensors|nosat|file|range> [options]",
+ argv[0]);
+ return (-1);
+ }
+ } else {
+ lprintf(LOG_ERR, "Invalid SDR command: %s", argv[0]);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+void
+printf_sdr_usage()
+{
+ lprintf(LOG_NOTICE,
+"usage: sdr <command> [options]");
+ lprintf(LOG_NOTICE,
+" list | elist [option]");
+ lprintf(LOG_NOTICE,
+" all All SDR Records");
+ lprintf(LOG_NOTICE,
+" full Full Sensor Record");
+ lprintf(LOG_NOTICE,
+" compact Compact Sensor Record");
+ lprintf(LOG_NOTICE,
+" event Event-Only Sensor Record");
+ lprintf(LOG_NOTICE,
+" mcloc Management Controller Locator Record");
+ lprintf(LOG_NOTICE,
+" fru FRU Locator Record");
+ lprintf(LOG_NOTICE,
+" generic Generic Device Locator Record\n");
+ lprintf(LOG_NOTICE,
+" type [option]");
+ lprintf(LOG_NOTICE,
+" <Sensor_Type> Retrieve the state of specified sensor.");
+ lprintf(LOG_NOTICE,
+" Sensor_Type can be specified either as");
+ lprintf(LOG_NOTICE,
+" a string or a hex value.");
+ lprintf(LOG_NOTICE,
+" list Get a list of available sensor types\n");
+ lprintf(LOG_NOTICE,
+" get <Sensor_ID>");
+ lprintf(LOG_NOTICE,
+" Retrieve state of the first sensor matched by Sensor_ID\n");
+ lprintf(LOG_NOTICE,
+" info");
+ lprintf(LOG_NOTICE,
+" Display information about the repository itself\n");
+ lprintf(LOG_NOTICE,
+" entity <Entity_ID>[.<Instance_ID>]");
+ lprintf(LOG_NOTICE,
+" Display all sensors associated with an entity\n");
+ lprintf(LOG_NOTICE,
+" dump <file>");
+ lprintf(LOG_NOTICE,
+" Dump raw SDR data to a file\n");
+ lprintf(LOG_NOTICE,
+" fill <option>");
+ lprintf(LOG_NOTICE,
+" sensors Creates the SDR repository for the current");
+ lprintf(LOG_NOTICE,
+" configuration");
+ lprintf(LOG_NOTICE,
+" nosat Creates the SDR repository for the current");
+ lprintf(LOG_NOTICE,
+" configuration, without satellite scan");
+ lprintf(LOG_NOTICE,
+" file <file> Load SDR repository from a file");
+ lprintf(LOG_NOTICE,
+" range <range> Load SDR repository from a provided list");
+ lprintf(LOG_NOTICE,
+" or range. Use ',' for list or '-' for");
+ lprintf(LOG_NOTICE,
+" range, eg. 0x28,0x32,0x40-0x44");
+}
diff --git a/lib/ipmi_sdradd.c b/lib/ipmi_sdradd.c
new file mode 100644
index 0000000..f3bc271
--- /dev/null
+++ b/lib/ipmi_sdradd.c
@@ -0,0 +1,668 @@
+/*
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/*
+ * Functions to program the SDR repository, from built-in sensors or
+ * from sensors dumped in a binary file.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/bswap.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_strings.h>
+
+#include <ipmitool/ipmi_sdr.h>
+
+
+#define ADD_PARTIAL_SDR 0x25
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+struct sdr_add_rq {
+ uint16_t reserve_id; /* reservation ID */
+ uint16_t id; /* record ID */
+ uint8_t offset; /* offset into SDR */
+ uint8_t in_progress; /* 0=partial, 1=last */
+#define PARTIAL_ADD (0)
+#define LAST_RECORD (1)
+ uint8_t data[1]; /* SDR record data */
+} ATTRIBUTE_PACKING;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(0)
+#endif
+
+/* This was formerly initialized to 24, reduced this to 19 so the overall
+ message fits into the recommended 32-byte limit */
+static int sdr_max_write_len = 19;
+int ipmi_parse_range_list(const char *rangeList, unsigned char *pHexList);
+int ipmi_hex_to_dec( char * rangeList, unsigned char * pDecValue);
+
+static int
+partial_send(struct ipmi_intf *intf, struct ipmi_rq *req, uint16_t *id)
+{
+ struct ipmi_rs *rsp;
+ rsp = intf->sendrecv(intf, req);
+ if (rsp == NULL) {
+ return -1;
+ }
+
+ if (rsp->ccode || rsp->data_len < 2) {
+ return -1;
+ }
+
+ *id = rsp->data[0] + (rsp->data[1] << 8);
+ return 0;
+}
+
+int
+ipmi_sdr_add_record(struct ipmi_intf *intf, struct sdr_record_list *sdrr)
+{
+ struct ipmi_rq req;
+ struct sdr_add_rq *sdr_rq;
+ uint16_t reserve_id;
+ uint16_t id;
+ int i;
+ int len = sdrr->length;
+ int rc = 0;
+
+ /* actually no SDR to program */
+ if (len < 1 || !sdrr->raw) {
+ lprintf(LOG_ERR, "ipmitool: bad record , skipped");
+ return 0;
+ }
+
+ if (ipmi_sdr_get_reservation(intf, 0, &reserve_id)) {
+ lprintf(LOG_ERR, "ipmitool: reservation failed");
+ return -1;
+ }
+
+ sdr_rq = (struct sdr_add_rq *)malloc(sizeof(*sdr_rq) + sdr_max_write_len);
+ if (sdr_rq == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+ sdr_rq->reserve_id = reserve_id;
+ sdr_rq->in_progress = PARTIAL_ADD;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = ADD_PARTIAL_SDR;
+ req.msg.data = (uint8_t *) sdr_rq;
+
+ /* header first */
+ sdr_rq->id = 0;
+ sdr_rq->offset = 0;
+ sdr_rq->data[0] = sdrr->id & 0xFF;
+ sdr_rq->data[1] = (sdrr->id >> 8) & 0xFF;
+ sdr_rq->data[2] = sdrr->version;
+ sdr_rq->data[3] = sdrr->type;
+ sdr_rq->data[4] = sdrr->length;
+ req.msg.data_len = 5 + sizeof(*sdr_rq) - 1;
+
+ if (partial_send(intf, &req, &id)) {
+ lprintf(LOG_ERR, "ipmitool: partial send error");
+ free(sdr_rq);
+ sdr_rq = NULL;
+ return -1;
+ }
+
+ i = 0;
+
+ /* sdr entry */
+ while (i < len) {
+ int data_len = 0;
+ if ( (len - i) <= sdr_max_write_len) {
+ /* last crunch */
+ data_len = len - i;
+ sdr_rq->in_progress = LAST_RECORD;
+ } else {
+ data_len = sdr_max_write_len;
+ }
+
+ sdr_rq->id = id;
+ sdr_rq->offset = i + 5;
+ memcpy(sdr_rq->data, sdrr->raw + i, data_len);
+ req.msg.data_len = data_len + sizeof(*sdr_rq) - 1;
+
+ if ((rc = partial_send(intf, &req, &id)) != 0) {
+ lprintf(LOG_ERR, "ipmitool: partial add failed");
+ break;
+ }
+
+ i += data_len;
+ }
+
+ free(sdr_rq);
+ sdr_rq = NULL;
+ return rc;
+}
+
+static int
+ipmi_sdr_repo_clear(struct ipmi_intf *intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[8];
+ uint16_t reserve_id;
+ int try;
+
+ if (ipmi_sdr_get_reservation(intf, 0, &reserve_id))
+ return -1;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = 0x27; // FIXME
+ req.msg.data = msg_data;
+ req.msg.data_len = 6;
+
+ msg_data[0] = reserve_id & 0xFF;
+ msg_data[1] = reserve_id >> 8;
+ msg_data[2] = 'C';
+ msg_data[3] = 'L';
+ msg_data[4] = 'R';
+ msg_data[5] = 0xAA;
+
+ for (try = 0; try < 5; try++) {
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to clear SDRR");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Unable to clear SDRR: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ if ((rsp->data[0] & 1) == 1) {
+ printf("SDRR successfully erased\n");
+ return 0;
+ }
+ printf("Wait for SDRR erasure completed...\n");
+ msg_data[5] = 0;
+ sleep(1);
+ }
+
+ /* if we are here we fed up trying erase */
+ return -1;
+}
+
+
+struct sdrr_queue {
+ struct sdr_record_list *head;
+ struct sdr_record_list *tail;
+};
+
+
+/*
+ * Fill the SDR repository from built-in sensors
+ *
+ */
+
+/*
+ * Get all the SDR records stored in <queue>
+ */
+static int
+sdrr_get_records(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr,
+ struct sdrr_queue *queue)
+{
+ struct sdr_get_rs *header;
+
+ queue->head = NULL;
+ queue->tail = NULL;
+
+ while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
+ struct sdr_record_list *sdrr;
+
+ sdrr = malloc(sizeof (struct sdr_record_list));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+ memset(sdrr, 0, sizeof (struct sdr_record_list));
+
+ sdrr->id = header->id;
+ sdrr->version = header->version;
+ sdrr->type = header->type;
+ sdrr->length = header->length;
+ sdrr->raw = ipmi_sdr_get_record(intf, header, itr);
+ (void)ipmi_sdr_print_name_from_rawentry(intf, sdrr->id, sdrr->type,sdrr->raw);
+
+ /* put in the record queue */
+ if (queue->head == NULL)
+ queue->head = sdrr;
+ else
+ queue->tail->next = sdrr;
+ queue->tail = sdrr;
+ }
+ return 0;
+}
+
+static int
+sdr_copy_to_sdrr(struct ipmi_intf *intf, int use_builtin,
+ int from_addr, int to_addr)
+{
+ int rc;
+ struct sdrr_queue sdrr_queue;
+ struct ipmi_sdr_iterator *itr;
+ struct sdr_record_list *sdrr;
+ struct sdr_record_list *sdrr_next;
+
+ /* generate list of records for this target */
+ intf->target_addr = from_addr;
+
+ /* initialize iterator */
+ itr = ipmi_sdr_start(intf, use_builtin);
+ if (itr == 0)
+ return 0;
+
+ printf("Load SDRs from 0x%x\n", from_addr);
+ rc = sdrr_get_records(intf, itr, &sdrr_queue);
+ ipmi_sdr_end(intf, itr);
+ /* ... */
+
+ /* write the SDRs to the destination SDR Repository */
+ intf->target_addr = to_addr;
+ for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) {
+ sdrr_next = sdrr->next;
+ rc = ipmi_sdr_add_record(intf, sdrr);
+ if(rc < 0){
+ lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id);
+ }
+ free(sdrr);
+ sdrr = NULL;
+ }
+ return rc;
+}
+
+int
+ipmi_sdr_add_from_sensors(struct ipmi_intf *intf, int maxslot)
+{
+ int i;
+ int rc = 0;
+ int slave_addr;
+ int myaddr = intf->target_addr;
+
+ if (ipmi_sdr_repo_clear(intf)) {
+ lprintf(LOG_ERR, "Cannot erase SDRR. Give up.");
+ return -1;
+ }
+
+ /* First fill the SDRR from local built-in sensors */
+ rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr);
+
+ /* Now fill the SDRR with remote sensors */
+ if( maxslot != 0 ) {
+ for (i = 0, slave_addr = 0xB0; i < maxslot; i++, slave_addr += 2) {
+ /* Hole in the PICMG 2.9 mapping */
+ if (slave_addr == 0xC2) slave_addr += 2;
+ if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0)
+ {
+ rc = -1;
+ }
+ }
+ }
+ return rc;
+}
+
+int ipmi_hex_to_dec( char * strchar, unsigned char * pDecValue)
+{
+ int rc = -1;
+ unsigned char retValue = 0;
+
+ if(
+ (strlen(strchar) == 4)
+ &&
+ (strchar[0] == '0')
+ &&
+ (strchar[1] == 'x')
+ )
+ {
+ rc = 0;
+
+ if((strchar[2] >= '0') && (strchar[2] <= '9'))
+ {
+ retValue += ((strchar[2]-'0') * 16);
+ }
+ else if((strchar[2] >= 'a') && (strchar[2] <= 'f'))
+ {
+ retValue += (((strchar[2]-'a') + 10) * 16);
+ }
+ else if((strchar[2] >= 'A') && (strchar[2] <= 'F'))
+ {
+ retValue += (((strchar[2]-'A') + 10) * 16);
+ }
+ else
+ {
+ rc = -1;
+ }
+
+ if((strchar[3] >= '0') && (strchar[3] <= '9'))
+ {
+ retValue += ((strchar[3]-'0'));
+ }
+ else if((strchar[3] >= 'a') && (strchar[3] <= 'f'))
+ {
+ retValue += (((strchar[3]-'a') + 10));
+ }
+ else if((strchar[3] >= 'A') && (strchar[3] <= 'F'))
+ {
+ retValue += (((strchar[3]-'A') + 10));
+ }
+ else
+ {
+ rc = -1;
+ }
+ }
+
+ if(rc == 0)
+ {
+ * pDecValue = retValue;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Must be Hex value of 4 characters (Ex.: 0x24)");
+ }
+
+ return rc;
+}
+
+
+
+#define MAX_NUM_SLOT 128
+int ipmi_parse_range_list(const char *rangeList, unsigned char * pHexList)
+{
+ int rc = -1;
+
+ unsigned char listOffset = 0;
+ char * nextString;
+ char * rangeString;
+ char * inProcessString = (char *) rangeList;
+
+ /* Discard empty string */
+ if(strlen(rangeList) == 0)
+ {
+ return rc;
+ }
+
+ /* First, cut to comma separated string */
+ nextString = strstr( rangeList, "," );
+
+ if(nextString != rangeList)
+ {
+ unsigned char isLast;
+ /* We get a valid string so far */
+ rc = 0;
+
+ do
+ {
+ if(nextString != NULL)
+ {
+ (*nextString)= 0;
+ nextString ++;
+ isLast = 0;
+ }
+ else
+ {
+ isLast = 1;
+ }
+
+ /* At this point, it is a single entry or a range */
+ rangeString = strstr( inProcessString, "-" );
+ if(rangeString == NULL)
+ {
+ unsigned char decValue = 0;
+
+ /* Single entry */
+ rc = ipmi_hex_to_dec( inProcessString, &decValue);
+
+ if(rc == 0)
+ {
+ if((decValue % 2) == 0)
+ {
+ pHexList[listOffset++] = decValue;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "I2C address provided value must be even.");
+ }
+ }
+ }
+ else
+ {
+ unsigned char startValue = 0;
+ unsigned char endValue = 0;
+
+
+ (*rangeString)= 0; /* Cut string*/
+ rangeString ++;
+
+ /* Range */
+ rc = ipmi_hex_to_dec( inProcessString, &startValue);
+ if(rc == 0)
+ rc = ipmi_hex_to_dec( rangeString, &endValue);
+
+ if(rc == 0)
+ {
+ if(((startValue % 2) == 0) && ((endValue % 2) == 0))
+ {
+ do
+ {
+ pHexList[listOffset++] = startValue;
+ startValue += 2;
+ }
+ while(startValue != endValue);
+ pHexList[listOffset++] = endValue;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "I2C address provided value must be even.");
+ }
+ }
+ }
+
+ if(isLast == 0)
+ {
+ /* Setup for next string */
+ inProcessString = nextString;
+ nextString = strstr( rangeList, "," );
+ }
+ }while ((isLast == 0) && (rc == 0));
+ }
+
+ return rc;
+}
+
+int
+ipmi_sdr_add_from_list(struct ipmi_intf *intf, const char *rangeList)
+{
+ int i;
+ int rc = 0;
+ int slave_addr;
+ int myaddr = intf->target_addr;
+ unsigned char listValue[MAX_NUM_SLOT];
+
+ memset( listValue, 0, MAX_NUM_SLOT );
+
+ /* Build list from string */
+ if(ipmi_parse_range_list(rangeList, listValue) != 0)
+ {
+ lprintf(LOG_ERR, "Range - List invalid, cannot be parsed.");
+ return -1;
+ }
+
+ {
+ unsigned char counter = 0;
+ printf("List to scan: (Built-in) ");
+ while(listValue[counter] != 0)
+ {
+ printf("%02x ", listValue[counter]);
+ counter++;
+ }
+ printf("\n");
+ }
+
+ printf("Clearing SDR Repository\n");
+ if (ipmi_sdr_repo_clear(intf)) {
+ lprintf(LOG_ERR, "Cannot erase SDRR. Give up.");
+ return -1;
+ }
+
+ /* First fill the SDRR from local built-in sensors */
+ printf("Sanning built-in sensors..\n");
+ rc = sdr_copy_to_sdrr(intf, 1, myaddr, myaddr);
+
+ /* Now fill the SDRR with provided sensors list */
+ {
+ unsigned char counter = 0;
+ while((rc == 0) && (listValue[counter] != 0))
+ {
+ slave_addr = listValue[counter];
+ printf("Scanning %02Xh..\n", slave_addr);
+ if(sdr_copy_to_sdrr(intf, 0, slave_addr, myaddr) < 0)
+ {
+ rc = -1;
+ }
+ counter++;
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * Fill the SDR repository from records stored in a binary file
+ *
+ */
+
+static int
+ipmi_sdr_read_records(const char *filename, struct sdrr_queue *queue)
+{
+ struct sdr_get_rs header;
+ int rc = 0;
+ int fd;
+ uint8_t binHdr[5];
+
+ queue->head = NULL;
+ queue->tail = NULL;
+
+ if ((fd = open(filename, O_RDONLY)) < 0) {
+ return -1;
+ }
+
+ while (read(fd, binHdr, 5) == 5) {
+
+ struct sdr_record_list *sdrr;
+
+ lprintf(LOG_DEBUG, "binHdr[0] (id[MSB]) = 0x%02x", binHdr[0]);
+ lprintf(LOG_DEBUG, "binHdr[1] (id[LSB]) = 0x%02x", binHdr[1]);
+ lprintf(LOG_DEBUG, "binHdr[2] (version) = 0x%02x", binHdr[2]);
+ lprintf(LOG_DEBUG, "binHdr[3] (type) = 0x%02x", binHdr[3]);
+ lprintf(LOG_DEBUG, "binHdr[4] (length) = 0x%02x", binHdr[4]);
+
+ sdrr = malloc(sizeof(*sdrr));
+ if (sdrr == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ rc = -1;
+ break;
+ }
+ sdrr->id = (binHdr[1] << 8) | binHdr[0]; // LS Byte first
+ sdrr->version = binHdr[2];
+ sdrr->type = binHdr[3];
+ sdrr->length = binHdr[4];
+
+ if ((sdrr->raw = malloc(sdrr->length)) == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ free(sdrr);
+ sdrr = NULL;
+ rc = -1;
+ break;
+ }
+
+ if (read(fd, sdrr->raw, sdrr->length) != sdrr->length) {
+ lprintf(LOG_ERR, "SDR from '%s' truncated", filename);
+ free(sdrr->raw);
+ sdrr->raw = NULL;
+ free(sdrr);
+ sdrr = NULL;
+ rc = -1;
+ break;
+ }
+
+ /* put in the record queue */
+ if (queue->head == NULL)
+ queue->head = sdrr;
+ else
+ queue->tail->next = sdrr;
+ queue->tail = sdrr;
+ }
+ return rc;
+}
+
+int
+ipmi_sdr_add_from_file(struct ipmi_intf *intf, const char *ifile)
+{
+ int rc;
+ struct sdrr_queue sdrr_queue;
+ struct sdr_record_list *sdrr;
+ struct sdr_record_list *sdrr_next;
+
+ /* read the SDR records from file */
+ rc = ipmi_sdr_read_records(ifile, &sdrr_queue);
+
+ if (ipmi_sdr_repo_clear(intf)) {
+ lprintf(LOG_ERR, "Cannot erase SDRR. Giving up.");
+ /* FIXME: free sdr list */
+ return -1;
+ }
+
+ /* write the SDRs to the SDR Repository */
+ for (sdrr = sdrr_queue.head; sdrr != NULL; sdrr = sdrr_next) {
+ sdrr_next = sdrr->next;
+ rc = ipmi_sdr_add_record(intf, sdrr);
+ if(rc < 0){
+ lprintf(LOG_ERR, "Cannot add SDR ID 0x%04x to repository...", sdrr->id);
+ }
+ free(sdrr);
+ sdrr = NULL;
+ }
+ return rc;
+}
+
diff --git a/lib/ipmi_sel.c b/lib/ipmi_sel.c
new file mode 100644
index 0000000..21ce0c4
--- /dev/null
+++ b/lib/ipmi_sel.c
@@ -0,0 +1,3094 @@
+/* -*-mode: C; indent-tabs-mode: t; -*-
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+#include <math.h>
+#define __USE_XOPEN /* glibc2 needs this for strptime */
+#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_mc.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_fru.h>
+#include <ipmitool/ipmi_sensor.h>
+
+extern int verbose;
+static int sel_extended = 0;
+static int sel_oem_nrecs = 0;
+
+static IPMI_OEM sel_iana = IPMI_OEM_UNKNOWN;
+
+struct ipmi_sel_oem_msg_rec {
+ int value[14];
+ char *string[14];
+ char *text;
+} *sel_oem_msg;
+
+#define SEL_BYTE(n) (n-3) /* So we can refer to byte positions in log entries (byte 3 is at index 0, etc) */
+
+// Definiation for the Decoding the SEL OEM Bytes for DELL Platfoms
+#define BIT(x) (1 << x) /* Select the Bit */
+#define SIZE_OF_DESC 128 /* Max Size of the description String to be displyed for the Each sel entry */
+#define MAX_CARDNO_STR 32 /* Max Size of Card number string */
+#define MAX_DIMM_STR 32 /* Max Size of DIMM string */
+#define MAX_CARD_STR 32 /* Max Size of Card string */
+/*
+ * Reads values found in message translation file. XX is a wildcard, R means reserved.
+ * Returns -1 for XX, -2 for R, -3 for non-hex (string), or positive integer from a hex value.
+ */
+static int ipmi_sel_oem_readval(char *str)
+{
+ int ret;
+ if (!strcmp(str, "XX")) {
+ return -1;
+ }
+ if (!strcmp(str, "R")) {
+ return -2;
+ }
+ if (sscanf(str, "0x%x", &ret) != 1) {
+ return -3;
+ }
+ return ret;
+}
+
+/*
+ * This is where the magic happens. SEL_BYTE is a bit ugly, but it allows
+ * reference to byte positions instead of array indexes which (hopefully)
+ * helps make the code easier to read.
+ */
+static int ipmi_sel_oem_match(uint8_t *evt, struct ipmi_sel_oem_msg_rec rec)
+{
+ if (evt[2] == rec.value[SEL_BYTE(3)] &&
+ ((rec.value[SEL_BYTE(4)] < 0) || (evt[3] == rec.value[SEL_BYTE(4)])) &&
+ ((rec.value[SEL_BYTE(5)] < 0) || (evt[4] == rec.value[SEL_BYTE(5)])) &&
+ ((rec.value[SEL_BYTE(6)] < 0) || (evt[5] == rec.value[SEL_BYTE(6)])) &&
+ ((rec.value[SEL_BYTE(7)] < 0) || (evt[6] == rec.value[SEL_BYTE(7)])) &&
+ ((rec.value[SEL_BYTE(11)] < 0) || (evt[10] == rec.value[SEL_BYTE(11)])) &&
+ ((rec.value[SEL_BYTE(12)] < 0) || (evt[11] == rec.value[SEL_BYTE(12)]))) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int ipmi_sel_oem_init(const char * filename)
+{
+ FILE * fp;
+ int i, j, k, n, byte;
+ char buf[15][150];
+
+ if (filename == NULL) {
+ lprintf(LOG_ERR, "No SEL OEM filename provided");
+ return -1;
+ }
+
+ fp = ipmi_open_file_read(filename);
+ if (fp == NULL) {
+ lprintf(LOG_ERR, "Could not open %s file", filename);
+ return -1;
+ }
+
+ /* count number of records (lines) in input file */
+ sel_oem_nrecs = 0;
+ while (fscanf(fp, "%*[^\n]\n") == 0) {
+ sel_oem_nrecs++;
+ }
+
+ printf("nrecs=%d\n", sel_oem_nrecs);
+
+ rewind(fp);
+ sel_oem_msg = (struct ipmi_sel_oem_msg_rec *)calloc(sel_oem_nrecs,
+ sizeof(struct ipmi_sel_oem_msg_rec));
+
+ for (i=0; i < sel_oem_nrecs; i++) {
+ n=fscanf(fp, "\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\""
+ "%[^\"]\",\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\""
+ "%[^\"]\",\"%[^\"]\",\"%[^\"]\",\"%[^\"]\",\""
+ "%[^\"]\",\"%[^\"]\",\"%[^\"]\"\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+ buf[6], buf[7], buf[8], buf[9], buf[10], buf[11],
+ buf[12], buf[13], buf[14]);
+
+ if (n != 15) {
+ lprintf (LOG_ERR, "Encountered problems reading line %d of %s",
+ i+1, filename);
+ fclose(fp);
+ fp = NULL;
+ sel_oem_nrecs = 0;
+ /* free all the memory allocated so far */
+ for (j=0; j<i ; j++) {
+ for (k=3; k<17; k++) {
+ if (sel_oem_msg[j].value[SEL_BYTE(k)] == -3) {
+ free(sel_oem_msg[j].string[SEL_BYTE(k)]);
+ sel_oem_msg[j].string[SEL_BYTE(k)] = NULL;
+ }
+ }
+ }
+ free(sel_oem_msg);
+ sel_oem_msg = NULL;
+ return -1;
+ }
+
+ for (byte = 3; byte < 17; byte++) {
+ if ((sel_oem_msg[i].value[SEL_BYTE(byte)] =
+ ipmi_sel_oem_readval(buf[SEL_BYTE(byte)])) == -3) {
+ sel_oem_msg[i].string[SEL_BYTE(byte)] =
+ (char *)malloc(strlen(buf[SEL_BYTE(byte)]) + 1);
+ strcpy(sel_oem_msg[i].string[SEL_BYTE(byte)],
+ buf[SEL_BYTE(byte)]);
+ }
+ }
+ sel_oem_msg[i].text = (char *)malloc(strlen(buf[SEL_BYTE(17)]) + 1);
+ strcpy(sel_oem_msg[i].text, buf[SEL_BYTE(17)]);
+ }
+
+ fclose(fp);
+ fp = NULL;
+ return 0;
+}
+
+static void ipmi_sel_oem_message(struct sel_event_record * evt, int verbose)
+{
+ /*
+ * Note: although we have a verbose argument, currently the output
+ * isn't affected by it.
+ */
+ int i, j;
+
+ for (i=0; i < sel_oem_nrecs; i++) {
+ if (ipmi_sel_oem_match((uint8_t *)evt, sel_oem_msg[i])) {
+ printf (csv_output ? ",\"%s\"" : " | %s", sel_oem_msg[i].text);
+ for (j=4; j<17; j++) {
+ if (sel_oem_msg[i].value[SEL_BYTE(j)] == -3) {
+ printf (csv_output ? ",%s=0x%x" : " %s = 0x%x",
+ sel_oem_msg[i].string[SEL_BYTE(j)],
+ ((uint8_t *)evt)[SEL_BYTE(j)]);
+ }
+ }
+ }
+ }
+}
+
+static const struct valstr event_dir_vals[] = {
+ { 0, "Assertion Event" },
+ { 1, "Deassertion Event" },
+ { 0, NULL },
+};
+
+static const char *
+ipmi_get_event_type(uint8_t code)
+{
+ if (code == 0)
+ return "Unspecified";
+ if (code == 1)
+ return "Threshold";
+ if (code >= 0x02 && code <= 0x0b)
+ return "Generic Discrete";
+ if (code == 0x6f)
+ return "Sensor-specific Discrete";
+ if (code >= 0x70 && code <= 0x7f)
+ return "OEM";
+ return "Reserved";
+}
+
+static char *
+ipmi_sel_timestamp(uint32_t stamp)
+{
+ static char tbuf[40];
+ time_t s = (time_t)stamp;
+ memset(tbuf, 0, 40);
+ strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&s));
+ return tbuf;
+}
+
+static char *
+ipmi_sel_timestamp_date(uint32_t stamp)
+{
+ static char tbuf[11];
+ time_t s = (time_t)stamp;
+ strftime(tbuf, sizeof(tbuf), "%m/%d/%Y", gmtime(&s));
+ return tbuf;
+}
+
+static char *
+ipmi_sel_timestamp_time(uint32_t stamp)
+{
+ static char tbuf[9];
+ time_t s = (time_t)stamp;
+ strftime(tbuf, sizeof(tbuf), "%H:%M:%S", gmtime(&s));
+ return tbuf;
+}
+
+static char *
+hex2ascii (uint8_t * hexChars, uint8_t numBytes)
+{
+ int count;
+ static char hexString[SEL_OEM_NOTS_DATA_LEN+1]; /*Max Size*/
+
+ if(numBytes > SEL_OEM_NOTS_DATA_LEN)
+ numBytes = SEL_OEM_NOTS_DATA_LEN;
+
+ for(count=0;count < numBytes;count++)
+ {
+ if((hexChars[count]<0x40)||(hexChars[count]>0x7e))
+ hexString[count]='.';
+ else
+ hexString[count]=hexChars[count];
+ }
+ hexString[numBytes]='\0';
+ return hexString;
+}
+
+IPMI_OEM
+ipmi_get_oem(struct ipmi_intf * intf)
+{
+ /* Execute a Get Device ID command to determine the OEM */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct ipm_devid_rsp *devid;
+
+ if (intf->fd == 0) {
+ if( sel_iana != IPMI_OEM_UNKNOWN ){
+ return sel_iana;
+ }
+ return IPMI_OEM_UNKNOWN;
+ }
+
+ /*
+ * Return the cached manufacturer id if the device is open and
+ * we got an identified OEM owner. Otherwise just attempt to read
+ * it.
+ */
+ if (intf->opened && intf->manufacturer_id != IPMI_OEM_UNKNOWN) {
+ return intf->manufacturer_id;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get Device ID command failed");
+ return IPMI_OEM_UNKNOWN;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get Device ID command failed: %#x %s",
+ rsp->ccode, val2str(rsp->ccode, completion_code_vals));
+ return IPMI_OEM_UNKNOWN;
+ }
+
+ devid = (struct ipm_devid_rsp *) rsp->data;
+
+ lprintf(LOG_DEBUG,"Iana: %u",
+ IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id));
+
+ return IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id);
+}
+
+static int
+ipmi_sel_add_entry(struct ipmi_intf * intf, struct sel_event_record * rec)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_ADD_SEL_ENTRY;
+ req.msg.data = (unsigned char *)rec;
+ req.msg.data_len = 16;
+
+ ipmi_sel_print_std_entry(intf, rec);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Add SEL Entry failed");
+ return -1;
+ }
+ else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Add SEL Entry failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+ipmi_sel_add_entries_fromfile(struct ipmi_intf * intf, const char * filename)
+{
+ FILE * fp;
+ char buf[1024];
+ char * ptr, * tok;
+ int i, j;
+ int rc = 0;
+ uint8_t rqdata[8];
+ struct sel_event_record sel_event;
+
+ if (filename == NULL)
+ return -1;
+
+ fp = ipmi_open_file_read(filename);
+ if (fp == NULL)
+ return -1;
+
+ while (feof(fp) == 0) {
+ if (fgets(buf, 1024, fp) == NULL)
+ continue;
+
+ /* clip off optional comment tail indicated by # */
+ ptr = strchr(buf, '#');
+ if (ptr)
+ *ptr = '\0';
+ else
+ ptr = buf + strlen(buf);
+
+ /* clip off trailing and leading whitespace */
+ ptr--;
+ while (isspace((int)*ptr) && ptr >= buf)
+ *ptr-- = '\0';
+ ptr = buf;
+ while (isspace((int)*ptr))
+ ptr++;
+ if (strlen(ptr) == 0)
+ continue;
+
+ /* parse the event, 7 bytes with optional comment */
+ /* 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # event */
+ i = 0;
+ tok = strtok(ptr, " ");
+ while (tok) {
+ if (i == 7)
+ break;
+ j = i++;
+ if (str2uchar(tok, &rqdata[j]) != 0) {
+ break;
+ }
+ tok = strtok(NULL, " ");
+ }
+ if (i < 7) {
+ lprintf(LOG_ERR, "Invalid Event: %s",
+ buf2str(rqdata, sizeof(rqdata)));
+ continue;
+ }
+
+ memset(&sel_event, 0, sizeof(struct sel_event_record));
+ sel_event.record_id = 0x0000;
+ sel_event.record_type = 0x02;
+ sel_event.sel_type.standard_type.gen_id = 0x00;
+ sel_event.sel_type.standard_type.evm_rev = rqdata[0];
+ sel_event.sel_type.standard_type.sensor_type = rqdata[1];
+ sel_event.sel_type.standard_type.sensor_num = rqdata[2];
+ sel_event.sel_type.standard_type.event_type = rqdata[3] & 0x7f;
+ sel_event.sel_type.standard_type.event_dir = (rqdata[3] & 0x80) >> 7;
+ sel_event.sel_type.standard_type.event_data[0] = rqdata[4];
+ sel_event.sel_type.standard_type.event_data[1] = rqdata[5];
+ sel_event.sel_type.standard_type.event_data[2] = rqdata[6];
+
+ rc = ipmi_sel_add_entry(intf, &sel_event);
+ if (rc < 0)
+ break;
+ }
+
+ fclose(fp);
+ return rc;
+}
+
+static struct ipmi_event_sensor_types oem_kontron_event_reading_types[] __attribute__((unused)) = {
+ { 0x70 , 0x00 , 0xff, IPMI_EVENT_CLASS_DISCRETE , "OEM Firmware Info 1", "Code Assert" },
+ { 0x71 , 0x00 , 0xff, IPMI_EVENT_CLASS_DISCRETE , "OEM Firmware Info 2", "Code Assert" },
+};
+
+char *
+get_kontron_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
+{
+ char * description = NULL;
+ /*
+ * Kontron OEM events are described in the product's user manual, but are limited in favor of
+ * sensor specific
+ */
+
+ /* Only standard records are defined so far */
+ if( rec->record_type < 0xC0 ){
+ struct ipmi_event_sensor_types *st=NULL;
+ for ( st=oem_kontron_event_reading_types ; st->type != NULL; st++){
+ if (st->code == rec->sel_type.standard_type.event_type ){
+ size_t len =strlen(st->desc);
+ description = (char*)malloc( len + 1 );
+ memcpy(description, st->desc , len);
+ description[len] = 0;;
+ return description;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+char *
+get_newisys_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
+{
+ /*
+ * Newisys OEM event descriptions can be retrieved through an
+ * OEM IPMI command.
+ */
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[6];
+ char * description = NULL;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x2E;
+ req.msg.cmd = 0x01;
+ req.msg.data_len = sizeof(msg_data);
+
+ msg_data[0] = 0x15; /* IANA LSB */
+ msg_data[1] = 0x24; /* IANA */
+ msg_data[2] = 0x00; /* IANA MSB */
+ msg_data[3] = 0x01; /* Subcommand */
+ msg_data[4] = rec->record_id & 0x00FF; /* SEL Record ID LSB */
+ msg_data[5] = (rec->record_id & 0xFF00) >> 8; /* SEL Record ID MSB */
+
+ req.msg.data = msg_data;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ if (verbose)
+ lprintf(LOG_ERR, "Error issuing OEM command");
+ return NULL;
+ }
+ if (rsp->ccode > 0) {
+ if (verbose)
+ lprintf(LOG_ERR, "OEM command returned error code: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return NULL;
+ }
+
+ /* Verify our response before we use it */
+ if (rsp->data_len < 5)
+ {
+ lprintf(LOG_ERR, "Newisys OEM response too short");
+ return NULL;
+ }
+ else if (rsp->data_len != (4 + rsp->data[3]))
+ {
+ lprintf(LOG_ERR, "Newisys OEM response has unexpected length");
+ return NULL;
+ }
+ else if (IPM_DEV_MANUFACTURER_ID(rsp->data) != IPMI_OEM_NEWISYS)
+ {
+ lprintf(LOG_ERR, "Newisys OEM response has unexpected length");
+ return NULL;
+ }
+
+ description = (char*)malloc(rsp->data[3] + 1);
+ memcpy(description, rsp->data + 4, rsp->data[3]);
+ description[rsp->data[3]] = 0;;
+
+ return description;
+}
+
+char *
+get_supermicro_evt_desc(struct ipmi_intf *intf, struct sel_event_record *rec)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ char *desc = NULL;
+ char *str;
+ int chipset_type = 1;
+ int data1;
+ int data2;
+ int data3;
+ int length;
+ int sensor_type;
+ uint8_t i = 0;
+ uint16_t oem_id = 0;
+ /* Get the OEM event Bytes of the SEL Records byte 13, 14, 15 to
+ * data1,data2,data3
+ */
+ data1 = rec->sel_type.standard_type.event_data[0];
+ data2 = rec->sel_type.standard_type.event_data[1];
+ data3 = rec->sel_type.standard_type.event_data[2];
+ /* Check for the Standard Event type == 0x6F */
+ if (rec->sel_type.standard_type.event_type != 0x6F) {
+ return NULL;
+ }
+ /* Allocate mem for te Description string */
+ desc = (char *)malloc(SIZE_OF_DESC);
+ if (desc == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return NULL;
+ }
+ memset(desc,0,SIZE_OF_DESC);
+ sensor_type = rec->sel_type.standard_type.sensor_type;
+ switch (sensor_type) {
+ case SENSOR_TYPE_MEMORY:
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data = NULL;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, " Error getting system info");
+ if (desc != NULL) {
+ free(desc);
+ desc = NULL;
+ }
+ return NULL;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, " Error getting system info: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ if (desc != NULL) {
+ free(desc);
+ desc = NULL;
+ }
+ return NULL;
+ }
+ /* check the chipset type */
+ oem_id = ipmi_get_oem_id(intf);
+ if (oem_id == 0) {
+ return NULL;
+ }
+ length = sizeof(supermicro_X8);
+ for (i = 0; i < length; i++) {
+ if (oem_id == supermicro_X8[i]) {
+ chipset_type = 0;
+ break;
+ }
+ }
+ length = sizeof(supermicro_x9);
+ for (i = 0; i < length; i++) {
+ if (oem_id == supermicro_x9[i]) {
+ chipset_type = 2;
+ break;
+ }
+ }
+ if (chipset_type == 0) {
+ snprintf(desc, SIZE_OF_DESC, "@DIMM%2X(CPU%x)",
+ data2,
+ (data3 & 0x03) + 1);
+ } else if (chipset_type == 1) {
+ snprintf(desc, SIZE_OF_DESC, "@DIMM%c%c(CPU%x)",
+ (data2 >> 4) + 0x40 + (data3 & 0x3) * 4,
+ (data2 & 0xf) + 0x27, (data3 & 0x03) + 1);
+ } else if (chipset_type == 2) {
+ snprintf(desc, SIZE_OF_DESC, "@DIMM%c%c(CPU%x)",
+ (data2 >> 4) + 0x40 + (data3 & 0x3) * 3,
+ (data2 & 0xf) + 0x27, (data3 & 0x03) + 1);
+ } else {
+ snprintf(desc, SIZE_OF_DESC, "");
+ }
+ break;
+ case SENSOR_TYPE_SUPERMICRO_OEM:
+ if (data1 == 0x80 && data3 == 0xFF) {
+ if (data2 == 0x0) {
+ snprintf(desc, SIZE_OF_DESC, "BMC unexpected reset");
+ } else if (data2 == 0x1) {
+ snprintf(desc, SIZE_OF_DESC, "BMC cold reset");
+ } else if (data2 == 0x2) {
+ snprintf(desc, SIZE_OF_DESC, "BMC warm reset");
+ }
+ }
+ break;
+ }
+ return desc;
+}
+
+/*
+ * Function : Decoding the SEL OEM Bytes for the DELL Platforms.
+ * Description : The below fucntion will decode the SEL Events OEM Bytes for the Dell specific Sensors only.
+ * The below function will append the additional information Strings/description to the normal sel desc.
+ * With this the SEL will display additional information sent via OEM Bytes of the SEL Record.
+ * NOTE : Specific to DELL Platforms only.
+ * Returns : Pointer to the char string.
+ */
+char * get_dell_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
+{
+ int data1, data2, data3;
+ int sensor_type;
+ char *desc = NULL;
+
+ unsigned char count;
+ unsigned char node;
+ unsigned char num;
+ unsigned char dimmNum;
+ unsigned char dimmsPerNode;
+ char dimmStr[MAX_DIMM_STR];
+ char cardStr[MAX_CARD_STR];
+ char numStr[MAX_CARDNO_STR];
+ char tmpdesc[SIZE_OF_DESC];
+ char* str;
+ unsigned char incr = 0;
+ unsigned char i=0,j = 0;
+ unsigned char postCode;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ char tmpData;
+ int version;
+ /* Get the OEM event Bytes of the SEL Records byte 13, 14, 15 to Data1,data2,data3 */
+ data1 = rec->sel_type.standard_type.event_data[0];
+ data2 = rec->sel_type.standard_type.event_data[1];
+ data3 = rec->sel_type.standard_type.event_data[2];
+ /* Check for the Standard Event type == 0x6F */
+ if (0x6F == rec->sel_type.standard_type.event_type)
+ {
+ sensor_type = rec->sel_type.standard_type.sensor_type;
+ /* Allocate mem for te Description string */
+ desc = (char*)malloc(SIZE_OF_DESC);
+ if(NULL == desc)
+ return NULL;
+ memset(desc,0,SIZE_OF_DESC);
+ memset(tmpdesc,0,SIZE_OF_DESC);
+ switch (sensor_type) {
+ case SENSOR_TYPE_PROCESSOR: /* Processor/CPU related OEM Sel Byte Decoding for DELL Platforms only */
+ if((OEM_CODE_IN_BYTE2 == (data1 & DATA_BYTE2_SPECIFIED_MASK)))
+ {
+ if(0x00 == (data1 & MASK_LOWER_NIBBLE))
+ snprintf(desc,SIZE_OF_DESC,"CPU Internal Err | ");
+ if(0x06 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc,SIZE_OF_DESC,"CPU Protocol Err | ");
+
+ }
+
+ /* change bit location to a number */
+ for (count= 0; count < 8; count++)
+ {
+ if (BIT(count)& data2)
+ {
+ count++;
+ /* 0x0A - CPU sensor number */
+ if((0x06 == (data1 & MASK_LOWER_NIBBLE)) && (0x0A == rec->sel_type.standard_type.sensor_num))
+ snprintf(desc,SIZE_OF_DESC,"FSB %d ",count); // Which CPU Has generated the FSB
+ else
+ snprintf(desc,SIZE_OF_DESC,"CPU %d | APIC ID %d ",count,data3); /* Specific CPU related info */
+ break;
+ }
+ }
+ }
+ break;
+ case SENSOR_TYPE_MEMORY: /* Memory or DIMM related OEM Sel Byte Decoding for DELL Platforms only */
+ case SENSOR_TYPE_EVT_LOG: /* Events Logging for Memory or DIMM related OEM Sel Byte Decoding for DELL Platforms only */
+
+ /* Get the current version of the IPMI Spec Based on that Decoding of memory info is done.*/
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.lun = 0;
+ req.msg.cmd = BMC_GET_DEVICE_ID;
+ req.msg.data = NULL;
+ req.msg.data_len = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (NULL == rsp)
+ {
+ lprintf(LOG_ERR, " Error getting system info");
+ if (desc != NULL) {
+ free(desc);
+ desc = NULL;
+ }
+ return NULL;
+ }
+ else if (rsp->ccode > 0)
+ {
+ lprintf(LOG_ERR, " Error getting system info: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ if (desc != NULL) {
+ free(desc);
+ desc = NULL;
+ }
+ return NULL;
+ }
+ version = rsp->data[4];
+ /* Memory DIMMS */
+ if( (data1 & OEM_CODE_IN_BYTE2) || (data1 & OEM_CODE_IN_BYTE3 ) )
+ {
+ /* Memory Redundancy related oem bytes docoding .. */
+ if( (SENSOR_TYPE_MEMORY == sensor_type) && (0x0B == rec->sel_type.standard_type.event_type) )
+ {
+ if(0x00 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc,SIZE_OF_DESC," Redundancy Regained | ");
+ }
+ else if(0x01 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc,SIZE_OF_DESC,"Redundancy Lost | ");
+ }
+ } /* Correctable and uncorrectable ECC Error Decoding */
+ else if(SENSOR_TYPE_MEMORY == sensor_type)
+ {
+ if(0x00 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ /* 0x1C - Memory Sensor Number */
+ if(0x1C == rec->sel_type.standard_type.sensor_num)
+ {
+ /*Add the complete information about the Memory Configs.*/
+ if((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3 ))
+ {
+ count = 0;
+ snprintf(desc,SIZE_OF_DESC,"CRC Error on:");
+ for(i=0;i<4;i++)
+ {
+ if((BIT(i))&(data2))
+ {
+ if(count)
+ {
+ str = desc+strlen(desc);
+ *str++ = ',';
+ str = '\0';
+ count = 0;
+ }
+ switch(i) /* Which type of memory config is present.. */
+ {
+ case 0: snprintf(tmpdesc,SIZE_OF_DESC,"South Bound Memory");
+ strcat(desc,tmpdesc);
+ count++;
+ break;
+ case 1: snprintf(tmpdesc,SIZE_OF_DESC,"South Bound Config");
+ strcat(desc,tmpdesc);
+ count++;
+ break;
+ case 2: snprintf(tmpdesc,SIZE_OF_DESC,"North Bound memory");
+ strcat(desc,tmpdesc);
+ count++;
+ break;
+ case 3: snprintf(tmpdesc,SIZE_OF_DESC,"North Bound memory-corr");
+ strcat(desc,tmpdesc);
+ count++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if(data3>=0x00 && data3<0xFF)
+ {
+ snprintf(tmpdesc,SIZE_OF_DESC,"|Failing_Channel:%d",data3);
+ strcat(desc,tmpdesc);
+ }
+ }
+ break;
+ }
+ snprintf(desc,SIZE_OF_DESC,"Correctable ECC | ");
+ }
+ else if(0x01 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc,SIZE_OF_DESC,"UnCorrectable ECC | ");
+ }
+ } /* Corr Memory log disabled */
+ else if(SENSOR_TYPE_EVT_LOG == sensor_type)
+ {
+ if(0x00 == (data1 & MASK_LOWER_NIBBLE))
+ snprintf(desc,SIZE_OF_DESC,"Corr Memory Log Disabled | ");
+ }
+ }
+ else
+ {
+ if(SENSOR_TYPE_SYS_EVENT == sensor_type)
+ {
+ if(0x02 == (data1 & MASK_LOWER_NIBBLE))
+ snprintf(desc,SIZE_OF_DESC,"Unknown System Hardware Failure ");
+ }
+ if(SENSOR_TYPE_EVT_LOG == sensor_type)
+ {
+ if(0x03 == (data1 & MASK_LOWER_NIBBLE))
+ snprintf(desc,SIZE_OF_DESC,"All Even Logging Dissabled");
+ }
+ }
+ /*
+ * Based on the above error, we need to find whcih memory slot or
+ * Card has got the Errors/Sel Generated.
+ */
+ if(data1 & OEM_CODE_IN_BYTE2 )
+ {
+ /* Find the Card Type */
+ if((0x0F != (data2 >> 4)) && ((data2 >> 4) < 0x08))
+ {
+ tmpData = ('A'+ (data2 >> 4));
+ if( (SENSOR_TYPE_MEMORY == sensor_type) && (0x0B == rec->sel_type.standard_type.event_type) )
+ {
+ snprintf(tmpdesc, SIZE_OF_DESC, "Bad Card %c", tmpData);
+ }
+ else
+ {
+ snprintf(tmpdesc, SIZE_OF_DESC, "Card %c", tmpData);
+ }
+ strcat(desc, tmpdesc);
+ } /* Find the Bank Number of the DIMM */
+ if (0x0F != (data2 & MASK_LOWER_NIBBLE))
+ {
+ if(0x51 == version)
+ {
+ snprintf(tmpdesc, SIZE_OF_DESC, "Bank %d", ((data2 & 0x0F)+1));
+ strcat(desc, tmpdesc);
+ }
+ else
+ {
+ incr = (data2 & 0x0f) << 3;
+ }
+ }
+
+ }
+ /* Find the DIMM Number of the Memory which has Generated the Fault or Sel */
+ if(data1 & OEM_CODE_IN_BYTE3 )
+ {
+ // Based on the IPMI Spec Need Identify the DIMM Details.
+ // For the SPEC 1.5 Only the DIMM Number is Valid.
+ if(0x51 == version)
+ {
+ snprintf(tmpdesc, SIZE_OF_DESC, "DIMM %c", ('A'+ data3));
+ strcat(desc, tmpdesc);
+ }
+ /* For the SPEC 2.0 Decode the DIMM Number as it supports more.*/
+ else if( ((data2 >> 4) > 0x07) && (0x0F != (data2 >> 4) ))
+ {
+ strcpy(dimmStr, " DIMM");
+ str = desc+strlen(desc);
+ dimmsPerNode = 4;
+ if(0x09 == (data2 >> 4)) dimmsPerNode = 6;
+ else if(0x0A == (data2 >> 4)) dimmsPerNode = 8;
+ else if(0x0B == (data2 >> 4)) dimmsPerNode = 9;
+ else if(0x0C == (data2 >> 4)) dimmsPerNode = 12;
+ else if(0x0D == (data2 >> 4)) dimmsPerNode = 24;
+ else if(0x0E == (data2 >> 4)) dimmsPerNode = 3;
+ count = 0;
+ for (i = 0; i < 8; i++)
+ {
+ if (BIT(i) & data3)
+ {
+ if(count)
+ {
+ strcat(str,",");
+ count = 0x00;
+ }
+ node = (incr + i)/dimmsPerNode;
+ dimmNum = ((incr + i)%dimmsPerNode)+1;
+ dimmStr[5] = node + 'A';
+ sprintf(tmpdesc,"%d",dimmNum);
+ for(j = 0; j < strlen(tmpdesc);j++)
+ dimmStr[6+j] = tmpdesc[j];
+ dimmStr[6+j] = '\0';
+ strcat(str,dimmStr); // final DIMM Details.
+ count++;
+ }
+ }
+ }
+ else
+ {
+ strcpy(dimmStr, " DIMM");
+ str = desc+strlen(desc);
+ count = 0;
+ for (i = 0; i < 8; i++)
+ {
+ if (BIT(i) & data3)
+ {
+ // check if more than one DIMM, if so add a comma to the string.
+ sprintf(tmpdesc,"%d",(i + incr + 1));
+ if(count)
+ {
+ strcat(str,",");
+ count = 0x00;
+ }
+ for(j = 0; j < strlen(tmpdesc);j++)
+ dimmStr[5+j] = tmpdesc[j];
+ dimmStr[5+j] = '\0';
+ strcat(str, dimmStr);
+ count++;
+ }
+ }
+ }
+ }
+ break;
+ /* Sensor In system charectorization Error Decoding.
+ Sensor type 0x20*/
+ case SENSOR_TYPE_TXT_CMD_ERROR:
+ if((0x00 == (data1 & MASK_LOWER_NIBBLE))&&((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3)))
+ {
+ switch(data3)
+ {
+ case 0x01:
+ snprintf(desc,SIZE_OF_DESC,"BIOS TXT Error");
+ break;
+ case 0x02:
+ snprintf(desc,SIZE_OF_DESC,"Processor/FIT TXT");
+ break;
+ case 0x03:
+ snprintf(desc,SIZE_OF_DESC,"BIOS ACM TXT Error");
+ break;
+ case 0x04:
+ snprintf(desc,SIZE_OF_DESC,"SINIT ACM TXT Error");
+ break;
+ case 0xff:
+ snprintf(desc,SIZE_OF_DESC,"Unrecognized TT Error12");
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ /* OS Watch Dog Timer Sel Events */
+ case SENSOR_TYPE_WTDOG:
+
+ if(SENSOR_TYPE_OEM_SEC_EVENT == data1)
+ {
+ if(0x04 == data2)
+ {
+ snprintf(desc,SIZE_OF_DESC,"Hard Reset|Interrupt type None,SMS/OS Timer used at expiration");
+ }
+ }
+
+ break;
+ /* This Event is for BMC to Othe Hardware or CPU . */
+ case SENSOR_TYPE_VER_CHANGE:
+ if((0x02 == (data1 & MASK_LOWER_NIBBLE))&&((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3)))
+ {
+ if(0x02 == data2)
+ {
+ if(0x00 == data3)
+ {
+ snprintf(desc, SIZE_OF_DESC, "between BMC/iDRAC Firmware and other hardware");
+ }
+ else if(0x01 == data3)
+ {
+ snprintf(desc, SIZE_OF_DESC, "between BMC/iDRAC Firmware and CPU");
+ }
+ }
+ }
+ break;
+ /* Flex or Mac tuning OEM Decoding for the DELL. */
+ case SENSOR_TYPE_OEM_SEC_EVENT:
+ /* 0x25 - Virtual MAC sensory number - Dell OEM */
+ if(0x25 == rec->sel_type.standard_type.sensor_num)
+ {
+ if(0x01 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc, SIZE_OF_DESC, "Failed to program Virtual Mac Address");
+ if((data1 & OEM_CODE_IN_BYTE2)&&(data1 & OEM_CODE_IN_BYTE3))
+ {
+ snprintf(tmpdesc, SIZE_OF_DESC, " at bus:%.2x device:%.2x function:%x",
+ data3 &0x7F, (data2 >> 3) & 0x1F,
+ data2 & 0x07);
+ strcat(desc,tmpdesc);
+ }
+ }
+ else if(0x02 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc, SIZE_OF_DESC, "Device option ROM failed to support link tuning or flex address");
+ }
+ else if(0x03 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc, SIZE_OF_DESC, "Failed to get link tuning or flex address data from BMC/iDRAC");
+ }
+ }
+ break;
+ case SENSOR_TYPE_CRIT_INTR:
+ case SENSOR_TYPE_OEM_NFATAL_ERROR: /* Non - Fatal PCIe Express Error Decoding */
+ case SENSOR_TYPE_OEM_FATAL_ERROR: /* Fatal IO Error Decoding */
+ /* 0x29 - QPI Linx Error Sensor Dell OEM */
+ if(0x29 == rec->sel_type.standard_type.sensor_num)
+ {
+ if((0x02 == (data1 & MASK_LOWER_NIBBLE))&&((data1 & OEM_CODE_IN_BYTE2) && (data1 & OEM_CODE_IN_BYTE3)))
+ {
+ snprintf(tmpdesc, SIZE_OF_DESC, "Partner-(LinkId:%d,AgentId:%d)|",(data2 & 0xC0),(data2 & 0x30));
+ strcat(desc,tmpdesc);
+ snprintf(tmpdesc, SIZE_OF_DESC, "ReportingAgent(LinkId:%d,AgentId:%d)|",(data2 & 0x0C),(data2 & 0x03));
+ strcat(desc,tmpdesc);
+ if(0x00 == (data3 & 0xFC))
+ {
+ snprintf(tmpdesc, SIZE_OF_DESC, "LinkWidthDegraded|");
+ strcat(desc,tmpdesc);
+ }
+ if(BIT(1)& data3)
+ {
+ snprintf(tmpdesc,SIZE_OF_DESC,"PA_Type:IOH|");
+ }
+ else
+ {
+ snprintf(tmpdesc,SIZE_OF_DESC,"PA-Type:CPU|");
+ }
+ strcat(desc,tmpdesc);
+ if(BIT(0)& data3)
+ {
+ snprintf(tmpdesc,SIZE_OF_DESC,"RA-Type:IOH");
+ }
+ else
+ {
+ snprintf(tmpdesc,SIZE_OF_DESC,"RA-Type:CPU");
+ }
+ strcat(desc,tmpdesc);
+ }
+ }
+ else
+ {
+
+ if(0x02 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ sprintf(desc,"%s","IO channel Check NMI");
+ }
+ else
+ {
+ if(0x00 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc, SIZE_OF_DESC, "%s","PCIe Error |");
+ }
+ else if(0x01 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc, SIZE_OF_DESC, "%s","I/O Error |");
+ }
+ else if(0x04 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc, SIZE_OF_DESC, "%s","PCI PERR |");
+ }
+ else if(0x05 == (data1 & MASK_LOWER_NIBBLE))
+ {
+ snprintf(desc, SIZE_OF_DESC, "%s","PCI SERR |");
+ }
+ else
+ {
+ snprintf(desc, SIZE_OF_DESC, "%s"," ");
+ }
+ if (data3 & 0x80)
+ snprintf(tmpdesc, SIZE_OF_DESC, "Slot %d", data3 & 0x7F);
+ else
+ snprintf(tmpdesc, SIZE_OF_DESC, "PCI bus:%.2x device:%.2x function:%x",
+ data3 &0x7F, (data2 >> 3) & 0x1F,
+ data2 & 0x07);
+
+ strcat(desc,tmpdesc);
+ }
+ }
+ break;
+ /* POST Fatal Errors generated from the Server with much more info*/
+ case SENSOR_TYPE_FRM_PROG:
+ if((0x0F == (data1 & MASK_LOWER_NIBBLE))&&(data1 & OEM_CODE_IN_BYTE2))
+ {
+ switch(data2)
+ {
+ case 0x80:
+ snprintf(desc, SIZE_OF_DESC, "No memory is detected.");break;
+ case 0x81:
+ snprintf(desc,SIZE_OF_DESC, "Memory is detected but is not configurable.");break;
+ case 0x82:
+ snprintf(desc, SIZE_OF_DESC, "Memory is configured but not usable.");break;
+ case 0x83:
+ snprintf(desc, SIZE_OF_DESC, "System BIOS shadow failed.");break;
+ case 0x84:
+ snprintf(desc, SIZE_OF_DESC, "CMOS failed.");break;
+ case 0x85:
+ snprintf(desc, SIZE_OF_DESC, "DMA controller failed.");break;
+ case 0x86:
+ snprintf(desc, SIZE_OF_DESC, "Interrupt controller failed.");break;
+ case 0x87:
+ snprintf(desc, SIZE_OF_DESC, "Timer refresh failed.");break;
+ case 0x88:
+ snprintf(desc, SIZE_OF_DESC, "Programmable interval timer error.");break;
+ case 0x89:
+ snprintf(desc, SIZE_OF_DESC, "Parity error.");break;
+ case 0x8A:
+ snprintf(desc, SIZE_OF_DESC, "SIO failed.");break;
+ case 0x8B:
+ snprintf(desc, SIZE_OF_DESC, "Keyboard controller failed.");break;
+ case 0x8C:
+ snprintf(desc, SIZE_OF_DESC, "System management interrupt initialization failed.");break;
+ case 0x8D:
+ snprintf(desc, SIZE_OF_DESC, "TXT-SX Error.");break;
+ case 0xC0:
+ snprintf(desc, SIZE_OF_DESC, "Shutdown test failed.");break;
+ case 0xC1:
+ snprintf(desc, SIZE_OF_DESC, "BIOS POST memory test failed.");break;
+ case 0xC2:
+ snprintf(desc, SIZE_OF_DESC, "RAC configuration failed.");break;
+ case 0xC3:
+ snprintf(desc, SIZE_OF_DESC, "CPU configuration failed.");break;
+ case 0xC4:
+ snprintf(desc, SIZE_OF_DESC, "Incorrect memory configuration.");break;
+ case 0xFE:
+ snprintf(desc, SIZE_OF_DESC, "General failure after video.");
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ sensor_type = rec->sel_type.standard_type.event_type;
+ }
+ return desc;
+}
+
+char *
+ipmi_get_oem_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
+{
+ char * desc = NULL;
+
+ switch (ipmi_get_oem(intf))
+ {
+ case IPMI_OEM_NEWISYS:
+ desc = get_newisys_evt_desc(intf, rec);
+ break;
+ case IPMI_OEM_KONTRON:
+ desc = get_kontron_evt_desc(intf, rec);
+ break;
+ case IPMI_OEM_DELL: // Dell Decoding of the OEM Bytes from SEL Record.
+ desc = get_dell_evt_desc(intf, rec);
+ break;
+ case IPMI_OEM_SUPERMICRO:
+ case IPMI_OEM_SUPERMICRO_47488:
+ desc = get_supermicro_evt_desc(intf, rec);
+ break;
+ case IPMI_OEM_UNKNOWN:
+ default:
+ break;
+ }
+
+ return desc;
+}
+
+
+void
+ipmi_get_event_desc(struct ipmi_intf * intf, struct sel_event_record * rec, char ** desc)
+{
+ uint8_t code, offset;
+ struct ipmi_event_sensor_types *evt = NULL;
+ char *sfx = NULL; /* This will be assigned if the Platform is DELL,
+ additional info is appended to the current Description */
+
+ if (desc == NULL)
+ return;
+ *desc = NULL;
+
+ if ((rec->sel_type.standard_type.event_type >= 0x70) && (rec->sel_type.standard_type.event_type < 0x7F)) {
+ *desc = ipmi_get_oem_desc(intf, rec);
+ return;
+ } else if (rec->sel_type.standard_type.event_type == 0x6f) {
+ if( rec->sel_type.standard_type.sensor_type >= 0xC0 && rec->sel_type.standard_type.sensor_type < 0xF0) {
+ IPMI_OEM iana = ipmi_get_oem(intf);
+
+ switch(iana){
+ case IPMI_OEM_KONTRON:
+ lprintf(LOG_DEBUG, "oem sensor type %x %d using oem type supplied description",
+ rec->sel_type.standard_type.sensor_type , iana);
+
+ evt = oem_kontron_event_types;
+ code = rec->sel_type.standard_type.sensor_type;
+ break;
+ case IPMI_OEM_DELL: /* OEM Bytes Decoding for DELLi */
+ evt = sensor_specific_types;
+ code = rec->sel_type.standard_type.sensor_type;
+ if ( (OEM_CODE_IN_BYTE2 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)) ||
+ (OEM_CODE_IN_BYTE3 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE3_SPECIFIED_MASK)) )
+ {
+ if(rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)
+ evt->data = rec->sel_type.standard_type.event_data[1];
+
+ sfx = ipmi_get_oem_desc(intf, rec);
+ }
+ break;
+ case IPMI_OEM_SUPERMICRO:
+ case IPMI_OEM_SUPERMICRO_47488:
+ evt = sensor_specific_types;
+ code = rec->sel_type.standard_type.sensor_type;
+ sfx = ipmi_get_oem_desc(intf, rec);
+ break;
+ /* add your oem sensor assignation here */
+ }
+ if( evt == NULL ){
+ lprintf(LOG_DEBUG, "oem sensor type %x using standard type supplied description",
+ rec->sel_type.standard_type.sensor_type );
+ }
+ } else {
+ switch (ipmi_get_oem(intf)) {
+ case IPMI_OEM_SUPERMICRO:
+ case IPMI_OEM_SUPERMICRO_47488:
+ evt = sensor_specific_types;
+ code = rec->sel_type.standard_type.sensor_type;
+ sfx = ipmi_get_oem_desc(intf, rec);
+ break;
+ }
+ }
+ if( evt == NULL ){
+ evt = sensor_specific_types;
+ code = rec->sel_type.standard_type.sensor_type;
+ }
+ /*
+ * Check for the OEM DELL Interface based on the Dell Specific Vendor Code.
+ * If its Dell Platform, do the OEM Byte decode from the SEL Records.
+ * Additional information should be written by the ipmi_get_oem_desc()
+ */
+ if(ipmi_get_oem(intf) == IPMI_OEM_DELL) {
+ code = rec->sel_type.standard_type.sensor_type;
+ if ( (OEM_CODE_IN_BYTE2 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)) ||
+ (OEM_CODE_IN_BYTE3 == (rec->sel_type.standard_type.event_data[0] & DATA_BYTE3_SPECIFIED_MASK)) )
+ {
+ if(rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK)
+ evt->data = rec->sel_type.standard_type.event_data[1];
+ sfx = ipmi_get_oem_desc(intf, rec);
+
+ }
+ else if(SENSOR_TYPE_OEM_SEC_EVENT == rec->sel_type.standard_type.event_data[0])
+ {
+ /* 0x23 : Sensor Number.*/
+ if(0x23 == rec->sel_type.standard_type.sensor_num)
+ {
+ evt->data = rec->sel_type.standard_type.event_data[1];
+ sfx = ipmi_get_oem_desc(intf, rec);
+ }
+ }
+ }
+ } else {
+ evt = generic_event_types;
+ code = rec->sel_type.standard_type.event_type;
+ }
+
+ offset = rec->sel_type.standard_type.event_data[0] & 0xf;
+
+ while (evt->type) {
+ if ((evt->code == code && evt->offset == offset && evt->desc != NULL) &&
+ ((evt->data == ALL_OFFSETS_SPECIFIED) ||
+ ((rec->sel_type.standard_type.event_data[0] & DATA_BYTE2_SPECIFIED_MASK) &&
+ (evt->data == rec->sel_type.standard_type.event_data[1]))))
+ {
+ /* Increase the Malloc size to current_size + Dellspecific description size */
+ *desc = (char *)malloc(strlen(evt->desc) + 48 + SIZE_OF_DESC);
+ if (NULL == *desc) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return;
+ }
+ memset(*desc, 0, strlen(evt->desc)+ 48 + SIZE_OF_DESC);
+ /*
+ * Additional info is present for the DELL Platforms.
+ * Append the same to the evt->desc string.
+ */
+ if (sfx) {
+ sprintf(*desc, "%s (%s)", evt->desc, sfx);
+ free(sfx);
+ sfx = NULL;
+ } else {
+ sprintf(*desc, "%s", evt->desc);
+ }
+ return;
+ }
+ evt++;
+ }
+ /* The Above while Condition was not met beacouse the below sensor type were Newly defined OEM
+ Secondary Events. 0xC1, 0xC2, 0xC3. */
+ if((sfx) && (0x6F == rec->sel_type.standard_type.event_type))
+ {
+ uint8_t flag = 0x00;
+ switch(code)
+ {
+ case SENSOR_TYPE_FRM_PROG:
+ if(0x0F == offset)
+ flag = 0x01;
+ break;
+ case SENSOR_TYPE_OEM_SEC_EVENT:
+ if((0x01 == offset) || (0x02 == offset) || (0x03 == offset))
+ flag = 0x01;
+ break;
+ case SENSOR_TYPE_OEM_NFATAL_ERROR:
+ if((0x00 == offset) || (0x02 == offset))
+ flag = 0x01;
+ break;
+ case SENSOR_TYPE_OEM_FATAL_ERROR:
+ if(0x01 == offset)
+ flag = 0x01;
+ break;
+ case SENSOR_TYPE_SUPERMICRO_OEM:
+ flag = 0x02;
+ break;
+ default:
+ break;
+ }
+ if(flag)
+ {
+ *desc = (char *)malloc( 48 + SIZE_OF_DESC);
+ if (NULL == *desc)
+ {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return;
+ }
+ memset(*desc, 0, 48 + SIZE_OF_DESC);
+ if (flag == 0x02) {
+ sprintf(*desc, "%s", sfx);
+ return;
+ }
+ sprintf(*desc, "(%s)",sfx);
+ }
+ free(sfx);
+ sfx = NULL;
+ }
+}
+
+
+const char *
+ipmi_sel_get_oem_sensor_type(IPMI_OEM iana, uint8_t code)
+{
+ struct ipmi_event_sensor_types *st = NULL;
+
+ switch(iana){
+ case IPMI_OEM_KONTRON:
+ st = oem_kontron_event_types;
+ break;
+ /* add you oem sensor type lookup assignement here */
+ default:
+ lprintf(LOG_DEBUG, "ipmitool: missing OEM sensor type for %ul",iana);
+ break;
+ }
+
+ if( st != NULL )
+ for (; st->type != NULL; st++)
+ if (st->code == code)
+ return st->type;
+
+ return ipmi_sel_get_sensor_type(code);
+}
+
+const char *
+ipmi_sel_get_oem_sensor_type_offset(IPMI_OEM iana, uint8_t code, uint8_t offset)
+{
+ struct ipmi_event_sensor_types *st = NULL;
+
+ switch(iana){
+ case IPMI_OEM_KONTRON:
+ st = oem_kontron_event_types;
+ break;
+ /* add you oem sensor type lookup assignement here */
+ default:
+ lprintf(LOG_DEBUG,
+ "ipmitool: missing OEM sensor type offset for %ul",iana);
+ break;
+ }
+
+ if( st != NULL )
+ for (; st->type != NULL; st++)
+ {
+ if (st->code == code && st->offset == (offset&0xf))
+ return st->type;
+ }
+
+ return ipmi_sel_get_oem_sensor_type(iana,code);
+}
+
+const char *
+ipmi_sel_get_sensor_type(uint8_t code)
+{
+ struct ipmi_event_sensor_types *st;
+ for (st = sensor_specific_types; st->type != NULL; st++)
+ if (st->code == code)
+ return st->type;
+ return "Unknown";
+}
+
+const char *
+ipmi_sel_get_sensor_type_offset(uint8_t code, uint8_t offset)
+{
+ struct ipmi_event_sensor_types *st;
+ for (st = sensor_specific_types; st->type != NULL; st++)
+ if (st->code == code && st->offset == (offset&0xf))
+ return st->type;
+
+ return ipmi_sel_get_sensor_type(code);
+}
+
+static int
+ipmi_sel_get_info(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint16_t e, version;
+ uint32_t f;
+ int pctfull = 0;
+ uint32_t fs = 0xffffffff;
+ uint32_t zeros = 0;
+
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_GET_SEL_INFO;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get SEL Info command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get SEL Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 2)
+ printbuf(rsp->data, rsp->data_len, "sel_info");
+
+ printf("SEL Information\n");
+ version = rsp->data[0];
+ printf("Version : %d.%d (%s)\n",
+ version & 0xf, (version>>4) & 0xf,
+ (version == 0x51 || version == 0x02) ? "v1.5, v2 compliant" : "Unknown");
+
+ /* save the entry count and free space to determine percent full */
+ e = buf2short(rsp->data + 1);
+ f = buf2short(rsp->data + 3);
+ printf("Entries : %d\n", e);
+ printf("Free Space : %d bytes %s\n", f ,(f==65535 ? "or more" : "" ));
+
+ if (e) {
+ e *= 16; /* each entry takes 16 bytes */
+ f += e; /* this is supposed to give the total size ... */
+ pctfull = (int)(100 * ( (double)e / (double)f ));
+ }
+
+ if( f >= 65535 ) {
+ printf("Percent Used : %s\n", "unknown" );
+ }
+ else {
+ printf("Percent Used : %d%%\n", pctfull);
+ }
+
+
+ if ((!memcmp(rsp->data + 5, &fs, 4)) ||
+ (!memcmp(rsp->data + 5, &zeros, 4)))
+ printf("Last Add Time : Not Available\n");
+ else
+ printf("Last Add Time : %s\n",
+ ipmi_sel_timestamp(buf2long(rsp->data + 5)));
+
+ if ((!memcmp(rsp->data + 9, &fs, 4)) ||
+ (!memcmp(rsp->data + 9, &zeros, 4)))
+ printf("Last Del Time : Not Available\n");
+ else
+ printf("Last Del Time : %s\n",
+ ipmi_sel_timestamp(buf2long(rsp->data + 9)));
+
+
+ printf("Overflow : %s\n",
+ rsp->data[13] & 0x80 ? "true" : "false");
+ printf("Supported Cmds : ");
+ if (rsp->data[13] & 0x0f)
+ {
+ if (rsp->data[13] & 0x08)
+ printf("'Delete' ");
+ if (rsp->data[13] & 0x04)
+ printf("'Partial Add' ");
+ if (rsp->data[13] & 0x02)
+ printf("'Reserve' ");
+ if (rsp->data[13] & 0x01)
+ printf("'Get Alloc Info' ");
+ }
+ else
+ printf("None");
+ printf("\n");
+
+ /* get sel allocation info if supported */
+ if (rsp->data[13] & 1) {
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_GET_SEL_ALLOC_INFO;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR,
+ "Get SEL Allocation Info command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR,
+ "Get SEL Allocation Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("# of Alloc Units : %d\n", buf2short(rsp->data));
+ printf("Alloc Unit Size : %d\n", buf2short(rsp->data + 2));
+ printf("# Free Units : %d\n", buf2short(rsp->data + 4));
+ printf("Largest Free Blk : %d\n", buf2short(rsp->data + 6));
+ printf("Max Record Size : %d\n", rsp->data[8]);
+ }
+ return 0;
+}
+
+uint16_t
+ipmi_sel_get_std_entry(struct ipmi_intf * intf, uint16_t id,
+ struct sel_event_record * evt)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ uint8_t msg_data[6];
+ uint16_t next;
+ int data_count;
+
+ memset(msg_data, 0, 6);
+ msg_data[0] = 0x00; /* no reserve id, not partial get */
+ msg_data[1] = 0x00;
+ msg_data[2] = id & 0xff;
+ msg_data[3] = (id >> 8) & 0xff;
+ msg_data[4] = 0x00; /* offset */
+ msg_data[5] = 0xff; /* length */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_GET_SEL_ENTRY;
+ req.msg.data = msg_data;
+ req.msg.data_len = 6;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get SEL Entry %x command failed", id);
+ return 0;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get SEL Entry %x command failed: %s",
+ id, val2str(rsp->ccode, completion_code_vals));
+ return 0;
+ }
+
+ /* save next entry id */
+ next = (rsp->data[1] << 8) | rsp->data[0];
+
+ lprintf(LOG_DEBUG, "SEL Entry: %s", buf2str(rsp->data+2, rsp->data_len-2));
+ memset(evt, 0, sizeof(*evt));
+
+ /*Clear SEL Structure*/
+ evt->record_id = 0;
+ evt->record_type = 0;
+ if (evt->record_type < 0xc0)
+ {
+ evt->sel_type.standard_type.timestamp = 0;
+ evt->sel_type.standard_type.gen_id = 0;
+ evt->sel_type.standard_type.evm_rev = 0;
+ evt->sel_type.standard_type.sensor_type = 0;
+ evt->sel_type.standard_type.sensor_num = 0;
+ evt->sel_type.standard_type.event_type = 0;
+ evt->sel_type.standard_type.event_dir = 0;
+ evt->sel_type.standard_type.event_data[0] = 0;
+ evt->sel_type.standard_type.event_data[1] = 0;
+ evt->sel_type.standard_type.event_data[2] = 0;
+ }
+ else if (evt->record_type < 0xe0)
+ {
+ evt->sel_type.oem_ts_type.timestamp = 0;
+ evt->sel_type.oem_ts_type.manf_id[0] = 0;
+ evt->sel_type.oem_ts_type.manf_id[1] = 0;
+ evt->sel_type.oem_ts_type.manf_id[2] = 0;
+ for(data_count=0; data_count < SEL_OEM_TS_DATA_LEN ; data_count++)
+ evt->sel_type.oem_ts_type.oem_defined[data_count] = 0;
+ }
+ else
+ {
+ for(data_count=0; data_count < SEL_OEM_NOTS_DATA_LEN ; data_count++)
+ evt->sel_type.oem_nots_type.oem_defined[data_count] = 0;
+ }
+
+ /* save response into SEL event structure */
+ evt->record_id = (rsp->data[3] << 8) | rsp->data[2];
+ evt->record_type = rsp->data[4];
+ if (evt->record_type < 0xc0)
+ {
+ evt->sel_type.standard_type.timestamp = (rsp->data[8] << 24) | (rsp->data[7] << 16) |
+ (rsp->data[6] << 8) | rsp->data[5];
+ evt->sel_type.standard_type.gen_id = (rsp->data[10] << 8) | rsp->data[9];
+ evt->sel_type.standard_type.evm_rev = rsp->data[11];
+ evt->sel_type.standard_type.sensor_type = rsp->data[12];
+ evt->sel_type.standard_type.sensor_num = rsp->data[13];
+ evt->sel_type.standard_type.event_type = rsp->data[14] & 0x7f;
+ evt->sel_type.standard_type.event_dir = (rsp->data[14] & 0x80) >> 7;
+ evt->sel_type.standard_type.event_data[0] = rsp->data[15];
+ evt->sel_type.standard_type.event_data[1] = rsp->data[16];
+ evt->sel_type.standard_type.event_data[2] = rsp->data[17];
+ }
+ else if (evt->record_type < 0xe0)
+ {
+ evt->sel_type.oem_ts_type.timestamp= (rsp->data[8] << 24) | (rsp->data[7] << 16) |
+ (rsp->data[6] << 8) | rsp->data[5];
+ evt->sel_type.oem_ts_type.manf_id[0]= rsp->data[11];
+ evt->sel_type.oem_ts_type.manf_id[1]= rsp->data[10];
+ evt->sel_type.oem_ts_type.manf_id[2]= rsp->data[9];
+ for(data_count=0; data_count < SEL_OEM_TS_DATA_LEN ; data_count++)
+ evt->sel_type.oem_ts_type.oem_defined[data_count] = rsp->data[(data_count+12)];
+ }
+ else
+ {
+ for(data_count=0; data_count < SEL_OEM_NOTS_DATA_LEN ; data_count++)
+ evt->sel_type.oem_nots_type.oem_defined[data_count] = rsp->data[(data_count+5)];
+ }
+ return next;
+}
+
+static void
+ipmi_sel_print_event_file(struct ipmi_intf * intf, struct sel_event_record * evt, FILE * fp)
+{
+ char * description;
+
+ if (fp == NULL)
+ return;
+
+ ipmi_get_event_desc(intf, evt, &description);
+
+ fprintf(fp, "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x # %s #0x%02x %s\n",
+ evt->sel_type.standard_type.evm_rev,
+ evt->sel_type.standard_type.sensor_type,
+ evt->sel_type.standard_type.sensor_num,
+ evt->sel_type.standard_type.event_type | (evt->sel_type.standard_type.event_dir << 7),
+ evt->sel_type.standard_type.event_data[0],
+ evt->sel_type.standard_type.event_data[1],
+ evt->sel_type.standard_type.event_data[2],
+ (
+ (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
+ ?
+ ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ :
+ ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ ),
+ evt->sel_type.standard_type.sensor_num,
+ (description != NULL) ? description : "Unknown");
+
+ if (description != NULL) {
+ free(description);
+ description = NULL;
+ }
+}
+
+void
+ipmi_sel_print_extended_entry(struct ipmi_intf * intf, struct sel_event_record * evt)
+{
+ sel_extended++;
+ ipmi_sel_print_std_entry(intf, evt);
+ sel_extended--;
+}
+
+void
+ipmi_sel_print_std_entry(struct ipmi_intf * intf, struct sel_event_record * evt)
+{
+ char * description;
+ struct sdr_record_list * sdr = NULL;
+ int data_count;
+
+ if (sel_extended && (evt->record_type < 0xc0))
+ sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt->sel_type.standard_type.gen_id, evt->sel_type.standard_type.sensor_num, evt->sel_type.standard_type.sensor_type);
+
+
+ if (!evt)
+ return;
+
+ if (csv_output)
+ printf("%x,", evt->record_id);
+ else
+ printf("%4x | ", evt->record_id);
+
+ if (evt->record_type == 0xf0)
+ {
+ if (csv_output)
+ printf(",,");
+
+ printf ("Linux kernel panic: %.11s\n", (char *) evt + 5);
+ return;
+ }
+
+ if (evt->record_type < 0xe0)
+ {
+ if ((evt->sel_type.standard_type.timestamp < 0x20000000)||(evt->sel_type.oem_ts_type.timestamp < 0x20000000)){
+ printf(" Pre-Init ");
+
+ if (csv_output)
+ printf(",");
+ else
+ printf(" |");
+
+ printf("%010d", evt->sel_type.standard_type.timestamp );
+ if (csv_output)
+ printf(",");
+ else
+ printf("| ");
+ }
+ else {
+ if (evt->record_type < 0xc0)
+ printf("%s", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp));
+ else
+ printf("%s", ipmi_sel_timestamp_date(evt->sel_type.oem_ts_type.timestamp));
+ if (csv_output)
+ printf(",");
+ else
+ printf(" | ");
+
+ if (evt->record_type < 0xc0)
+ printf("%s", ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp));
+ else
+ printf("%s", ipmi_sel_timestamp_time(evt->sel_type.oem_ts_type.timestamp));
+
+ if (csv_output)
+ printf(",");
+ else
+ printf(" | ");
+ }
+
+ }
+ else
+ {
+ if (csv_output)
+ printf(",,");
+ }
+
+ if (evt->record_type >= 0xc0)
+ {
+ printf ("OEM record %02x", evt->record_type);
+ if (csv_output)
+ printf(",");
+ else
+ printf(" | ");
+
+ if(evt->record_type < 0xdf)
+ {
+ printf ("%02x%02x%02x", evt->sel_type.oem_ts_type.manf_id[0], evt->sel_type.oem_ts_type.manf_id[1], evt->sel_type.oem_ts_type.manf_id[2]);
+ if (csv_output)
+ printf(",");
+ else
+ printf(" | ");
+ for(data_count=0;data_count < SEL_OEM_TS_DATA_LEN;data_count++)
+ printf("%02x", evt->sel_type.oem_ts_type.oem_defined[data_count]);
+ }
+ else
+ {
+ for(data_count=0;data_count < SEL_OEM_NOTS_DATA_LEN;data_count++)
+ printf("%02x", evt->sel_type.oem_nots_type.oem_defined[data_count]);
+ }
+ ipmi_sel_oem_message(evt, 0);
+ printf ("\n");
+ return;
+ }
+
+ /* lookup SDR entry based on sensor number and type */
+ if (sdr != NULL) {
+ printf("%s ",
+ (
+ (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
+ ?
+ ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ :
+ ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ )
+ );
+ switch (sdr->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ printf("%s", sdr->record.full->id_string);
+ break;
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ printf("%s", sdr->record.compact->id_string);
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ printf("%s", sdr->record.eventonly->id_string);
+ break;
+ case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
+ printf("%s", sdr->record.fruloc->id_string);
+ break;
+ case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
+ printf("%s", sdr->record.mcloc->id_string);
+ break;
+ case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
+ printf("%s", sdr->record.genloc->id_string);
+ break;
+ default:
+ printf("#%02x", evt->sel_type.standard_type.sensor_num);
+ break;
+ }
+ } else {
+ printf("%s",(
+ (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
+ ?
+ ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ :
+ ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ ));
+ if (evt->sel_type.standard_type.sensor_num != 0)
+ printf(" #0x%02x", evt->sel_type.standard_type.sensor_num);
+ }
+
+ if (csv_output)
+ printf(",");
+ else
+ printf(" | ");
+
+ ipmi_get_event_desc(intf, evt, &description);
+ if (description) {
+ printf("%s", description);
+ free(description);
+ description = NULL;
+ }
+
+ if (csv_output) {
+ printf(",");
+ } else {
+ printf(" | ");
+ }
+
+ if (evt->sel_type.standard_type.event_dir) {
+ printf("Deasserted");
+ } else {
+ printf("Asserted");
+ }
+
+ if (sdr != NULL && evt->sel_type.standard_type.event_type == 1) {
+ /*
+ * Threshold Event
+ */
+ float trigger_reading = 0.0;
+ float threshold_reading = 0.0;
+ uint8_t threshold_reading_provided = 0;
+
+ /* trigger reading in event data byte 2 */
+ if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) {
+ trigger_reading = sdr_convert_sensor_reading(
+ sdr->record.full, evt->sel_type.standard_type.event_data[1]);
+ }
+
+ /* trigger threshold in event data byte 3 */
+ if (((evt->sel_type.standard_type.event_data[0] >> 4) & 3) == 1) {
+ threshold_reading = sdr_convert_sensor_reading(
+ sdr->record.full, evt->sel_type.standard_type.event_data[2]);
+ threshold_reading_provided = 1;
+ }
+
+ if (csv_output)
+ printf(",");
+ else
+ printf(" | ");
+
+ printf("Reading %.*f",
+ (trigger_reading==(int)trigger_reading) ? 0 : 2,
+ trigger_reading);
+ if (threshold_reading_provided) {
+ printf(" %s Threshold %.*f %s",
+ ((evt->sel_type.standard_type.event_data[0] & 0xf) % 2) ? ">" : "<",
+ (threshold_reading==(int)threshold_reading) ? 0 : 2,
+ threshold_reading,
+ ipmi_sdr_get_unit_string(sdr->record.common->unit.pct,
+ sdr->record.common->unit.modifier,
+ sdr->record.common->unit.type.base,
+ sdr->record.common->unit.type.modifier));
+ }
+ }
+ else if (evt->sel_type.standard_type.event_type == 0x6f) {
+ int print_sensor = 1;
+ switch (ipmi_get_oem(intf)) {
+ case IPMI_OEM_SUPERMICRO:
+ case IPMI_OEM_SUPERMICRO_47488:
+ print_sensor = 0;
+ break;
+ }
+ /*
+ * Sensor-Specific Discrete
+ */
+ if (print_sensor && evt->sel_type.standard_type.sensor_type == 0xC && /*TODO*/
+ evt->sel_type.standard_type.sensor_num == 0 &&
+ (evt->sel_type.standard_type.event_data[0] & 0x30) == 0x20) {
+ /* break down memory ECC reporting if we can */
+ if (csv_output)
+ printf(",");
+ else
+ printf(" | ");
+
+ printf("CPU %d DIMM %d",
+ evt->sel_type.standard_type.event_data[2] & 0x0f,
+ (evt->sel_type.standard_type.event_data[2] & 0xf0) >> 4);
+ }
+ }
+
+ printf("\n");
+}
+
+void
+ipmi_sel_print_std_entry_verbose(struct ipmi_intf * intf, struct sel_event_record * evt)
+{
+ char * description;
+ int data_count;
+
+ if (!evt)
+ return;
+
+ printf("SEL Record ID : %04x\n", evt->record_id);
+
+ if (evt->record_type == 0xf0)
+ {
+ printf (" Record Type : Linux kernel panic (OEM record %02x)\n", evt->record_type);
+ printf (" Panic string : %.11s\n\n", (char *) evt + 5);
+ return;
+ }
+
+ printf(" Record Type : %02x", evt->record_type);
+ if (evt->record_type >= 0xc0)
+ {
+ if (evt->record_type < 0xe0)
+ printf(" (OEM timestamped)");
+ else
+ printf(" (OEM non-timestamped)");
+ }
+ printf("\n");
+
+ if (evt->record_type < 0xe0)
+ {
+ printf(" Timestamp : ");
+ if (evt->record_type < 0xc0)
+ printf("%s %s", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp),
+ ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp));
+ else
+ printf("%s %s", ipmi_sel_timestamp_date(evt->sel_type.oem_ts_type.timestamp),
+ ipmi_sel_timestamp_time(evt->sel_type.oem_ts_type.timestamp));
+ printf("\n");
+ }
+
+ if (evt->record_type >= 0xc0)
+ {
+ if(evt->record_type < 0xdf)
+ {
+ printf (" Manufactacturer ID : %02x%02x%02x\n", evt->sel_type.oem_ts_type.manf_id[0],
+ evt->sel_type.oem_ts_type.manf_id[1], evt->sel_type.oem_ts_type.manf_id[2]);
+ printf (" OEM Defined : ");
+ for(data_count=0;data_count < SEL_OEM_TS_DATA_LEN;data_count++)
+ printf("%02x", evt->sel_type.oem_ts_type.oem_defined[data_count]);
+ printf(" [%s]\n\n",hex2ascii (evt->sel_type.oem_ts_type.oem_defined, SEL_OEM_TS_DATA_LEN));
+ }
+ else
+ {
+ printf (" OEM Defined : ");
+ for(data_count=0;data_count < SEL_OEM_NOTS_DATA_LEN;data_count++)
+ printf("%02x", evt->sel_type.oem_nots_type.oem_defined[data_count]);
+ printf(" [%s]\n\n",hex2ascii (evt->sel_type.oem_nots_type.oem_defined, SEL_OEM_NOTS_DATA_LEN));
+ ipmi_sel_oem_message(evt, 1);
+ }
+ return;
+ }
+
+ printf(" Generator ID : %04x\n",
+ evt->sel_type.standard_type.gen_id);
+ printf(" EvM Revision : %02x\n",
+ evt->sel_type.standard_type.evm_rev);
+ printf(" Sensor Type : %s\n",
+ (
+ (evt->sel_type.standard_type.sensor_type >=0xC0 && evt->sel_type.standard_type.sensor_type < 0xF0)
+ ?
+ ipmi_sel_get_oem_sensor_type_offset(ipmi_get_oem(intf),evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ :
+ ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0])
+ )
+ );
+ printf(" Sensor Number : %02x\n",
+ evt->sel_type.standard_type.sensor_num);
+ printf(" Event Type : %s\n",
+ ipmi_get_event_type(evt->sel_type.standard_type.event_type));
+ printf(" Event Direction : %s\n",
+ val2str(evt->sel_type.standard_type.event_dir, event_dir_vals));
+ printf(" Event Data : %02x%02x%02x\n",
+ evt->sel_type.standard_type.event_data[0], evt->sel_type.standard_type.event_data[1], evt->sel_type.standard_type.event_data[2]);
+ ipmi_get_event_desc(intf, evt, &description);
+ printf(" Description : %s\n",
+ description ? description : "");
+ free(description);
+ description = NULL;
+
+ printf("\n");
+}
+
+
+void
+ipmi_sel_print_extended_entry_verbose(struct ipmi_intf * intf, struct sel_event_record * evt)
+{
+ struct sdr_record_list * sdr;
+ char * description;
+
+ if (!evt)
+ return;
+
+ sdr = ipmi_sdr_find_sdr_bynumtype(intf,
+ evt->sel_type.standard_type.gen_id,
+ evt->sel_type.standard_type.sensor_num,
+ evt->sel_type.standard_type.sensor_type);
+ if (sdr == NULL)
+ {
+ ipmi_sel_print_std_entry_verbose(intf, evt);
+ return;
+ }
+
+ printf("SEL Record ID : %04x\n", evt->record_id);
+
+ if (evt->record_type == 0xf0)
+ {
+ printf (" Record Type : "
+ "Linux kernel panic (OEM record %02x)\n",
+ evt->record_type);
+ printf (" Panic string : %.11s\n\n",
+ (char *) evt + 5);
+ return;
+ }
+
+ printf(" Record Type : %02x\n", evt->record_type);
+ if (evt->record_type < 0xe0)
+ {
+ printf(" Timestamp : ");
+ printf("%s %s\n", ipmi_sel_timestamp_date(evt->sel_type.standard_type.timestamp),
+ ipmi_sel_timestamp_time(evt->sel_type.standard_type.timestamp));
+ }
+
+
+ printf(" Generator ID : %04x\n",
+ evt->sel_type.standard_type.gen_id);
+ printf(" EvM Revision : %02x\n",
+ evt->sel_type.standard_type.evm_rev);
+ printf(" Sensor Type : %s\n",
+ ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, evt->sel_type.standard_type.event_data[0]));
+ printf(" Sensor Number : %02x\n",
+ evt->sel_type.standard_type.sensor_num);
+ printf(" Event Type : %s\n",
+ ipmi_get_event_type(evt->sel_type.standard_type.event_type));
+ printf(" Event Direction : %s\n",
+ val2str(evt->sel_type.standard_type.event_dir, event_dir_vals));
+ printf(" Event Data (RAW) : %02x%02x%02x\n",
+ evt->sel_type.standard_type.event_data[0], evt->sel_type.standard_type.event_data[1], evt->sel_type.standard_type.event_data[2]);
+
+ /* break down event data field
+ * as per IPMI Spec 2.0 Table 29-6 */
+ if (evt->sel_type.standard_type.event_type == 1 && sdr->type == SDR_RECORD_TYPE_FULL_SENSOR) {
+ /* Threshold */
+ switch ((evt->sel_type.standard_type.event_data[0] >> 6) & 3) { /* EV1[7:6] */
+ case 0:
+ /* unspecified byte 2 */
+ break;
+ case 1:
+ /* trigger reading in byte 2 */
+ printf(" Trigger Reading : %.3f",
+ sdr_convert_sensor_reading(sdr->record.full,
+ evt->sel_type.standard_type.event_data[1]));
+ /* determine units with possible modifiers */
+ printf ("%s\n", ipmi_sdr_get_unit_string(sdr->record.common->unit.pct,
+ sdr->record.common->unit.modifier,
+ sdr->record.common->unit.type.base,
+ sdr->record.common->unit.type.modifier));
+ break;
+ case 2:
+ /* oem code in byte 2 */
+ printf(" OEM Data : %02x\n",
+ evt->sel_type.standard_type.event_data[1]);
+ break;
+ case 3:
+ /* sensor-specific extension code in byte 2 */
+ printf(" Sensor Extension Code : %02x\n",
+ evt->sel_type.standard_type.event_data[1]);
+ break;
+ }
+ switch ((evt->sel_type.standard_type.event_data[0] >> 4) & 3) { /* EV1[5:4] */
+ case 0:
+ /* unspecified byte 3 */
+ break;
+ case 1:
+ /* trigger threshold value in byte 3 */
+ printf(" Trigger Threshold : %.3f",
+ sdr_convert_sensor_reading(sdr->record.full,
+ evt->sel_type.standard_type.event_data[2]));
+ /* determine units with possible modifiers */
+ printf ("%s\n", ipmi_sdr_get_unit_string(sdr->record.common->unit.pct,
+ sdr->record.common->unit.modifier,
+ sdr->record.common->unit.type.base,
+ sdr->record.common->unit.type.modifier));
+ break;
+ case 2:
+ /* OEM code in byte 3 */
+ printf(" OEM Data : %02x\n",
+ evt->sel_type.standard_type.event_data[2]);
+ break;
+ case 3:
+ /* sensor-specific extension code in byte 3 */
+ printf(" Sensor Extension Code : %02x\n",
+ evt->sel_type.standard_type.event_data[2]);
+ break;
+ }
+ } else if (evt->sel_type.standard_type.event_type >= 0x2 && evt->sel_type.standard_type.event_type <= 0xc) {
+ /* Generic Discrete */
+ } else if (evt->sel_type.standard_type.event_type == 0x6f) {
+
+ /* Sensor-Specific Discrete */
+ if (evt->sel_type.standard_type.sensor_type == 0xC &&
+ evt->sel_type.standard_type.sensor_num == 0 && /**** THIS LOOK TO BE OEM ****/
+ (evt->sel_type.standard_type.event_data[0] & 0x30) == 0x20)
+ {
+ /* break down memory ECC reporting if we can */
+ printf(" Event Data : CPU %d DIMM %d\n",
+ evt->sel_type.standard_type.event_data[2] & 0x0f,
+ (evt->sel_type.standard_type.event_data[2] & 0xf0) >> 4);
+ }
+ else if(
+ evt->sel_type.standard_type.sensor_type == 0x2b && /* Version change */
+ evt->sel_type.standard_type.event_data[0] == 0xC1 /* Data in Data 2 */
+ )
+
+ {
+ //evt->sel_type.standard_type.event_data[1]
+ }
+ else
+ {
+ /* FIXME : Add sensor specific discrete types */
+ printf(" Event Interpretation : Missing\n");
+ }
+ } else if (evt->sel_type.standard_type.event_type >= 0x70 && evt->sel_type.standard_type.event_type <= 0x7f) {
+ /* OEM */
+ } else {
+ printf(" Event Data : %02x%02x%02x\n",
+ evt->sel_type.standard_type.event_data[0], evt->sel_type.standard_type.event_data[1], evt->sel_type.standard_type.event_data[2]);
+ }
+
+ ipmi_get_event_desc(intf, evt, &description);
+ printf(" Description : %s\n",
+ description ? description : "");
+ free(description);
+ description = NULL;
+
+ printf("\n");
+}
+
+static int
+__ipmi_sel_savelist_entries(struct ipmi_intf * intf, int count, const char * savefile,
+ int binary)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint16_t next_id = 0, curr_id = 0;
+ struct sel_event_record evt;
+ int n=0;
+ FILE * fp = NULL;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_GET_SEL_INFO;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get SEL Info command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get SEL Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ if (verbose > 2)
+ printbuf(rsp->data, rsp->data_len, "sel_info");
+
+ if (rsp->data[1] == 0 && rsp->data[2] == 0) {
+ lprintf(LOG_ERR, "SEL has no entries");
+ return 0;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_RESERVE_SEL;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Reserve SEL command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Reserve SEL command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ if (count < 0) {
+ /** Show only the most recent 'count' records. */
+ int delta;
+ uint16_t entries;
+
+ req.msg.cmd = IPMI_CMD_GET_SEL_INFO;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get SEL Info command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get SEL Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ entries = buf2short(rsp->data + 1);
+ if (-count > entries)
+ count = -entries;
+
+ /* Get first record. */
+ next_id = ipmi_sel_get_std_entry(intf, 0, &evt);
+
+ delta = next_id - evt.record_id;
+
+ /* Get last record. */
+ next_id = ipmi_sel_get_std_entry(intf, 0xffff, &evt);
+
+ next_id = evt.record_id + count * delta + delta;
+ }
+
+ if (savefile != NULL) {
+ fp = ipmi_open_file_write(savefile);
+ }
+
+ while (next_id != 0xffff) {
+ curr_id = next_id;
+ lprintf(LOG_DEBUG, "SEL Next ID: %04x", curr_id);
+
+ next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt);
+ if (next_id == 0) {
+ /*
+ * usually next_id of zero means end but
+ * retry because some hardware has quirks
+ * and will return 0 randomly.
+ */
+ next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt);
+ if (next_id == 0)
+ break;
+ }
+
+ if (verbose)
+ ipmi_sel_print_std_entry_verbose(intf, &evt);
+ else
+ ipmi_sel_print_std_entry(intf, &evt);
+
+ if (fp != NULL) {
+ if (binary)
+ fwrite(&evt, 1, 16, fp);
+ else
+ ipmi_sel_print_event_file(intf, &evt, fp);
+ }
+
+ if (++n == count) {
+ break;
+ }
+ }
+
+ if (fp != NULL)
+ fclose(fp);
+
+ return 0;
+}
+
+static int
+ipmi_sel_list_entries(struct ipmi_intf * intf, int count)
+{
+ return __ipmi_sel_savelist_entries(intf, count, NULL, 0);
+}
+
+static int
+ipmi_sel_save_entries(struct ipmi_intf * intf, int count, const char * savefile)
+{
+ return __ipmi_sel_savelist_entries(intf, count, savefile, 0);
+}
+
+/*
+ * ipmi_sel_interpret
+ *
+ * return 0 on success,
+ * -1 on error
+ */
+static int
+ipmi_sel_interpret(struct ipmi_intf *intf, unsigned long iana,
+ const char *readfile, const char *format)
+{
+ FILE *fp = 0;
+ struct sel_event_record evt;
+ char *buffer = NULL;
+ char *cursor = NULL;
+ int status = 0;
+ /* since the interface is not used, iana is taken from
+ * the command line
+ */
+ sel_iana = iana;
+ if (strncmp("pps", format, 3) == 0) {
+ /* Parser for the following format */
+ /* 0x001F: Event: at Mar 27 06:41:10 2007;from:(0x9a,0,7);
+ * sensor:(0xc3,119); event:0x6f(asserted): 0xA3 0x00 0x88
+ * commonly found in PPS shelf managers
+ * Supports a tweak for hotswap events that are already interpreted.
+ */
+ fp = ipmi_open_file(readfile, 0);
+ if (fp == NULL) {
+ lprintf(LOG_ERR, "Failed to open file '%s' for reading.",
+ readfile);
+ return (-1);
+ }
+ buffer = (char *)malloc((size_t)256);
+ if (buffer == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ fclose(fp);
+ return (-1);
+ }
+ do {
+ /* Only allow complete lines to be parsed,
+ * hardcoded maximum line length
+ */
+ if (fgets(buffer, 256, fp) == NULL) {
+ status = (-1);
+ break;
+ }
+ if (strlen(buffer) > 255) {
+ lprintf(LOG_ERR, "ipmitool: invalid entry found in file.");
+ continue;
+ }
+ cursor = buffer;
+ /* assume normal "System" event */
+ evt.record_type = 2;
+ errno = 0;
+ evt.record_id = strtol((const char *)cursor, (char **)NULL, 16);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid record ID.");
+ status = (-1);
+ break;
+ }
+ evt.sel_type.standard_type.evm_rev = 4;
+
+ /* FIXME: convert*/
+ evt.sel_type.standard_type.timestamp;
+
+ /* skip timestamp */
+ cursor = index((const char *)cursor, ';');
+ cursor++;
+
+ /* FIXME: parse originator */
+ evt.sel_type.standard_type.gen_id = 0x0020;
+
+ /* skip originator info */
+ cursor = index((const char *)cursor, ';');
+ cursor++;
+
+ /* Get sensor type */
+ cursor = index((const char *)cursor, '(');
+ cursor++;
+
+ errno = 0;
+ evt.sel_type.standard_type.sensor_type =
+ strtol((const char *)cursor, (char **)NULL, 16);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Sensor Type.");
+ status = (-1);
+ break;
+ }
+ cursor = index((const char *)cursor, ',');
+ cursor++;
+
+ errno = 0;
+ evt.sel_type.standard_type.sensor_num =
+ strtol((const char *)cursor, (char **)NULL, 10);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Sensor Number.");
+ status = (-1);
+ break;
+ }
+
+ /* skip to event type info */
+ cursor = index((const char *)cursor, ':');
+ cursor++;
+
+ errno = 0;
+ evt.sel_type.standard_type.event_type=
+ strtol((const char *)cursor, (char **)NULL, 16);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Type.");
+ status = (-1);
+ break;
+ }
+
+ /* skip to event dir info */
+ cursor = index((const char *)cursor, '(');
+ cursor++;
+ if (*cursor == 'a') {
+ evt.sel_type.standard_type.event_dir = 0;
+ } else {
+ evt.sel_type.standard_type.event_dir = 1;
+ }
+ /* skip to data info */
+ cursor = index((const char *)cursor, ' ');
+ cursor++;
+
+ if (evt.sel_type.standard_type.sensor_type == 0xF0) {
+ /* got to FRU id */
+ while (!isdigit(*cursor)) {
+ cursor++;
+ }
+ /* store FRUid */
+ errno = 0;
+ evt.sel_type.standard_type.event_data[2] =
+ strtol(cursor, (char **)NULL, 10);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Data#2.");
+ status = (-1);
+ break;
+ }
+
+ /* Get to previous state */
+ cursor = index((const char *)cursor, 'M');
+ cursor++;
+
+ /* Set previous state */
+ errno = 0;
+ evt.sel_type.standard_type.event_data[1] =
+ strtol(cursor, (char **)NULL, 10);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Data#1.");
+ status = (-1);
+ break;
+ }
+
+ /* Get to current state */
+ cursor = index((const char *)cursor, 'M');
+ cursor++;
+
+ /* Set current state */
+ errno = 0;
+ evt.sel_type.standard_type.event_data[0] =
+ 0xA0 | strtol(cursor, (char **)NULL, 10);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Data#0.");
+ status = (-1);
+ break;
+ }
+
+ /* skip to cause */
+ cursor = index((const char *)cursor, '=');
+ cursor++;
+ errno = 0;
+ evt.sel_type.standard_type.event_data[1] |=
+ (strtol(cursor, (char **)NULL, 16)) << 4;
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Data#1.");
+ status = (-1);
+ break;
+ }
+ } else if (*cursor == '0') {
+ errno = 0;
+ evt.sel_type.standard_type.event_data[0] =
+ strtol((const char *)cursor, (char **)NULL, 16);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Data#0.");
+ status = (-1);
+ break;
+ }
+ cursor = index((const char *)cursor, ' ');
+ cursor++;
+
+ errno = 0;
+ evt.sel_type.standard_type.event_data[1] =
+ strtol((const char *)cursor, (char **)NULL, 16);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Data#1.");
+ status = (-1);
+ break;
+ }
+
+ cursor = index((const char *)cursor, ' ');
+ cursor++;
+
+ errno = 0;
+ evt.sel_type.standard_type.event_data[2] =
+ strtol((const char *)cursor, (char **)NULL, 16);
+ if (errno != 0) {
+ lprintf(LOG_ERR, "Invalid Event Data#2.");
+ status = (-1);
+ break;
+ }
+ } else {
+ lprintf(LOG_ERR, "ipmitool: can't guess format.");
+ }
+ /* parse the PPS line into a sel_event_record */
+ if (verbose) {
+ ipmi_sel_print_std_entry_verbose(intf, &evt);
+ } else {
+ ipmi_sel_print_std_entry(intf, &evt);
+ }
+ cursor = NULL;
+ } while (status == 0); /* until file is completely read */
+ cursor = NULL;
+ free(buffer);
+ buffer = NULL;
+ fclose(fp);
+ } else {
+ lprintf(LOG_ERR, "Given format '%s' is unknown.", format);
+ status = (-1);
+ }
+ return status;
+}
+
+
+static int
+ipmi_sel_writeraw(struct ipmi_intf * intf, const char * savefile)
+{
+ return __ipmi_sel_savelist_entries(intf, 0, savefile, 1);
+}
+
+
+static int
+ipmi_sel_readraw(struct ipmi_intf * intf, const char * inputfile)
+{
+ struct sel_event_record evt;
+ int ret = 0;
+ FILE* fp = 0;
+
+ fp = ipmi_open_file(inputfile, 0);
+ if (fp)
+ {
+ size_t bytesRead;
+
+ do {
+ if ((bytesRead = fread(&evt, 1, 16, fp)) == 16)
+ {
+ if (verbose)
+ ipmi_sel_print_std_entry_verbose(intf, &evt);
+ else
+ ipmi_sel_print_std_entry(intf, &evt);
+ }
+ else
+ {
+ if (bytesRead != 0)
+ {
+ lprintf(LOG_ERR, "ipmitool: incomplete record found in file.");
+ ret = -1;
+ }
+
+ break;
+ }
+
+ } while (1);
+ fclose(fp);
+ }
+ else
+ {
+ lprintf(LOG_ERR, "ipmitool: could not open input file.");
+ ret = -1;
+ }
+ return ret;
+}
+
+
+
+static uint16_t
+ipmi_sel_reserve(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_RESERVE_SEL;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_WARN, "Unable to reserve SEL");
+ return 0;
+ }
+ if (rsp->ccode > 0) {
+ printf("Unable to reserve SEL: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return 0;
+ }
+
+ return (rsp->data[0] | (rsp->data[1] << 8));
+}
+
+
+
+/*
+ * ipmi_sel_get_time
+ *
+ * return 0 on success,
+ * -1 on error
+ */
+static int
+ipmi_sel_get_time(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ static char tbuf[40];
+ uint32_t timei;
+ time_t time;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_GET_SEL_TIME;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get SEL Time command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get SEL Time command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ if (rsp->data_len != 4) {
+ lprintf(LOG_ERR, "Get SEL Time command failed: "
+ "Invalid data length %d", rsp->data_len);
+ return -1;
+ }
+
+ memcpy(&timei, rsp->data, 4);
+#if WORDS_BIGENDIAN
+ time = (time_t)(BSWAP_32(timei));
+#else
+ time = (time_t)timei;
+#endif
+
+ strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", gmtime(&time));
+ printf("%s\n", tbuf);
+
+ return 0;
+}
+
+
+
+/*
+ * ipmi_sel_set_time
+ *
+ * return 0 on success,
+ * -1 on error
+ */
+static int
+ipmi_sel_set_time(struct ipmi_intf * intf, const char * time_string)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct tm tm = {0};
+ time_t t;
+ uint32_t timei;
+ const char * time_format = "%m/%d/%Y %H:%M:%S";
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_SET_SEL_TIME;
+
+ /* See if user requested set to current client system time */
+ if (strncasecmp(time_string, "now", 3) == 0) {
+ t = time(NULL);
+ }
+ else {
+ /* Now how do we get our time_t from our ascii version? */
+ if (strptime(time_string, time_format, &tm) == 0) {
+ lprintf(LOG_ERR, "Specified time could not be parsed");
+ return -1;
+ }
+ tm.tm_isdst = (-1); /* look up DST information */
+ t = mktime(&tm);
+ if (t < 0) {
+ lprintf(LOG_ERR, "Specified time could not be parsed");
+ return -1;
+ }
+ }
+
+ {
+ //modify UTC time to local time expressed in number of seconds from 1/1/70 0:0:0 1970 GMT
+ struct tm * tm_tmp = {0};
+ int gt_year,gt_yday,gt_hour,lt_year,lt_yday,lt_hour;
+ int delta_hour;
+ tm_tmp=gmtime(&t);
+ gt_year=tm_tmp->tm_year;
+ gt_yday=tm_tmp->tm_yday;
+ gt_hour=tm_tmp->tm_hour;
+ memset(&*tm_tmp, 0, sizeof(struct tm));
+ tm_tmp=localtime(&t);
+ lt_year=tm_tmp->tm_year;
+ lt_yday=tm_tmp->tm_yday;
+ lt_hour=tm_tmp->tm_hour;
+ delta_hour=lt_hour - gt_hour;
+ if ( (lt_year > gt_year) || ((lt_year == gt_year) && (lt_yday > gt_yday)) )
+ delta_hour += 24;
+ if ( (lt_year < gt_year) || ((lt_year == gt_year) && (lt_yday < gt_yday)) )
+ delta_hour -= 24;
+
+ t += (delta_hour * 60 * 60);
+ }
+
+ timei = (uint32_t)t;
+ req.msg.data = (uint8_t *)&timei;
+ req.msg.data_len = 4;
+
+#if WORDS_BIGENDIAN
+ timei = BSWAP_32(timei);
+#endif
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set SEL Time command failed");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set SEL Time command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ ipmi_sel_get_time(intf);
+
+ return 0;
+}
+
+
+
+static int
+ipmi_sel_clear(struct ipmi_intf * intf)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint16_t reserve_id;
+ uint8_t msg_data[6];
+
+ reserve_id = ipmi_sel_reserve(intf);
+ if (reserve_id == 0)
+ return -1;
+
+ memset(msg_data, 0, 6);
+ msg_data[0] = reserve_id & 0xff;
+ msg_data[1] = reserve_id >> 8;
+ msg_data[2] = 'C';
+ msg_data[3] = 'L';
+ msg_data[4] = 'R';
+ msg_data[5] = 0xaa;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_CLEAR_SEL;
+ req.msg.data = msg_data;
+ req.msg.data_len = 6;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to clear SEL");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Unable to clear SEL: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ printf("Clearing SEL. Please allow a few seconds to erase.\n");
+ return 0;
+}
+
+static int
+ipmi_sel_delete(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint16_t id;
+ uint8_t msg_data[4];
+ int rc = 0;
+
+ if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
+ lprintf(LOG_ERR, "usage: delete <id>...<id>\n");
+ return -1;
+ }
+
+ id = ipmi_sel_reserve(intf);
+ if (id == 0)
+ return -1;
+
+ memset(msg_data, 0, 4);
+ msg_data[0] = id & 0xff;
+ msg_data[1] = id >> 8;
+
+ for (; argc != 0; argc--)
+ {
+ id = (uint16_t) strtoul(argv[argc-1], NULL, 0);
+ if (str2ushort(argv[argc-1], &id) != 0) {
+ lprintf(LOG_ERR, "Given SEL ID '%s' is invalid.",
+ argv[argc-1]);
+ rc = (-1);
+ continue;
+ }
+ msg_data[2] = id & 0xff;
+ msg_data[3] = id >> 8;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_STORAGE;
+ req.msg.cmd = IPMI_CMD_DELETE_SEL_ENTRY;
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to delete entry %d", id);
+ rc = -1;
+ }
+ else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Unable to delete entry %d: %s", id,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = -1;
+ }
+ else {
+ printf("Deleted entry %d\n", id);
+ }
+ }
+
+ return rc;
+}
+
+static int
+ipmi_sel_show_entry(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ uint16_t id;
+ int i, oldv;
+ struct sel_event_record evt;
+ struct sdr_record_list * sdr;
+ struct entity_id entity;
+ struct sdr_record_list * list, * entry;
+ int rc = 0;
+
+ if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
+ lprintf(LOG_ERR, "usage: sel get <id>...<id>");
+ return -1;
+ }
+
+ if (ipmi_sel_reserve(intf) == 0) {
+ lprintf(LOG_ERR, "Unable to reserve SEL");
+ return -1;
+ }
+
+ for (i=0; i<argc; i++) {
+ if (str2ushort(argv[i], &id) != 0) {
+ lprintf(LOG_ERR, "Given SEL ID '%s' is invalid.",
+ argv[i]);
+ rc = (-1);
+ continue;
+ }
+
+ lprintf(LOG_DEBUG, "Looking up SEL entry 0x%x", id);
+
+ /* lookup SEL entry based on ID */
+ if (!ipmi_sel_get_std_entry(intf, id, &evt)) {
+ lprintf(LOG_DEBUG, "SEL Entry 0x%x not found.", id);
+ rc = (-1);
+ continue;
+ }
+ if (evt.sel_type.standard_type.sensor_num == 0 && evt.sel_type.standard_type.sensor_type == 0 && evt.record_type == 0) {
+ lprintf(LOG_WARN, "SEL Entry 0x%x not found", id);
+ rc = -1;
+ continue;
+ }
+
+ /* lookup SDR entry based on sensor number and type */
+ ipmi_sel_print_extended_entry_verbose(intf, &evt);
+
+ sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt.sel_type.standard_type.gen_id, evt.sel_type.standard_type.sensor_num, evt.sel_type.standard_type.sensor_type);
+ if (sdr == NULL) {
+ continue;
+ }
+
+ /* print SDR entry */
+ oldv = verbose;
+ verbose = verbose ? : 1;
+ switch (sdr->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ ipmi_sensor_print_fc(intf, sdr->record.common,
+ sdr->type);
+ entity.id = sdr->record.common->entity.id;
+ entity.instance = sdr->record.common->entity.instance;
+ break;
+ case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
+ ipmi_sdr_print_sensor_eventonly(intf, sdr->record.eventonly);
+ entity.id = sdr->record.eventonly->entity.id;
+ entity.instance = sdr->record.eventonly->entity.instance;
+ break;
+ default:
+ verbose = oldv;
+ continue;
+ }
+ verbose = oldv;
+
+ /* lookup SDR entry based on entity id */
+ list = ipmi_sdr_find_sdr_byentity(intf, &entity);
+ for (entry=list; entry; entry=entry->next) {
+ /* print FRU devices we find for this entity */
+ if (entry->type == SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR)
+ ipmi_fru_print(intf, entry->record.fruloc);
+ }
+
+ if ((argc > 1) && (i<(argc-1)))
+ printf("----------------------\n\n");
+ }
+
+ return rc;
+}
+
+int ipmi_sel_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if (argc == 0)
+ rc = ipmi_sel_get_info(intf);
+ else if (strncmp(argv[0], "help", 4) == 0)
+ lprintf(LOG_ERR, "SEL Commands: "
+ "info clear delete list elist get add time save readraw writeraw interpret");
+ else if (strncmp(argv[0], "interpret", 9) == 0) {
+ uint32_t iana = 0;
+ if (argc < 4) {
+ lprintf(LOG_NOTICE, "usage: sel interpret iana filename format(pps)");
+ return 0;
+ }
+ if (str2uint(argv[1], &iana) != 0) {
+ lprintf(LOG_ERR, "Given IANA '%s' is invalid.",
+ argv[1]);
+ return (-1);
+ }
+ rc = ipmi_sel_interpret(intf, iana, argv[2], argv[3]);
+ }
+ else if (strncmp(argv[0], "info", 4) == 0)
+ rc = ipmi_sel_get_info(intf);
+ else if (strncmp(argv[0], "save", 4) == 0) {
+ if (argc < 2) {
+ lprintf(LOG_NOTICE, "usage: sel save <filename>");
+ return 0;
+ }
+ rc = ipmi_sel_save_entries(intf, 0, argv[1]);
+ }
+ else if (strncmp(argv[0], "add", 3) == 0) {
+ if (argc < 2) {
+ lprintf(LOG_NOTICE, "usage: sel add <filename>");
+ return 0;
+ }
+ rc = ipmi_sel_add_entries_fromfile(intf, argv[1]);
+ }
+ else if (strncmp(argv[0], "writeraw", 8) == 0) {
+ if (argc < 2) {
+ lprintf(LOG_NOTICE, "usage: sel writeraw <filename>");
+ return 0;
+ }
+ rc = ipmi_sel_writeraw(intf, argv[1]);
+ }
+ else if (strncmp(argv[0], "readraw", 7) == 0) {
+ if (argc < 2) {
+ lprintf(LOG_NOTICE, "usage: sel readraw <filename>");
+ return 0;
+ }
+ rc = ipmi_sel_readraw(intf, argv[1]);
+ }
+ else if (strncmp(argv[0], "ereadraw", 8) == 0) {
+ if (argc < 2) {
+ lprintf(LOG_NOTICE, "usage: sel ereadraw <filename>");
+ return 0;
+ }
+ sel_extended = 1;
+ rc = ipmi_sel_readraw(intf, argv[1]);
+ }
+ else if (strncmp(argv[0], "list", 4) == 0 ||
+ strncmp(argv[0], "elist", 5) == 0) {
+ /*
+ * Usage:
+ * list - show all SEL entries
+ * list first <n> - show the first (oldest) <n> SEL entries
+ * list last <n> - show the last (newsest) <n> SEL entries
+ */
+ int count = 0;
+ int sign = 1;
+ char *countstr = NULL;
+
+ if (strncmp(argv[0], "elist", 5) == 0)
+ sel_extended = 1;
+ else
+ sel_extended = 0;
+
+ if (argc == 2) {
+ countstr = argv[1];
+ }
+ else if (argc == 3) {
+ countstr = argv[2];
+
+ if (strncmp(argv[1], "last", 4) == 0) {
+ sign = -1;
+ }
+ else if (strncmp(argv[1], "first", 5) != 0) {
+ lprintf(LOG_ERR, "Unknown sel list option");
+ return -1;
+ }
+ }
+
+ if (countstr) {
+ if (str2int(countstr, &count) != 0) {
+ lprintf(LOG_ERR, "Numeric argument required; got '%s'",
+ countstr);
+ return -1;
+ }
+ }
+ count *= sign;
+
+ rc = ipmi_sel_list_entries(intf,count);
+ }
+ else if (strncmp(argv[0], "clear", 5) == 0)
+ rc = ipmi_sel_clear(intf);
+ else if (strncmp(argv[0], "delete", 6) == 0) {
+ if (argc < 2)
+ lprintf(LOG_ERR, "usage: sel delete <id>...<id>");
+ else
+ rc = ipmi_sel_delete(intf, argc-1, &argv[1]);
+ }
+ else if (strncmp(argv[0], "get", 3) == 0) {
+ if (argc < 2)
+ lprintf(LOG_ERR, "usage: sel get <entry>");
+ else
+ rc = ipmi_sel_show_entry(intf, argc-1, &argv[1]);
+ }
+ else if (strncmp(argv[0], "time", 4) == 0) {
+ if (argc < 2)
+ lprintf(LOG_ERR, "sel time commands: get set");
+ else if (strncmp(argv[1], "get", 3) == 0)
+ ipmi_sel_get_time(intf);
+ else if (strncmp(argv[1], "set", 3) == 0) {
+ if (argc < 3)
+ lprintf(LOG_ERR, "usage: sel time set \"mm/dd/yyyy hh:mm:ss\"");
+ else
+ rc = ipmi_sel_set_time(intf, argv[2]);
+ } else {
+ lprintf(LOG_ERR, "sel time commands: get set");
+ }
+ }
+ else {
+ lprintf(LOG_ERR, "Invalid SEL command: %s", argv[0]);
+ rc = -1;
+ }
+
+ return rc;
+}
diff --git a/lib/ipmi_sensor.c b/lib/ipmi_sensor.c
new file mode 100644
index 0000000..4ef5138
--- /dev/null
+++ b/lib/ipmi_sensor.c
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_sensor.h>
+
+extern int verbose;
+void printf_sensor_get_usage();
+
+// Macro's for Reading the current sensor Data.
+#define SCANNING_DISABLED 0x40
+#define READING_UNAVAILABLE 0x20
+#define INVALID_THRESHOLD "Invalid Threshold data values. Cannot Set Threshold Data."
+// static
+int
+ipmi_sensor_get_sensor_reading_factors(
+ struct ipmi_intf * intf,
+ struct sdr_record_full_sensor * sensor,
+ uint8_t reading)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ uint8_t req_data[2];
+
+ char id[17];
+
+ if (intf == NULL || sensor == NULL)
+ return -1;
+
+ memset(id, 0, sizeof(id));
+ memcpy(id, sensor->id_string, 16);
+
+ req_data[0] = sensor->cmn.keys.sensor_num;
+ req_data[1] = reading;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = sensor->cmn.keys.lun;
+ req.msg.cmd = GET_SENSOR_FACTORS;
+ req.msg.data = req_data;
+ req.msg.data_len = sizeof(req_data);
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error updating reading factor for sensor %s (#%02x)",
+ id, sensor->cmn.keys.sensor_num);
+ return -1;
+ } else if (rsp->ccode) {
+ return -1;
+ } else {
+ /* Update SDR copy with updated Reading Factors for this reading */
+ /* Note:
+ * The Format of the returned data is exactly as in the SDR definition (Little Endian Format),
+ * therefore we can use raw copy operation here.
+ * Note: rsp->data[0] would point to the next valid entry in the sampling table
+ */
+ // BUGBUG: uses 'hardcoded' length information from SDR Definition
+ memcpy(&sensor->mtol, &rsp->data[1], sizeof(sensor->mtol));
+ memcpy(&sensor->bacc, &rsp->data[3], sizeof(sensor->bacc));
+ return 0;
+ }
+
+}
+
+static
+struct ipmi_rs *
+ipmi_sensor_set_sensor_thresholds(struct ipmi_intf *intf,
+ uint8_t sensor,
+ uint8_t threshold, uint8_t setting,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rq req;
+ static struct sensor_set_thresh_rq set_thresh_rq;
+ struct ipmi_rs *rsp;
+ uint8_t bridged_request = 0;
+ uint32_t save_addr;
+ uint32_t save_channel;
+
+ memset(&set_thresh_rq, 0, sizeof (set_thresh_rq));
+ set_thresh_rq.sensor_num = sensor;
+ set_thresh_rq.set_mask = threshold;
+ if (threshold == UPPER_NON_RECOV_SPECIFIED)
+ set_thresh_rq.upper_non_recov = setting;
+ else if (threshold == UPPER_CRIT_SPECIFIED)
+ set_thresh_rq.upper_crit = setting;
+ else if (threshold == UPPER_NON_CRIT_SPECIFIED)
+ set_thresh_rq.upper_non_crit = setting;
+ else if (threshold == LOWER_NON_CRIT_SPECIFIED)
+ set_thresh_rq.lower_non_crit = setting;
+ else if (threshold == LOWER_CRIT_SPECIFIED)
+ set_thresh_rq.lower_crit = setting;
+ else if (threshold == LOWER_NON_RECOV_SPECIFIED)
+ set_thresh_rq.lower_non_recov = setting;
+ else
+ return NULL;
+
+ if (BRIDGE_TO_SENSOR(intf, target, channel)) {
+ bridged_request = 1;
+ save_addr = intf->target_addr;
+ intf->target_addr = target;
+ save_channel = intf->target_channel;
+ intf->target_channel = channel;
+ }
+ memset(&req, 0, sizeof (req));
+ req.msg.netfn = IPMI_NETFN_SE;
+ req.msg.lun = lun;
+ req.msg.cmd = SET_SENSOR_THRESHOLDS;
+ req.msg.data = (uint8_t *) & set_thresh_rq;
+ req.msg.data_len = sizeof (set_thresh_rq);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (bridged_request) {
+ intf->target_addr = save_addr;
+ intf->target_channel = save_channel;
+ }
+ return rsp;
+}
+
+static int
+ipmi_sensor_print_fc_discrete(struct ipmi_intf *intf,
+ struct sdr_record_common_sensor *sensor,
+ uint8_t sdr_record_type)
+{
+ const char *id;
+ struct sensor_reading *sr;
+
+ sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 3);
+
+ if (sr == NULL) {
+ return -1;
+ }
+
+ if (csv_output) {
+ /* NOT IMPLEMENTED */
+ } else {
+ if (verbose == 0) {
+ /* output format
+ * id value units status thresholds....
+ */
+ printf("%-16s ", sr->s_id);
+ if (sr->s_reading_valid) {
+ if (sr->s_has_analog_value) {
+ /* don't show discrete component */
+ printf("| %-10s | %-10s | %-6s",
+ sr->s_a_str, sr->s_a_units, "ok");
+ } else {
+ printf("| 0x%-8x | %-10s | 0x%02x%02x",
+ sr->s_reading, "discrete",
+ sr->s_data2, sr->s_data3);
+ }
+ } else {
+ printf("| %-10s | %-10s | %-6s",
+ "na", "discrete", "na");
+ }
+ printf("| %-10s| %-10s| %-10s| %-10s| %-10s| %-10s",
+ "na", "na", "na", "na", "na", "na");
+
+ printf("\n");
+ } else {
+ printf("Sensor ID : %s (0x%x)\n",
+ sr->s_id, sensor->keys.sensor_num);
+ printf(" Entity ID : %d.%d\n",
+ sensor->entity.id, sensor->entity.instance);
+ printf(" Sensor Type (Discrete): %s\n",
+ ipmi_sdr_get_sensor_type_desc(sensor->sensor.
+ type));
+ if( sr->s_reading_valid )
+ {
+ if (sr->s_has_analog_value) {
+ printf(" Sensor Reading : %s %s\n", sr->s_a_str, sr->s_a_units);
+ }
+ ipmi_sdr_print_discrete_state("States Asserted",
+ sensor->sensor.type,
+ sensor->event_type,
+ sr->s_data2,
+ sr->s_data3);
+ printf("\n");
+ } else {
+ printf(" Unable to read sensor: Device Not Present\n\n");
+ }
+ }
+ }
+
+ return (sr->s_reading_valid ? 0 : -1 );
+}
+
+static void
+print_thresh_setting(struct sdr_record_full_sensor *full,
+ uint8_t thresh_is_avail, uint8_t setting,
+ const char *field_sep,
+ const char *analog_fmt,
+ const char *discrete_fmt,
+ const char *na_fmt)
+{
+ printf("%s", field_sep);
+ if (!thresh_is_avail) {
+ printf(na_fmt, "na");
+ return;
+ }
+ if (full && !UNITS_ARE_DISCRETE(&full->cmn)) {
+ printf(analog_fmt, sdr_convert_sensor_reading (full, setting));
+ } else {
+ printf(discrete_fmt, setting);
+ }
+}
+
+static int
+ipmi_sensor_print_fc_threshold(struct ipmi_intf *intf,
+ struct sdr_record_common_sensor *sensor,
+ uint8_t sdr_record_type)
+{
+ int thresh_available = 1;
+ struct ipmi_rs *rsp;
+ struct sensor_reading *sr;
+
+ sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 3);
+
+ if (sr == NULL) {
+ return -1;
+ }
+
+ const char *thresh_status = ipmi_sdr_get_thresh_status(sr, "ns");
+
+ /*
+ * Get sensor thresholds
+ */
+ rsp = ipmi_sdr_get_sensor_thresholds(intf,
+ sensor->keys.sensor_num, sensor->keys.owner_id,
+ sensor->keys.lun, sensor->keys.channel);
+
+ if ((rsp == NULL) || (rsp->ccode > 0) || (rsp->data_len == 0))
+ thresh_available = 0;
+
+ if (csv_output) {
+ /* NOT IMPLEMENTED */
+ } else {
+ if (verbose == 0) {
+ /* output format
+ * id value units status thresholds....
+ */
+ printf("%-16s ", sr->s_id);
+ if (sr->s_reading_valid) {
+ if (sr->s_has_analog_value)
+ printf("| %-10.3f | %-10s | %-6s",
+ sr->s_a_val, sr->s_a_units, thresh_status);
+ else
+ printf("| 0x%-8x | %-10s | %-6s",
+ sr->s_reading, sr->s_a_units, thresh_status);
+ } else {
+ printf("| %-10s | %-10s | %-6s",
+ "na", sr->s_a_units, "na");
+ }
+ if (thresh_available && sr->full) {
+#define PTS(bit, dataidx) { \
+ print_thresh_setting(sr->full, rsp->data[0] & (bit), \
+ rsp->data[(dataidx)], "| ", "%-10.3f", "0x-8x", "%-10s"); \
+}
+ PTS(LOWER_NON_RECOV_SPECIFIED, 3);
+ PTS(LOWER_CRIT_SPECIFIED, 2);
+ PTS(LOWER_NON_CRIT_SPECIFIED, 1);
+ PTS(UPPER_NON_CRIT_SPECIFIED, 4);
+ PTS(UPPER_CRIT_SPECIFIED, 5);
+ PTS(UPPER_NON_RECOV_SPECIFIED, 6);
+#undef PTS
+ } else {
+ printf
+ ("| %-10s| %-10s| %-10s| %-10s| %-10s| %-10s",
+ "na", "na", "na", "na", "na", "na");
+ }
+
+ printf("\n");
+ } else {
+ printf("Sensor ID : %s (0x%x)\n",
+ sr->s_id, sensor->keys.sensor_num);
+
+ printf(" Entity ID : %d.%d\n",
+ sensor->entity.id, sensor->entity.instance);
+
+ printf(" Sensor Type (Threshold) : %s\n",
+ ipmi_sdr_get_sensor_type_desc(sensor->sensor.
+ type));
+
+ printf(" Sensor Reading : ");
+ if (sr->s_reading_valid) {
+ if (sr->full) {
+ uint16_t raw_tol = __TO_TOL(sr->full->mtol);
+ if (sr->s_has_analog_value) {
+ double tol =
+ sdr_convert_sensor_tolerance(sr->full,
+ raw_tol);
+ printf("%.*f (+/- %.*f) %s\n",
+ (sr->s_a_val == (int)
+ sr->s_a_val) ? 0 : 3,
+ sr->s_a_val,
+ (tol == (int) tol) ? 0 : 3, tol,
+ sr->s_a_units);
+ } else {
+ printf("0x%x (+/- 0x%x) %s\n",
+ sr->s_reading,
+ raw_tol,
+ sr->s_a_units);
+ }
+ } else {
+ printf("0x%x %s\n", sr->s_reading,
+ sr->s_a_units);
+ }
+ printf(" Status : %s\n", thresh_status);
+
+ if (thresh_available) {
+ if (sr->full) {
+#define PTS(bit, dataidx, str) { \
+print_thresh_setting(sr->full, rsp->data[0] & (bit), \
+ rsp->data[(dataidx)], \
+ (str), "%.3f\n", "0x%x\n", "%s\n"); \
+}
+
+ PTS(LOWER_NON_RECOV_SPECIFIED, 3, " Lower Non-Recoverable : ");
+ PTS(LOWER_CRIT_SPECIFIED, 2, " Lower Critical : ");
+ PTS(LOWER_NON_CRIT_SPECIFIED, 1, " Lower Non-Critical : ");
+ PTS(UPPER_NON_CRIT_SPECIFIED, 4, " Upper Non-Critical : ");
+ PTS(UPPER_CRIT_SPECIFIED, 5, " Upper Critical : ");
+ PTS(UPPER_NON_RECOV_SPECIFIED, 6, " Upper Non-Recoverable : ");
+#undef PTS
+
+ }
+ ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
+ sr->full ? sr->full->threshold.hysteresis.positive :
+ sr->compact->threshold.hysteresis.positive,
+ "Positive Hysteresis");
+
+ ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
+ sr->full ? sr->full->threshold.hysteresis.negative :
+ sr->compact->threshold.hysteresis.negative,
+ "Negative Hysteresis");
+ } else {
+ printf(" Sensor Threshold Settings not available\n");
+ }
+ } else {
+ printf(" Unable to read sensor: Device Not Present\n\n");
+ }
+
+ ipmi_sdr_print_sensor_event_status(intf,
+ sensor->keys.
+ sensor_num,
+ sensor->sensor.type,
+ sensor->event_type,
+ ANALOG_SENSOR,
+ sensor->keys.owner_id,
+ sensor->keys.lun,
+ sensor->keys.channel);
+ ipmi_sdr_print_sensor_event_enable(intf,
+ sensor->keys.
+ sensor_num,
+ sensor->sensor.type,
+ sensor->event_type,
+ ANALOG_SENSOR,
+ sensor->keys.owner_id,
+ sensor->keys.lun,
+ sensor->keys.channel);
+
+ printf("\n");
+ }
+ }
+
+ return (sr->s_reading_valid ? 0 : -1 );
+}
+
+int
+ipmi_sensor_print_fc(struct ipmi_intf *intf,
+ struct sdr_record_common_sensor *sensor,
+ uint8_t sdr_record_type)
+{
+ if (IS_THRESHOLD_SENSOR(sensor))
+ return ipmi_sensor_print_fc_threshold(intf, sensor, sdr_record_type);
+ else
+ return ipmi_sensor_print_fc_discrete(intf, sensor, sdr_record_type);
+}
+
+static int
+ipmi_sensor_list(struct ipmi_intf *intf)
+{
+ struct sdr_get_rs *header;
+ struct ipmi_sdr_iterator *itr;
+ int rc = 0;
+
+ lprintf(LOG_DEBUG, "Querying SDR for sensor list");
+
+ itr = ipmi_sdr_start(intf, 0);
+ if (itr == NULL) {
+ lprintf(LOG_ERR, "Unable to open SDR for reading");
+ return -1;
+ }
+
+ while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
+ uint8_t *rec;
+
+ rec = ipmi_sdr_get_record(intf, header, itr);
+ if (rec == NULL) {
+ lprintf(LOG_DEBUG, "rec == NULL");
+ continue;
+ }
+
+ switch (header->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ ipmi_sensor_print_fc(intf,
+ (struct
+ sdr_record_common_sensor *)
+ rec,
+ header->type);
+ break;
+ }
+ free(rec);
+ rec = NULL;
+
+ /* fix for CR6604909: */
+ /* mask failure of individual reads in sensor list command */
+ /* rc = (r == 0) ? rc : r; */
+ }
+
+ ipmi_sdr_end(intf, itr);
+
+ return rc;
+}
+
+static const struct valstr threshold_vals[] = {
+ {UPPER_NON_RECOV_SPECIFIED, "Upper Non-Recoverable"},
+ {UPPER_CRIT_SPECIFIED, "Upper Critical"},
+ {UPPER_NON_CRIT_SPECIFIED, "Upper Non-Critical"},
+ {LOWER_NON_RECOV_SPECIFIED, "Lower Non-Recoverable"},
+ {LOWER_CRIT_SPECIFIED, "Lower Critical"},
+ {LOWER_NON_CRIT_SPECIFIED, "Lower Non-Critical"},
+ {0x00, NULL},
+};
+
+static int
+__ipmi_sensor_set_threshold(struct ipmi_intf *intf,
+ uint8_t num, uint8_t mask, uint8_t setting,
+ uint8_t target, uint8_t lun, uint8_t channel)
+{
+ struct ipmi_rs *rsp;
+
+ rsp = ipmi_sensor_set_sensor_thresholds(intf, num, mask, setting,
+ target, lun, channel);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error setting threshold");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Error setting threshold: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint8_t
+__ipmi_sensor_threshold_value_to_raw(struct sdr_record_full_sensor *full, double value)
+{
+ if (!UNITS_ARE_DISCRETE(&full->cmn)) { /* Has an analog reading */
+ /* Has an analog reading and supports mx+b */
+ return sdr_convert_sensor_value_to_raw(full, value);
+ }
+ else {
+ /* Does not have an analog reading and/or does not support mx+b */
+ if (value > 255) {
+ return 255;
+ }
+ else if (value < 0) {
+ return 0;
+ }
+ else {
+ return (uint8_t )value;
+ }
+ }
+}
+
+
+static int
+ipmi_sensor_set_threshold(struct ipmi_intf *intf, int argc, char **argv)
+{
+ char *id, *thresh;
+ uint8_t settingMask = 0;
+ double setting1 = 0.0, setting2 = 0.0, setting3 = 0.0;
+ int allUpper = 0, allLower = 0;
+ int ret = 0;
+ struct ipmi_rs *rsp;
+ int i =0;
+ double val[10] = {0};
+
+ struct sdr_record_list *sdr;
+
+ if (argc < 3 || strncmp(argv[0], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "sensor thresh <id> <threshold> <setting>");
+ lprintf(LOG_NOTICE,
+ " id : name of the sensor for which threshold is to be set");
+ lprintf(LOG_NOTICE, " threshold : which threshold to set");
+ lprintf(LOG_NOTICE,
+ " unr = upper non-recoverable");
+ lprintf(LOG_NOTICE, " ucr = upper critical");
+ lprintf(LOG_NOTICE,
+ " unc = upper non-critical");
+ lprintf(LOG_NOTICE,
+ " lnc = lower non-critical");
+ lprintf(LOG_NOTICE, " lcr = lower critical");
+ lprintf(LOG_NOTICE,
+ " lnr = lower non-recoverable");
+ lprintf(LOG_NOTICE,
+ " setting : the value to set the threshold to");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE,
+ "sensor thresh <id> lower <lnr> <lcr> <lnc>");
+ lprintf(LOG_NOTICE,
+ " Set all lower thresholds at the same time");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE,
+ "sensor thresh <id> upper <unc> <ucr> <unr>");
+ lprintf(LOG_NOTICE,
+ " Set all upper thresholds at the same time");
+ lprintf(LOG_NOTICE, "");
+ return 0;
+ }
+
+ id = argv[0];
+ thresh = argv[1];
+
+ if (strncmp(thresh, "upper", 5) == 0) {
+ if (argc < 5) {
+ lprintf(LOG_ERR,
+ "usage: sensor thresh <id> upper <unc> <ucr> <unr>");
+ return -1;
+ }
+ allUpper = 1;
+ if (str2double(argv[2], &setting1) != 0) {
+ lprintf(LOG_ERR, "Given unc '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ if (str2double(argv[3], &setting2) != 0) {
+ lprintf(LOG_ERR, "Given ucr '%s' is invalid.",
+ argv[3]);
+ return (-1);
+ }
+ if (str2double(argv[4], &setting3) != 0) {
+ lprintf(LOG_ERR, "Given unr '%s' is invalid.",
+ argv[4]);
+ return (-1);
+ }
+ } else if (strncmp(thresh, "lower", 5) == 0) {
+ if (argc < 5) {
+ lprintf(LOG_ERR,
+ "usage: sensor thresh <id> lower <unc> <ucr> <unr>");
+ return -1;
+ }
+ allLower = 1;
+ if (str2double(argv[2], &setting1) != 0) {
+ lprintf(LOG_ERR, "Given lnc '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ if (str2double(argv[3], &setting2) != 0) {
+ lprintf(LOG_ERR, "Given lcr '%s' is invalid.",
+ argv[3]);
+ return (-1);
+ }
+ if (str2double(argv[4], &setting3) != 0) {
+ lprintf(LOG_ERR, "Given lnr '%s' is invalid.",
+ argv[4]);
+ return (-1);
+ }
+ } else {
+ if (strncmp(thresh, "unr", 3) == 0)
+ settingMask = UPPER_NON_RECOV_SPECIFIED;
+ else if (strncmp(thresh, "ucr", 3) == 0)
+ settingMask = UPPER_CRIT_SPECIFIED;
+ else if (strncmp(thresh, "unc", 3) == 0)
+ settingMask = UPPER_NON_CRIT_SPECIFIED;
+ else if (strncmp(thresh, "lnc", 3) == 0)
+ settingMask = LOWER_NON_CRIT_SPECIFIED;
+ else if (strncmp(thresh, "lcr", 3) == 0)
+ settingMask = LOWER_CRIT_SPECIFIED;
+ else if (strncmp(thresh, "lnr", 3) == 0)
+ settingMask = LOWER_NON_RECOV_SPECIFIED;
+ else {
+ lprintf(LOG_ERR,
+ "Valid threshold '%s' for sensor '%s' not specified!",
+ thresh, id);
+ return -1;
+ }
+ if (str2double(argv[2], &setting1) != 0) {
+ lprintf(LOG_ERR,
+ "Given %s threshold value '%s' is invalid.",
+ thresh, argv[2]);
+ return (-1);
+ }
+ }
+
+ printf("Locating sensor record '%s'...\n", id);
+
+ /* lookup by sensor name */
+ sdr = ipmi_sdr_find_sdr_byid(intf, id);
+ if (sdr == NULL) {
+ lprintf(LOG_ERR, "Sensor data record not found!");
+ return -1;
+ }
+
+ if (sdr->type != SDR_RECORD_TYPE_FULL_SENSOR) {
+ lprintf(LOG_ERR, "Invalid sensor type %02x", sdr->type);
+ return -1;
+ }
+
+ if (!IS_THRESHOLD_SENSOR(sdr->record.common)) {
+ lprintf(LOG_ERR, "Invalid sensor event type %02x", sdr->record.common->event_type);
+ return -1;
+ }
+
+
+ if (allUpper) {
+ settingMask = UPPER_NON_CRIT_SPECIFIED;
+ printf("Setting sensor \"%s\" %s threshold to %.3f\n",
+ sdr->record.full->id_string,
+ val2str(settingMask, threshold_vals), setting1);
+ ret = __ipmi_sensor_set_threshold(intf,
+ sdr->record.common->keys.
+ sensor_num, settingMask,
+ __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+
+ settingMask = UPPER_CRIT_SPECIFIED;
+ printf("Setting sensor \"%s\" %s threshold to %.3f\n",
+ sdr->record.full->id_string,
+ val2str(settingMask, threshold_vals), setting2);
+ ret = __ipmi_sensor_set_threshold(intf,
+ sdr->record.common->keys.
+ sensor_num, settingMask,
+ __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting2),
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+
+ settingMask = UPPER_NON_RECOV_SPECIFIED;
+ printf("Setting sensor \"%s\" %s threshold to %.3f\n",
+ sdr->record.full->id_string,
+ val2str(settingMask, threshold_vals), setting3);
+ ret = __ipmi_sensor_set_threshold(intf,
+ sdr->record.common->keys.
+ sensor_num, settingMask,
+ __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting3),
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+ } else if (allLower) {
+ settingMask = LOWER_NON_RECOV_SPECIFIED;
+ printf("Setting sensor \"%s\" %s threshold to %.3f\n",
+ sdr->record.full->id_string,
+ val2str(settingMask, threshold_vals), setting1);
+ ret = __ipmi_sensor_set_threshold(intf,
+ sdr->record.common->keys.
+ sensor_num, settingMask,
+ __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+
+ settingMask = LOWER_CRIT_SPECIFIED;
+ printf("Setting sensor \"%s\" %s threshold to %.3f\n",
+ sdr->record.full->id_string,
+ val2str(settingMask, threshold_vals), setting2);
+ ret = __ipmi_sensor_set_threshold(intf,
+ sdr->record.common->keys.
+ sensor_num, settingMask,
+ __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting2),
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+
+ settingMask = LOWER_NON_CRIT_SPECIFIED;
+ printf("Setting sensor \"%s\" %s threshold to %.3f\n",
+ sdr->record.full->id_string,
+ val2str(settingMask, threshold_vals), setting3);
+ ret = __ipmi_sensor_set_threshold(intf,
+ sdr->record.common->keys.
+ sensor_num, settingMask,
+ __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting3),
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+ } else {
+
+ /*
+ * Current implementation doesn't check for the valid setting of upper non critical and other thresholds.
+ * In the below logic:
+ * Get all the current reading of the sensor i.e. unc, uc, lc,lnc.
+ * Validate the values given by the user.
+ * If the values are not correct, then popup with the Error message and return.
+ */
+ /*
+ * Get current reading
+ */
+ rsp = ipmi_sdr_get_sensor_reading_ipmb(intf,
+ sdr->record.common->keys.sensor_num,
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,sdr->record.common->keys.channel);
+ rsp = ipmi_sdr_get_sensor_thresholds(intf,
+ sdr->record.common->keys.sensor_num,
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+ if ((rsp == NULL) || (rsp->ccode > 0)) {
+ lprintf(LOG_ERR, "Sensor data record not found!");
+ return -1;
+ }
+ for(i=1;i<=6;i++) {
+ val[i] = sdr_convert_sensor_reading(sdr->record.full, rsp->data[i]);
+ if(val[i] < 0)
+ val[i] = 0;
+ }
+ /* Check for the valid Upper non recovarable Value.*/
+ if( (settingMask & UPPER_NON_RECOV_SPECIFIED) ) {
+
+ if( (rsp->data[0] & UPPER_NON_RECOV_SPECIFIED) &&
+ (( (rsp->data[0] & UPPER_CRIT_SPECIFIED) && ( setting1 <= val[5])) ||
+ ( (rsp->data[0] & UPPER_NON_CRIT_SPECIFIED) && ( setting1 <= val[4]))) )
+ {
+ lprintf(LOG_ERR, INVALID_THRESHOLD);
+ return -1;
+ }
+ } else if( (settingMask & UPPER_CRIT_SPECIFIED) ) { /* Check for the valid Upper critical Value.*/
+ if( (rsp->data[0] & UPPER_CRIT_SPECIFIED) &&
+ (((rsp->data[0] & UPPER_NON_RECOV_SPECIFIED)&& ( setting1 >= val[6])) ||
+ ((rsp->data[0] & UPPER_NON_CRIT_SPECIFIED)&&( setting1 <= val[4]))) )
+ {
+ lprintf(LOG_ERR, INVALID_THRESHOLD);
+ return -1;
+ }
+ } else if( (settingMask & UPPER_NON_CRIT_SPECIFIED) ) { /* Check for the valid Upper non critical Value.*/
+ if( (rsp->data[0] & UPPER_NON_CRIT_SPECIFIED) &&
+ (((rsp->data[0] & UPPER_NON_RECOV_SPECIFIED)&&( setting1 >= val[6])) ||
+ ((rsp->data[0] & UPPER_CRIT_SPECIFIED)&&( setting1 >= val[5])) ||
+ ((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 <= val[1]))) )
+ {
+ lprintf(LOG_ERR, INVALID_THRESHOLD);
+ return -1;
+ }
+ } else if( (settingMask & LOWER_NON_CRIT_SPECIFIED) ) { /* Check for the valid lower non critical Value.*/
+ if( (rsp->data[0] & LOWER_NON_CRIT_SPECIFIED) &&
+ (((rsp->data[0] & LOWER_CRIT_SPECIFIED)&&( setting1 <= val[2])) ||
+ ((rsp->data[0] & LOWER_NON_RECOV_SPECIFIED)&&( setting1 <= val[3]))||
+ ((rsp->data[0] & UPPER_NON_CRIT_SPECIFIED)&&( setting1 >= val[4]))) )
+ {
+ lprintf(LOG_ERR, INVALID_THRESHOLD);
+ return -1;
+ }
+ } else if( (settingMask & LOWER_CRIT_SPECIFIED) ) { /* Check for the valid lower critical Value.*/
+ if( (rsp->data[0] & LOWER_CRIT_SPECIFIED) &&
+ (((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 >= val[1])) ||
+ ((rsp->data[0] & LOWER_NON_RECOV_SPECIFIED)&&( setting1 <= val[3]))) )
+ {
+ lprintf(LOG_ERR, INVALID_THRESHOLD);
+ return -1;
+ }
+ } else if( (settingMask & LOWER_NON_RECOV_SPECIFIED) ) { /* Check for the valid lower non recovarable Value.*/
+ if( (rsp->data[0] & LOWER_NON_RECOV_SPECIFIED) &&
+ (((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 >= val[1])) ||
+ ((rsp->data[0] & LOWER_CRIT_SPECIFIED)&&( setting1 >= val[2]))) )
+ {
+ lprintf(LOG_ERR, INVALID_THRESHOLD);
+ return -1;
+ }
+ } else { /* None of this Then Return with error messages.*/
+ lprintf(LOG_ERR, INVALID_THRESHOLD);
+ return -1;
+ }
+
+
+ printf("Setting sensor \"%s\" %s threshold to %.3f\n",
+ sdr->record.full->id_string,
+ val2str(settingMask, threshold_vals), setting1);
+
+ ret = __ipmi_sensor_set_threshold(intf,
+ sdr->record.common->keys.
+ sensor_num, settingMask,
+ __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
+ sdr->record.common->keys.owner_id,
+ sdr->record.common->keys.lun,
+ sdr->record.common->keys.channel);
+ }
+
+ return ret;
+}
+
+static int
+ipmi_sensor_get_reading(struct ipmi_intf *intf, int argc, char **argv)
+{
+ struct sdr_record_list *sdr;
+ int i, rc=0;
+
+ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "sensor reading <id> ... [id]");
+ lprintf(LOG_NOTICE, " id : name of desired sensor");
+ return -1;
+ }
+
+ for (i = 0; i < argc; i++) {
+ sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
+ if (sdr == NULL) {
+ lprintf(LOG_ERR, "Sensor \"%s\" not found!",
+ argv[i]);
+ rc = -1;
+ continue;
+ }
+
+ switch (sdr->type) {
+ case SDR_RECORD_TYPE_FULL_SENSOR:
+ case SDR_RECORD_TYPE_COMPACT_SENSOR:
+ {
+ struct sensor_reading *sr;
+ struct sdr_record_common_sensor *sensor = sdr->record.common;
+ sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr->type, 3);
+
+ if (sr == NULL) {
+ rc = -1;
+ continue;
+ }
+
+ if (!sr->full)
+ continue;
+
+ if (!sr->s_reading_valid)
+ continue;
+
+ if (!sr->s_has_analog_value) {
+ lprintf(LOG_ERR, "Sensor \"%s\" is a discrete sensor!", argv[i]);
+ continue;
+ }
+ if (csv_output)
+ printf("%s,%s\n", argv[i], sr->s_a_str);
+ else
+ printf("%-16s | %s\n", argv[i], sr->s_a_str);
+
+ break;
+ }
+ default:
+ continue;
+ }
+ }
+
+ return rc;
+}
+
+static int
+ipmi_sensor_get(struct ipmi_intf *intf, int argc, char **argv)
+{
+ int i, v;
+ int rc = 0;
+ struct sdr_record_list *sdr;
+
+ if (argc < 1) {
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ printf_sensor_get_usage();
+ return (-1);
+ } else if (strcmp(argv[0], "help") == 0) {
+ printf_sensor_get_usage();
+ return 0;
+ }
+ printf("Locating sensor record...\n");
+ /* lookup by sensor name */
+ for (i = 0; i < argc; i++) {
+ sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
+ if (sdr == NULL) {
+ lprintf(LOG_ERR, "Sensor data record \"%s\" not found!",
+ argv[i]);
+ rc = -1;
+ continue;
+ }
+ /* need to set verbose level to 1 */
+ v = verbose;
+ verbose = 1;
+ if (ipmi_sdr_print_listentry(intf, sdr) < 0) {
+ rc = (-1);
+ }
+ verbose = v;
+ sdr = NULL;
+ }
+ return rc;
+}
+
+int
+ipmi_sensor_main(struct ipmi_intf *intf, int argc, char **argv)
+{
+ int rc = 0;
+
+ if (argc == 0) {
+ rc = ipmi_sensor_list(intf);
+ } else if (strncmp(argv[0], "help", 4) == 0) {
+ lprintf(LOG_NOTICE, "Sensor Commands: list thresh get reading");
+ } else if (strncmp(argv[0], "list", 4) == 0) {
+ rc = ipmi_sensor_list(intf);
+ } else if (strncmp(argv[0], "thresh", 5) == 0) {
+ rc = ipmi_sensor_set_threshold(intf, argc - 1, &argv[1]);
+ } else if (strncmp(argv[0], "get", 3) == 0) {
+ rc = ipmi_sensor_get(intf, argc - 1, &argv[1]);
+ } else if (strncmp(argv[0], "reading", 7) == 0) {
+ rc = ipmi_sensor_get_reading(intf, argc - 1, &argv[1]);
+ } else {
+ lprintf(LOG_ERR, "Invalid sensor command: %s", argv[0]);
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/* printf_sensor_get_usage - print usage for # ipmitool sensor get NAC;
+ *
+ * @returns: void
+ */
+void
+printf_sensor_get_usage()
+{
+ lprintf(LOG_NOTICE, "sensor get <id> ... [id]");
+ lprintf(LOG_NOTICE, " id : name of desired sensor");
+}
diff --git a/lib/ipmi_session.c b/lib/ipmi_session.c
new file mode 100644
index 0000000..4855bc4
--- /dev/null
+++ b/lib/ipmi_session.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_lanp.h>
+#include <ipmitool/ipmi_session.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/bswap.h>
+
+
+typedef enum {
+ IPMI_SESSION_REQUEST_CURRENT = 0,
+ IPMI_SESSION_REQUEST_ALL,
+ IPMI_SESSION_REQUEST_BY_ID,
+ IPMI_SESSION_REQUEST_BY_HANDLE
+} Ipmi_Session_Request_Type;
+
+
+
+
+/*
+ * print_session_info_csv
+ */
+static void
+print_session_info_csv(const struct get_session_info_rsp * session_info,
+ int data_len)
+{
+ char buffer[18];
+ uint16_t console_port_tmp;
+
+ printf("%d", session_info->session_handle);
+ printf(",%d", session_info->session_slot_count);
+ printf(",%d", session_info->active_session_count);
+
+ if (data_len == 3)
+ {
+ /* There is no session data here*/
+ printf("\n");
+ return;
+ }
+
+ printf(",%d", session_info->user_id);
+ printf(",%s", val2str(session_info->privilege_level, ipmi_privlvl_vals));
+
+ printf(",%s", session_info->auxiliary_data?
+ "IPMIv2/RMCP+" : "IPMIv1.5");
+
+ printf(",0x%02x", session_info->channel_number);
+
+ if (data_len == 18)
+ {
+ /* We have 802.3 LAN data */
+ printf(",%s",
+ inet_ntop(AF_INET,
+ &(session_info->channel_data.lan_data.console_ip),
+ buffer,
+ 16));
+
+ printf(",%02x:%02x:%02x:%02x:%02x:%02x",
+ session_info->channel_data.lan_data.console_mac[0],
+ session_info->channel_data.lan_data.console_mac[1],
+ session_info->channel_data.lan_data.console_mac[2],
+ session_info->channel_data.lan_data.console_mac[3],
+ session_info->channel_data.lan_data.console_mac[4],
+ session_info->channel_data.lan_data.console_mac[5]);
+
+ console_port_tmp = session_info->channel_data.lan_data.console_port;
+ #if WORDS_BIGENDIAN
+ console_port_tmp = BSWAP_16(console_port_tmp);
+ #endif
+ printf(",%d", console_port_tmp);
+ }
+
+
+ else if ((data_len == 12) || (data_len == 14))
+ {
+ /* Channel async serial/modem */
+ printf(",%s",
+ val2str(session_info->channel_data.modem_data.session_channel_activity_type,
+ ipmi_channel_activity_type_vals));
+
+ printf(",%d",
+ session_info->channel_data.modem_data.destination_selector);
+
+ printf(",%s",
+ inet_ntop(AF_INET,
+ &(session_info->channel_data.modem_data.console_ip),
+ buffer,
+ 16));
+
+ if (data_len == 14)
+ {
+ /* Connection is PPP */
+ console_port_tmp = session_info->channel_data.lan_data.console_port;
+ #if WORDS_BIGENDIAN
+ console_port_tmp = BSWAP_16(console_port_tmp);
+ #endif
+ printf(",%d", console_port_tmp);
+ }
+ }
+
+ printf("\n");
+}
+
+
+
+/*
+ * print_session_info_verbose
+ */
+static void
+print_session_info_verbose(const struct get_session_info_rsp * session_info,
+ int data_len)
+{
+ char buffer[18];
+ uint16_t console_port_tmp;
+
+ printf("session handle : %d\n", session_info->session_handle);
+ printf("slot count : %d\n", session_info->session_slot_count);
+ printf("active sessions : %d\n", session_info->active_session_count);
+
+ if (data_len == 3)
+ {
+ /* There is no session data here */
+ printf("\n");
+ return;
+ }
+
+ printf("user id : %d\n", session_info->user_id);
+ printf("privilege level : %s\n",
+ val2str(session_info->privilege_level, ipmi_privlvl_vals));
+
+ printf("session type : %s\n", session_info->auxiliary_data?
+ "IPMIv2/RMCP+" : "IPMIv1.5");
+
+ printf("channel number : 0x%02x\n", session_info->channel_number);
+
+
+ if (data_len == 18)
+ {
+ /* We have 802.3 LAN data */
+ printf("console ip : %s\n",
+ inet_ntop(AF_INET,
+ &(session_info->channel_data.lan_data.console_ip),
+ buffer,
+ 16));
+
+ printf("console mac : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ session_info->channel_data.lan_data.console_mac[0],
+ session_info->channel_data.lan_data.console_mac[1],
+ session_info->channel_data.lan_data.console_mac[2],
+ session_info->channel_data.lan_data.console_mac[3],
+ session_info->channel_data.lan_data.console_mac[4],
+ session_info->channel_data.lan_data.console_mac[5]);
+
+ console_port_tmp = session_info->channel_data.lan_data.console_port;
+ #if WORDS_BIGENDIAN
+ console_port_tmp = BSWAP_16(console_port_tmp);
+ #endif
+ printf("console port : %d\n", console_port_tmp);
+ }
+
+
+ else if ((data_len == 12) || (data_len == 14))
+ {
+ /* Channel async serial/modem */
+ printf("Session/Channel Activity Type : %s\n",
+ val2str(session_info->channel_data.modem_data.session_channel_activity_type,
+ ipmi_channel_activity_type_vals));
+
+ printf("Destination selector : %d\n",
+ session_info->channel_data.modem_data.destination_selector);
+
+ printf("console ip : %s\n",
+ inet_ntop(AF_INET,
+ &(session_info->channel_data.modem_data.console_ip),
+ buffer,
+ 16));
+
+ if (data_len == 14)
+ {
+ /* Connection is PPP */
+ console_port_tmp = session_info->channel_data.lan_data.console_port;
+ #if WORDS_BIGENDIAN
+ console_port_tmp = BSWAP_16(console_port_tmp);
+ #endif
+ printf("console port : %d\n", console_port_tmp);
+ }
+ }
+
+ printf("\n");
+}
+
+
+static void print_session_info(const struct get_session_info_rsp * session_info,
+ int data_len)
+{
+ if (csv_output)
+ print_session_info_csv(session_info, data_len);
+ else
+ print_session_info_verbose(session_info, data_len);
+}
+
+
+/*
+ * ipmi_get_session_info
+ *
+ * returns 0 on success
+ * -1 on error
+ */
+int
+ipmi_get_session_info(struct ipmi_intf * intf,
+ Ipmi_Session_Request_Type session_request_type,
+ uint32_t id_or_handle)
+{
+ int i, retval = 0;
+
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[5]; // max length of the variable length request
+ struct get_session_info_rsp session_info;
+
+ memset(&req, 0, sizeof(req));
+ memset(&session_info, 0, sizeof(session_info));
+ req.msg.netfn = IPMI_NETFN_APP; // 0x06
+ req.msg.cmd = IPMI_GET_SESSION_INFO; // 0x3D
+ req.msg.data = rqdata;
+
+ switch (session_request_type)
+ {
+
+ case IPMI_SESSION_REQUEST_CURRENT:
+ case IPMI_SESSION_REQUEST_BY_ID:
+ case IPMI_SESSION_REQUEST_BY_HANDLE:
+ switch (session_request_type)
+ {
+ case IPMI_SESSION_REQUEST_CURRENT:
+ rqdata[0] = 0x00;
+ req.msg.data_len = 1;
+ break;
+ case IPMI_SESSION_REQUEST_BY_ID:
+ rqdata[0] = 0xFF;
+ rqdata[1] = id_or_handle & 0x000000FF;
+ rqdata[2] = (id_or_handle >> 8) & 0x000000FF;
+ rqdata[3] = (id_or_handle >> 16) & 0x000000FF;
+ rqdata[4] = (id_or_handle >> 24) & 0x000000FF;
+ req.msg.data_len = 5;
+ break;
+ case IPMI_SESSION_REQUEST_BY_HANDLE:
+ rqdata[0] = 0xFE;
+ rqdata[1] = (uint8_t)id_or_handle;
+ req.msg.data_len = 2;
+ break;
+ case IPMI_SESSION_REQUEST_ALL:
+ break;
+ }
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL)
+ {
+ lprintf(LOG_ERR, "Get Session Info command failed");
+ retval = -1;
+ }
+ else if (rsp->ccode > 0)
+ {
+ lprintf(LOG_ERR, "Get Session Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ retval = -1;
+ }
+
+ if (retval < 0)
+ {
+ if ((session_request_type == IPMI_SESSION_REQUEST_CURRENT) &&
+ (strncmp(intf->name, "lan", 3) != 0))
+ lprintf(LOG_ERR, "It is likely that the channel in use "
+ "does not support sessions");
+ }
+ else
+ {
+ memcpy(&session_info, rsp->data, rsp->data_len);
+ print_session_info(&session_info, rsp->data_len);
+ }
+ break;
+
+ case IPMI_SESSION_REQUEST_ALL:
+ req.msg.data_len = 1;
+ i = 1;
+ do
+ {
+ rqdata[0] = i++;
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL)
+ {
+ lprintf(LOG_ERR, "Get Session Info command failed");
+ retval = -1;
+ break;
+ }
+ else if (rsp->ccode > 0 && rsp->ccode != 0xCC && rsp->ccode != 0xCB)
+ {
+ lprintf(LOG_ERR, "Get Session Info command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ retval = -1;
+ break;
+ }
+ else if (rsp->data_len < 3)
+ {
+ retval = -1;
+ break;
+ }
+
+ memcpy(&session_info, rsp->data, rsp->data_len);
+ print_session_info(&session_info, rsp->data_len);
+
+ } while (i <= session_info.session_slot_count);
+ break;
+ }
+
+ return retval;
+}
+
+
+
+static void
+printf_session_usage(void)
+{
+ lprintf(LOG_NOTICE, "Session Commands: info <active | all | id 0xnnnnnnnn | handle 0xnn>");
+}
+
+
+int
+ipmi_session_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int retval = 0;
+
+ if (argc == 0 || strncmp(argv[0], "help", 4) == 0)
+ {
+ printf_session_usage();
+ }
+ else if (strncmp(argv[0], "info", 4) == 0)
+ {
+
+ if ((argc < 2) || strncmp(argv[1], "help", 4) == 0)
+ {
+ printf_session_usage();
+ }
+ else
+ {
+ Ipmi_Session_Request_Type session_request_type = 0;
+ uint32_t id_or_handle = 0;
+
+ if (strncmp(argv[1], "active", 6) == 0)
+ session_request_type = IPMI_SESSION_REQUEST_CURRENT;
+ else if (strncmp(argv[1], "all", 3) == 0)
+ session_request_type = IPMI_SESSION_REQUEST_ALL;
+ else if (strncmp(argv[1], "id", 2) == 0)
+ {
+ if (argc >= 3)
+ {
+ session_request_type = IPMI_SESSION_REQUEST_BY_ID;
+ if (str2uint(argv[2], &id_or_handle) != 0) {
+ lprintf(LOG_ERR, "HEX number expected, but '%s' given.",
+ argv[2]);
+ printf_session_usage();
+ retval = -1;
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Missing id argument");
+ printf_session_usage();
+ retval = -1;
+ }
+ }
+ else if (strncmp(argv[1], "handle", 6) == 0)
+ {
+ if (argc >= 3)
+ {
+ session_request_type = IPMI_SESSION_REQUEST_BY_HANDLE;
+ if (str2uint(argv[2], &id_or_handle) != 0) {
+ lprintf(LOG_ERR, "HEX number expected, but '%s' given.",
+ argv[2]);
+ printf_session_usage();
+ retval = -1;
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Missing handle argument");
+ printf_session_usage();
+ retval = -1;
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Invalid SESSION info parameter: %s", argv[1]);
+ printf_session_usage();
+ retval = -1;
+ }
+
+
+ if (retval == 0)
+ retval = ipmi_get_session_info(intf,
+ session_request_type,
+ id_or_handle);
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Invalid SESSION command: %s", argv[0]);
+ printf_session_usage();
+ retval = -1;
+ }
+
+ return retval;
+}
+
diff --git a/lib/ipmi_sol.c b/lib/ipmi_sol.c
new file mode 100644
index 0000000..a5b962f
--- /dev/null
+++ b/lib/ipmi_sol.c
@@ -0,0 +1,2098 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <time.h>
+#include <signal.h>
+#include <unistd.h>
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#if defined(HAVE_TERMIOS_H)
+# include <termios.h>
+#elif defined (HAVE_SYS_TERMIOS_H)
+# include <sys/termios.h>
+#endif
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_sol.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/bswap.h>
+
+
+#define SOL_PARAMETER_SET_IN_PROGRESS 0x00
+#define SOL_PARAMETER_SOL_ENABLE 0x01
+#define SOL_PARAMETER_SOL_AUTHENTICATION 0x02
+#define SOL_PARAMETER_CHARACTER_INTERVAL 0x03
+#define SOL_PARAMETER_SOL_RETRY 0x04
+#define SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE 0x05
+#define SOL_PARAMETER_SOL_VOLATILE_BIT_RATE 0x06
+#define SOL_PARAMETER_SOL_PAYLOAD_CHANNEL 0x07
+#define SOL_PARAMETER_SOL_PAYLOAD_PORT 0x08
+
+#define MAX_SOL_RETRY 6
+
+const struct valstr sol_parameter_vals[] = {
+ { SOL_PARAMETER_SET_IN_PROGRESS, "Set In Progress (0)" },
+ { SOL_PARAMETER_SOL_ENABLE, "Enable (1)" },
+ { SOL_PARAMETER_SOL_AUTHENTICATION, "Authentication (2)" },
+ { SOL_PARAMETER_CHARACTER_INTERVAL, "Character Interval (3)" },
+ { SOL_PARAMETER_SOL_RETRY, "Retry (4)" },
+ { SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE, "Nonvolatile Bitrate (5)" },
+ { SOL_PARAMETER_SOL_VOLATILE_BIT_RATE, "Volatile Bitrate (6)" },
+ { SOL_PARAMETER_SOL_PAYLOAD_CHANNEL, "Payload Channel (7)" },
+ { SOL_PARAMETER_SOL_PAYLOAD_PORT, "Payload Port (8)" },
+ { 0x00, NULL },
+};
+
+
+static struct timeval _start_keepalive;
+static struct termios _saved_tio;
+static int _in_raw_mode = 0;
+static int _disable_keepalive = 0;
+static int _use_sol_for_keepalive = 0;
+static int _keepalive_retries = 0;
+
+extern int verbose;
+
+/*
+ * ipmi_sol_payload_access
+ */
+int
+ipmi_sol_payload_access(struct ipmi_intf * intf, uint8_t channel,
+ uint8_t userid, int enable)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ int rc = (-1);
+ uint8_t data[6];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS;
+ req.msg.data = data;
+ req.msg.data_len = 6;
+
+ memset(data, 0, 6);
+ /* channel */
+ data[0] = channel & 0xf;
+ /* user id */
+ data[1] = userid & 0x3f;
+ if (!enable) {
+ /* disable */
+ data[1] |= 0x40;
+ }
+ /* payload 1 is SOL */
+ data[2] = 0x02;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d",
+ enable ? "en" : "dis", userid, channel);
+ rc = (-1);
+ } else if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s",
+ enable ? "en" : "dis", userid, channel,
+ val2str(rsp->ccode, completion_code_vals));
+ rc = (-1);
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+int
+ipmi_sol_payload_access_status(struct ipmi_intf * intf,
+ uint8_t channel,
+ uint8_t userid)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ uint8_t data[2];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_GET_USER_PAYLOAD_ACCESS;
+ req.msg.data = data;
+ req.msg.data_len = sizeof(data);
+
+ data[0] = channel & 0xf; /* channel */
+ data[1] = userid & 0x3f; /* user id */
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error. No valid response received.");
+ return -1;
+ }
+
+ switch(rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len != 4) {
+ lprintf(LOG_ERR, "Error parsing SOL payload status for user %d on channel %d",
+ userid, channel);
+ return -1;
+ }
+
+ printf("User %d on channel %d is %sabled\n",
+ userid, channel, (rsp->data[0] & 0x02) ? "en":"dis");
+ return 0;
+
+ default:
+ lprintf(LOG_ERR, "Error getting SOL payload status for user %d on channel %d: %s",
+ userid, channel,
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+}
+
+
+/*
+ * ipmi_get_sol_info
+ */
+int
+ipmi_get_sol_info(
+ struct ipmi_intf * intf,
+ uint8_t channel,
+ struct sol_config_parameters * params)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t data[4];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_GET_SOL_CONFIG_PARAMETERS;
+ req.msg.data_len = 4;
+ req.msg.data = data;
+
+ /*
+ * set in progress
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SET_IN_PROGRESS; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 2) {
+ params->set_in_progress = rsp->data[1];
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
+ val2str(data[1], sol_parameter_vals));
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * SOL enable
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SOL_ENABLE; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 2) {
+ params->enabled = rsp->data[1];
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
+ val2str(data[1], sol_parameter_vals));
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * SOL authentication
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 2) {
+ params->force_encryption = ((rsp->data[1] & 0x80)? 1 : 0);
+ params->force_authentication = ((rsp->data[1] & 0x40)? 1 : 0);
+ params->privilege_level = rsp->data[1] & 0x0F;
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
+ val2str(data[1], sol_parameter_vals));
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * Character accumulate interval and character send interval
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 3) {
+ params->character_accumulate_level = rsp->data[1];
+ params->character_send_threshold = rsp->data[2];
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
+ val2str(data[1], sol_parameter_vals));
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * SOL retry
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SOL_RETRY; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 3) {
+ params->retry_count = rsp->data[1];
+ params->retry_interval = rsp->data[2];
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
+ val2str(data[1], sol_parameter_vals));
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * SOL non-volatile bit rate
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 2) {
+ params->non_volatile_bit_rate = rsp->data[1] & 0x0F;
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
+ val2str(data[1], sol_parameter_vals));
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * SOL volatile bit rate
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 2) {
+ params->volatile_bit_rate = rsp->data[1] & 0x0F;
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
+ val2str(data[1], sol_parameter_vals));
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * SOL payload channel
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SOL_PAYLOAD_CHANNEL; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 2) {
+ params->payload_channel = rsp->data[1];
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x",
+ val2str(data[1], sol_parameter_vals), channel);
+ params->payload_channel = channel;
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ /*
+ * SOL payload port
+ */
+ memset(data, 0, sizeof(data));
+ data[0] = channel; /* channel number */
+ data[1] = SOL_PARAMETER_SOL_PAYLOAD_PORT; /* parameter selector */
+ data[2] = 0x00; /* set selector */
+ data[3] = 0x00; /* block selector */
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 3) {
+ params->payload_port = (rsp->data[1]) | (rsp->data[2] << 8);
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "for SOL parameter '%s'",
+ rsp->data_len,
+ val2str(data[1], sol_parameter_vals));
+ }
+ break;
+ case 0x80:
+ if( intf->session != NULL ) {
+ lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d",
+ val2str(data[1], sol_parameter_vals), intf->session->port);
+ params->payload_port = intf->session->port;
+ } else {
+ lprintf(LOG_ERR,
+ "Info: SOL parameter '%s' not supported - can't determine which "
+ "payload port to use on NULL session",
+ val2str(data[1], sol_parameter_vals));
+ return (-1);
+ }
+ break;
+ default:
+ lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
+ val2str(data[1], sol_parameter_vals),
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * ipmi_print_sol_info
+ */
+static int
+ipmi_print_sol_info(struct ipmi_intf * intf, uint8_t channel)
+{
+ struct sol_config_parameters params = {0};
+ if (ipmi_get_sol_info(intf, channel, &params))
+ return -1;
+
+ if (csv_output)
+ {
+ printf("%s,",
+ val2str(params.set_in_progress & 0x03,
+ ipmi_set_in_progress_vals));
+ printf("%s,", params.enabled?"true": "false");
+ printf("%s,", params.force_encryption?"true":"false");
+ printf("%s,", params.force_encryption?"true":"false");
+ printf("%s,",
+ val2str(params.privilege_level, ipmi_privlvl_vals));
+ printf("%d,", params.character_accumulate_level * 5);
+ printf("%d,", params.character_send_threshold);
+ printf("%d,", params.retry_count);
+ printf("%d,", params.retry_interval * 10);
+
+ printf("%s,",
+ val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
+
+ printf("%s,",
+ val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
+
+ printf("%d,", params.payload_channel);
+ printf("%d\n", params.payload_port);
+ }
+ else
+ {
+ printf("Set in progress : %s\n",
+ val2str(params.set_in_progress & 0x03,
+ ipmi_set_in_progress_vals));
+ printf("Enabled : %s\n",
+ params.enabled?"true": "false");
+ printf("Force Encryption : %s\n",
+ params.force_encryption?"true":"false");
+ printf("Force Authentication : %s\n",
+ params.force_authentication?"true":"false");
+ printf("Privilege Level : %s\n",
+ val2str(params.privilege_level, ipmi_privlvl_vals));
+ printf("Character Accumulate Level (ms) : %d\n",
+ params.character_accumulate_level * 5);
+ printf("Character Send Threshold : %d\n",
+ params.character_send_threshold);
+ printf("Retry Count : %d\n",
+ params.retry_count);
+ printf("Retry Interval (ms) : %d\n",
+ params.retry_interval * 10);
+
+ printf("Volatile Bit Rate (kbps) : %s\n",
+ val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
+
+ printf("Non-Volatile Bit Rate (kbps) : %s\n",
+ val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
+
+ printf("Payload Channel : %d (0x%02x)\n",
+ params.payload_channel, params.payload_channel);
+ printf("Payload Port : %d\n",
+ params.payload_port);
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Small function to validate that user-supplied SOL
+ * configuration parameter values we store in uint8_t
+ * data type falls within valid range. With minval
+ * and maxval parameters we can use the same function
+ * to validate parameters that have different ranges
+ * of values.
+ *
+ * function will return -1 if value is not valid, or
+ * will return 0 if valid.
+ */
+int ipmi_sol_set_param_isvalid_uint8_t( const char *strval,
+ const char *name,
+ int base,
+ uint8_t minval,
+ uint8_t maxval,
+ uint8_t *out_value)
+{
+ if (str2uchar(strval, out_value) != 0 || (*out_value < minval)
+ || (*out_value > maxval)) {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ strval, name);
+ lprintf(LOG_ERR, "Valid values are %d-%d", minval, maxval);
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * ipmi_sol_set_param
+ *
+ * Set the specified Serial Over LAN value to the specified
+ * value
+ *
+ * return 0 on success,
+ * -1 on failure
+ */
+static int
+ipmi_sol_set_param(struct ipmi_intf * intf,
+ uint8_t channel,
+ const char * param,
+ const char * value,
+ uint8_t guarded)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t data[4];
+ int bGuarded = guarded; /* Use set-in-progress indicator? */
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT; /* 0x0c */
+ req.msg.cmd = IPMI_SET_SOL_CONFIG_PARAMETERS; /* 0x21 */
+ req.msg.data = data;
+
+ data[0] = channel;
+
+ /*
+ * set-in-progress
+ */
+ if (! strcmp(param, "set-in-progress"))
+ {
+ bGuarded = 0; /* We _ARE_ the set-in-progress indicator */
+ req.msg.data_len = 3;
+ data[1] = SOL_PARAMETER_SET_IN_PROGRESS;
+
+ if (! strcmp(value, "set-complete"))
+ data[2] = 0x00;
+ else if (! strcmp(value, "set-in-progress"))
+ data[2] = 0x01;
+ else if (! strcmp(value, "commit-write"))
+ data[2] = 0x02;
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ value, param);
+ lprintf(LOG_ERR, "Valid values are set-complete, set-in-progress "
+ "and commit-write");
+ return -1;
+ }
+ }
+
+
+ /*
+ * enabled
+ */
+ else if (! strcmp(param, "enabled"))
+ {
+ req.msg.data_len = 3;
+ data[1] = SOL_PARAMETER_SOL_ENABLE;
+
+ if (! strcmp(value, "true"))
+ data[2] = 0x01;
+ else if (! strcmp(value, "false"))
+ data[2] = 0x00;
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ value, param);
+ lprintf(LOG_ERR, "Valid values are true and false");
+ return -1;
+ }
+ }
+
+
+ /*
+ * force-payload-encryption
+ */
+ else if (! strcmp(param, "force-encryption"))
+ {
+ struct sol_config_parameters params;
+
+ req.msg.data_len = 3;
+ data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
+
+ if (! strcmp(value, "true"))
+ data[2] = 0x80;
+ else if (! strcmp(value, "false"))
+ data[2] = 0x00;
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ value, param);
+ lprintf(LOG_ERR, "Valid values are true and false");
+ return -1;
+ }
+
+
+ /* We need other values to complete the request */
+ if (ipmi_get_sol_info(intf, channel, &params))
+ {
+ lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
+ param);
+ return -1;
+ }
+
+ data[2] |= params.force_authentication? 0x40 : 0x00;
+ data[2] |= params.privilege_level;
+ }
+
+
+ /*
+ * force-payload-authentication
+ */
+ else if (! strcmp(param, "force-authentication"))
+ {
+ struct sol_config_parameters params;
+
+ req.msg.data_len = 3;
+ data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
+
+ if (! strcmp(value, "true"))
+ data[2] = 0x40;
+ else if (! strcmp(value, "false"))
+ data[2] = 0x00;
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ value, param);
+ lprintf(LOG_ERR, "Valid values are true and false");
+ return -1;
+ }
+
+
+ /* We need other values to complete the request */
+ if (ipmi_get_sol_info(intf, channel, &params))
+ {
+ lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
+ param);
+ return -1;
+ }
+
+ data[2] |= params.force_encryption? 0x80 : 0x00;
+ data[2] |= params.privilege_level;
+ }
+
+
+ /*
+ * privilege-level
+ */
+ else if (! strcmp(param, "privilege-level"))
+ {
+ struct sol_config_parameters params;
+
+ req.msg.data_len = 3;
+ data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
+
+ if (! strcmp(value, "user"))
+ data[2] = 0x02;
+ else if (! strcmp(value, "operator"))
+ data[2] = 0x03;
+ else if (! strcmp(value, "admin"))
+ data[2] = 0x04;
+ else if (! strcmp(value, "oem"))
+ data[2] = 0x05;
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+ value, param);
+ lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem");
+ return -1;
+ }
+
+
+ /* We need other values to complete the request */
+ if (ipmi_get_sol_info(intf, channel, &params))
+ {
+ lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
+ param);
+ return -1;
+ }
+
+ data[2] |= params.force_encryption? 0x80 : 0x00;
+ data[2] |= params.force_authentication? 0x40 : 0x00;
+ }
+
+
+ /*
+ * character-accumulate-level
+ */
+ else if (! strcmp(param, "character-accumulate-level"))
+ {
+ struct sol_config_parameters params;
+
+ req.msg.data_len = 4;
+ data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
+
+ /* validate user-supplied input */
+ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 1, 255, &data[2]))
+ return -1;
+
+ /* We need other values to complete the request */
+ if (ipmi_get_sol_info(intf, channel, &params))
+ {
+ lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
+ param);
+ return -1;
+ }
+
+ data[3] = params.character_send_threshold;
+ }
+
+
+ /*
+ * character-send-threshold
+ */
+ else if (! strcmp(param, "character-send-threshold"))
+ {
+ struct sol_config_parameters params;
+
+ req.msg.data_len = 4;
+ data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
+
+ /* validate user-supplied input */
+ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
+ return -1;
+
+ /* We need other values to complete the request */
+ if (ipmi_get_sol_info(intf, channel, &params))
+ {
+ lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
+ param);
+ return -1;
+ }
+
+ data[2] = params.character_accumulate_level;
+ }
+
+
+ /*
+ * retry-count
+ */
+ else if (! strcmp(param, "retry-count"))
+ {
+ struct sol_config_parameters params;
+
+ req.msg.data_len = 4;
+ data[1] = SOL_PARAMETER_SOL_RETRY;
+
+ /* validate user input, 7 is max value */
+ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 7, &data[2]))
+ return -1;
+
+ /* We need other values to complete the request */
+ if (ipmi_get_sol_info(intf, channel, &params))
+ {
+ lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
+ param);
+ return -1;
+ }
+
+ data[3] = params.retry_interval;
+ }
+
+
+ /*
+ * retry-interval
+ */
+ else if (! strcmp(param, "retry-interval"))
+ {
+ struct sol_config_parameters params;
+
+ req.msg.data_len = 4;
+ data[1] = SOL_PARAMETER_SOL_RETRY;
+
+ /* validate user-supplied input */
+ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
+ return -1;
+
+ /* We need other values to complete the request */
+ if (ipmi_get_sol_info(intf, channel, &params))
+ {
+ lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
+ param);
+ return -1;
+ }
+
+ data[2] = params.retry_count;
+ }
+
+
+ /*
+ * non-volatile-bit-rate
+ */
+ else if (! strcmp(param, "non-volatile-bit-rate"))
+ {
+ req.msg.data_len = 3;
+ data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE;
+
+ if (!strcmp(value, "serial"))
+ {
+ data[2] = 0x00;
+ }
+ else if (!strcmp(value, "9.6"))
+ {
+ data[2] = 0x06;
+ }
+ else if (!strcmp(value, "19.2"))
+ {
+ data[2] = 0x07;
+ }
+ else if (!strcmp(value, "38.4"))
+ {
+ data[2] = 0x08;
+ }
+ else if (!strcmp(value, "57.6"))
+ {
+ data[2] = 0x09;
+ }
+ else if (!strcmp(value, "115.2"))
+ {
+ data[2] = 0x0A;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
+ value,
+ param);
+ lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
+ return -1;
+ }
+ }
+
+
+ /*
+ * volatile-bit-rate
+ */
+ else if (! strcmp(param, "volatile-bit-rate"))
+ {
+ req.msg.data_len = 3;
+ data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE;
+
+ if (!strcmp(value, "serial"))
+ {
+ data[2] = 0x00;
+ }
+ else if (!strcmp(value, "9.6"))
+ {
+ data[2] = 0x06;
+ }
+ else if (!strcmp(value, "19.2"))
+ {
+ data[2] = 0x07;
+ }
+ else if (!strcmp(value, "38.4"))
+ {
+ data[2] = 0x08;
+ }
+ else if (!strcmp(value, "57.6"))
+ {
+ data[2] = 0x09;
+ }
+ else if (!strcmp(value, "115.2"))
+ {
+ data[2] = 0x0A;
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
+ value,
+ param);
+ lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
+ return -1;
+ }
+ }
+ else
+ {
+ lprintf(LOG_ERR, "Error: invalid SOL parameter %s", param);
+ return -1;
+ }
+
+
+ /*
+ * Execute the request
+ */
+ if (bGuarded &&
+ (ipmi_sol_set_param(intf,
+ channel,
+ "set-in-progress",
+ "set-in-progress",
+ bGuarded)))
+ {
+ lprintf(LOG_ERR, "Error: set of parameter \"%s\" failed", param);
+ return -1;
+ }
+
+
+ /* The command proper */
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Error setting SOL parameter '%s'", param);
+ return -1;
+ }
+
+ if (!(!strncmp(param, "set-in-progress", 15) && !strncmp(value, "commit-write", 12)) &&
+ rsp->ccode > 0) {
+ switch (rsp->ccode) {
+ case 0x80:
+ lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
+ "Parameter not supported", param);
+ break;
+ case 0x81:
+ lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
+ "Attempt to set set-in-progress when not in set-complete state",
+ param);
+ break;
+ case 0x82:
+ lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
+ "Attempt to write read-only parameter", param);
+ break;
+ case 0x83:
+ lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
+ "Attempt to read write-only parameter", param);
+ break;
+ default:
+ lprintf(LOG_ERR, "Error setting SOL parameter '%s' to '%s': %s",
+ param, value, val2str(rsp->ccode, completion_code_vals));
+ break;
+ }
+
+ if (bGuarded &&
+ (ipmi_sol_set_param(intf,
+ channel,
+ "set-in-progress",
+ "set-complete",
+ bGuarded)))
+ {
+ lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
+ "to \"set-complete\"");
+ }
+
+ return -1;
+ }
+
+
+ /*
+ * The commit write could very well fail, but that's ok.
+ * It may not be implemented.
+ */
+ if (bGuarded)
+ ipmi_sol_set_param(intf,
+ channel,
+ "set-in-progress",
+ "commit-write",
+ bGuarded);
+
+
+ if (bGuarded &&
+ ipmi_sol_set_param(intf,
+ channel,
+ "set-in-progress",
+ "set-complete",
+ bGuarded))
+ {
+ lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
+ "to \"set-complete\"");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+void
+leave_raw_mode(void)
+{
+ if (!_in_raw_mode)
+ return;
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 0;
+}
+
+
+
+void
+enter_raw_mode(void)
+{
+ struct termios tio;
+ if (tcgetattr(fileno(stdin), &tio) == -1) {
+ perror("tcgetattr");
+ return;
+ }
+ _saved_tio = tio;
+ tio.c_iflag |= IGNPAR;
+ tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
+ tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+ // #ifdef IEXTEN
+ tio.c_lflag &= ~IEXTEN;
+ // #endif
+ tio.c_oflag &= ~OPOST;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 1;
+}
+
+
+static void
+sendBreak(struct ipmi_intf * intf)
+{
+ struct ipmi_v2_payload v2_payload;
+
+ memset(&v2_payload, 0, sizeof(v2_payload));
+
+ v2_payload.payload.sol_packet.character_count = 0;
+ v2_payload.payload.sol_packet.generate_break = 1;
+
+ intf->send_sol(intf, &v2_payload);
+}
+
+
+
+/*
+ * suspendSelf
+ *
+ * Put ourself in the background
+ *
+ * param bRestoreTty specifies whether we will put our self back
+ * in raw mode when we resume
+ */
+static void
+suspendSelf(int bRestoreTty)
+{
+ leave_raw_mode();
+ kill(getpid(), SIGTSTP);
+
+ if (bRestoreTty)
+ enter_raw_mode();
+}
+
+
+
+/*
+ * printSolEscapeSequences
+ *
+ * Send some useful documentation to the user
+ */
+static void
+printSolEscapeSequences(struct ipmi_intf * intf)
+{
+ printf(
+ "%c?\n\
+ Supported escape sequences:\n\
+ %c. - terminate connection\n\
+ %c^Z - suspend ipmitool\n\
+ %c^X - suspend ipmitool, but don't restore tty on restart\n\
+ %cB - send break\n\
+ %c? - this message\n\
+ %c%c - send the escape character by typing it twice\n\
+ (Note that escapes are only recognized immediately after newline.)\n",
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char);
+}
+
+
+
+/*
+ * output
+ *
+ * Send the specified data to stdout
+ */
+static void
+output(struct ipmi_rs * rsp)
+{
+ /* Add checks to make sure it is actually SOL data, in general I see
+ * outside code mostly trying to guard against this happening, but
+ * some places fail to do so, so I do so here to make sure nothing gets
+ * through. If non-sol data comes through here, there is probably
+ * a packet that won't get processed somewhere else, but the alternative
+ * of outputting corrupt data is worse. Generally I see the get device
+ * id response make it here somehow. I assume it is a heartbeat and the
+ * other code will retry if it cares about the response and misses it.
+ */
+ if (rsp &&
+ (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
+ (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
+ {
+ int i;
+
+ for (i = 0; i < rsp->data_len; ++i)
+ putc(rsp->data[i], stdout);
+
+ fflush(stdout);
+ }
+}
+
+
+
+/*
+ * ipmi_sol_deactivate
+ */
+static int
+ipmi_sol_deactivate(struct ipmi_intf * intf, int instance)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t data[6];
+
+ if ((instance <= 0) || (instance > 15)) {
+ lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD;
+ req.msg.data_len = 6;
+ req.msg.data = data;
+
+ bzero(data, sizeof(data));
+ data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
+ data[1] = instance; /* payload instance. */
+
+ /* Lots of important data */
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+ data[5] = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (NULL != rsp) {
+ switch (rsp->ccode) {
+ case 0x00:
+ return 0;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL payload already de-activated");
+ break;
+ case 0x81:
+ lprintf(LOG_ERR, "Info: SOL payload type disabled");
+ break;
+ default:
+ lprintf(LOG_ERR, "Error de-activating SOL payload: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ break;
+ }
+ } else {
+ lprintf(LOG_ERR, "Error: No response de-activating SOL payload");
+ }
+
+ return -1;
+}
+
+
+
+/*
+ * processSolUserInput
+ *
+ * Act on user input into the SOL session. The only reason this
+ * is complicated is that we have to process escape sequences.
+ *
+ * return 0 on success
+ * 1 if we should exit
+ * < 0 on error (BMC probably closed the session)
+ */
+static int
+processSolUserInput(
+ struct ipmi_intf * intf,
+ uint8_t * input,
+ uint16_t buffer_length)
+{
+ static int escape_pending = 0;
+ static int last_was_cr = 1;
+ struct ipmi_v2_payload v2_payload;
+ int length = 0;
+ int retval = 0;
+ char ch;
+ int i;
+
+ memset(&v2_payload, 0, sizeof(v2_payload));
+
+ /*
+ * Our first order of business is to check the input for escape
+ * sequences to act on.
+ */
+ for (i = 0; i < buffer_length; ++i)
+ {
+ ch = input[i];
+
+ if (escape_pending){
+ escape_pending = 0;
+
+ /*
+ * Process a possible escape sequence.
+ */
+ switch (ch) {
+ case '.':
+ printf("%c. [terminated ipmitool]\n",
+ intf->session->sol_escape_char);
+ retval = 1;
+ break;
+
+ case 'Z' - 64:
+ printf("%c^Z [suspend ipmitool]\n",
+ intf->session->sol_escape_char);
+ suspendSelf(1); /* Restore tty back to raw */
+ continue;
+
+ case 'X' - 64:
+ printf("%c^Z [suspend ipmitool]\n",
+ intf->session->sol_escape_char);
+ suspendSelf(0); /* Don't restore to raw mode */
+ continue;
+
+ case 'B':
+ printf("%cB [send break]\n",
+ intf->session->sol_escape_char);
+ sendBreak(intf);
+ continue;
+
+ case '?':
+ printSolEscapeSequences(intf);
+ continue;
+
+ default:
+ if (ch != intf->session->sol_escape_char)
+ v2_payload.payload.sol_packet.data[length++] =
+ intf->session->sol_escape_char;
+ v2_payload.payload.sol_packet.data[length++] = ch;
+ }
+ }
+
+ else
+ {
+ if (last_was_cr && (ch == intf->session->sol_escape_char)) {
+ escape_pending = 1;
+ continue;
+ }
+
+ v2_payload.payload.sol_packet.data[length++] = ch;
+ }
+
+
+ /*
+ * Normal character. Record whether it was a newline.
+ */
+ last_was_cr = (ch == '\r' || ch == '\n');
+ }
+
+
+ /*
+ * If there is anything left to process we dispatch it to the BMC,
+ * send intf->session->sol_data.max_outbound_payload_size bytes
+ * at a time.
+ */
+ if (length)
+ {
+ struct ipmi_rs * rsp = NULL;
+ int try = 0;
+
+ while (try < intf->session->retry) {
+
+ v2_payload.payload.sol_packet.character_count = length;
+
+ rsp = intf->send_sol(intf, &v2_payload);
+
+ if (rsp)
+ {
+ break;
+ }
+
+ usleep(5000);
+ try++;
+ }
+
+ if (! rsp)
+ {
+ lprintf(LOG_ERR, "Error sending SOL data: FAIL");
+ retval = -1;
+ }
+
+ /* If the sequence number is set we know we have new data */
+ if (retval == 0)
+ if ((rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
+ (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
+ (rsp->payload.sol_packet.packet_sequence_number))
+ output(rsp);
+ }
+
+ return retval;
+}
+
+static int
+ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf)
+{
+ struct ipmi_v2_payload v2_payload;
+ struct ipmi_rs * rsp = NULL;
+ struct timeval end;
+
+ int ret = 0;
+
+ if (_disable_keepalive)
+ return 0;
+
+ gettimeofday(&end, 0);
+
+ if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
+ memset(&v2_payload, 0, sizeof(v2_payload));
+
+ v2_payload.payload.sol_packet.character_count = 0;
+
+ rsp = intf->send_sol(intf, &v2_payload);
+
+ gettimeofday(&_start_keepalive, 0);
+ }
+ return ret;
+}
+
+static int
+ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf)
+{
+ struct timeval end;
+ static int ret = 0;
+
+ if (_disable_keepalive)
+ return 0;
+
+ gettimeofday(&end, 0);
+
+ if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
+ ret = intf->keepalive(intf);
+ if ( (ret!=0) && (_keepalive_retries < SOL_KEEPALIVE_RETRIES) ) {
+ ret = 0;
+ _keepalive_retries++;
+ }
+ else if ((ret==0) && (_keepalive_retries > 0))
+ _keepalive_retries = 0;
+ gettimeofday(&_start_keepalive, 0);
+ }
+ return ret;
+}
+
+
+
+/*
+ * ipmi_sol_red_pill
+ */
+static int
+ipmi_sol_red_pill(struct ipmi_intf * intf, int instance)
+{
+ char * buffer;
+ int numRead;
+ int bShouldExit = 0;
+ int bBmcClosedSession = 0;
+ fd_set read_fds;
+ struct timeval tv;
+ int retval;
+ int buffer_size = intf->session->sol_data.max_inbound_payload_size;
+ int keepAliveRet = 0;
+ int retrySol = 0;
+
+ /* Subtract SOL header from max_inbound_payload_size */
+ if (buffer_size > 4)
+ buffer_size -= 4;
+
+ buffer = (char*)malloc(buffer_size);
+ if (buffer == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+
+ /* Initialize keepalive start time */
+ gettimeofday(&_start_keepalive, 0);
+
+ enter_raw_mode();
+
+ while (! bShouldExit)
+ {
+ FD_ZERO(&read_fds);
+ FD_SET(0, &read_fds);
+ FD_SET(intf->fd, &read_fds);
+
+ if (!ipmi_oem_active(intf,"i82571spt"))
+ {
+ /* Send periodic keepalive packet */
+ if(_use_sol_for_keepalive == 0)
+ {
+ keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf);
+ }
+ else
+ {
+ keepAliveRet = ipmi_sol_keepalive_using_sol(intf);
+ }
+
+ if (keepAliveRet != 0)
+ {
+ /*
+ * Retrying the keep Alive before declaring a communication
+ * lost state with the IPMC. Helpful when the payload is
+ * reset and brings down the connection temporarily. Otherwise,
+ * if we send getDevice Id to check the status of IPMC during
+ * this down time when the connection is restarting, SOL will
+ * exit even though the IPMC is available and the session is open.
+ */
+ if (retrySol == MAX_SOL_RETRY)
+ {
+ /* no response to Get Device ID keepalive message */
+ bShouldExit = 1;
+ continue;
+ }
+ else
+ {
+ retrySol++;
+ }
+ }
+ else
+ {
+ /* if the keep Alive is successful reset retries to zero */
+ retrySol = 0;
+ }
+ } /* !oem="i82571spt" */
+ /* Wait up to half a second */
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000;
+
+ retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv);
+
+ if (retval)
+ {
+ if (retval == -1)
+ {
+ /* ERROR */
+ perror("select");
+ return -1;
+ }
+
+
+ /*
+ * Process input from the user
+ */
+ if (FD_ISSET(0, &read_fds))
+ {
+ memset(buffer, 0, buffer_size);
+ numRead = read(fileno(stdin),
+ buffer,
+ buffer_size);
+
+ if (numRead > 0)
+ {
+ int rc = processSolUserInput(intf, (uint8_t *)buffer, numRead);
+
+ if (rc)
+ {
+ if (rc < 0)
+ bShouldExit = bBmcClosedSession = 1;
+ else
+ bShouldExit = 1;
+ }
+ }
+ else
+ {
+ bShouldExit = 1;
+ }
+ }
+
+
+ /*
+ * Process input from the BMC
+ */
+ else if (FD_ISSET(intf->fd, &read_fds))
+ {
+ struct ipmi_rs * rs =intf->recv_sol(intf);
+ if (! rs)
+ {
+ bShouldExit = bBmcClosedSession = 1;
+ }
+ else
+ {
+ output(rs);
+ }
+ }
+
+
+ /*
+ * ERROR in select
+ */
+ else
+ {
+ lprintf(LOG_ERR, "Error: Select returned with nothing to read");
+ bShouldExit = 1;
+ }
+ }
+ }
+
+ leave_raw_mode();
+
+ if (keepAliveRet != 0)
+ {
+ lprintf(LOG_ERR, "Error: No response to keepalive - Terminating session");
+ /* attempt to clean up anyway */
+ ipmi_sol_deactivate(intf, instance);
+ exit(1);
+ }
+
+ if (bBmcClosedSession)
+ {
+ lprintf(LOG_ERR, "SOL session closed by BMC");
+ exit(1);
+ }
+ else
+ ipmi_sol_deactivate(intf, instance);
+
+ return 0;
+}
+
+
+
+
+/*
+ * ipmi_sol_activate
+ */
+static int
+ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval,
+ int instance)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ struct activate_payload_rsp ap_rsp;
+ uint8_t data[6];
+ uint8_t bSolEncryption = 1;
+ uint8_t bSolAuthentication = 1;
+
+ /*
+ * This command is only available over RMCP+ (the lanplus
+ * interface).
+ */
+ if (strncmp(intf->name, "lanplus", 7) != 0)
+ {
+ lprintf(LOG_ERR, "Error: This command is only available over the "
+ "lanplus interface");
+ return -1;
+ }
+
+ if ((instance <= 0) || (instance > 15)) {
+ lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
+ return -1;
+ }
+
+
+ /*
+ * Setup a callback so that the lanplus processing knows what
+ * to do with packets that come unexpectedly (while waiting for
+ * an ACK, perhaps.
+ */
+ intf->session->sol_data.sol_input_handler = output;
+
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = IPMI_ACTIVATE_PAYLOAD;
+ req.msg.data_len = 6;
+ req.msg.data = data;
+
+ data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
+ data[1] = instance; /* payload instance */
+
+ /* Lots of important data. Most is default */
+ data[2] = bSolEncryption? 0x80 : 0;
+ data[2] |= bSolAuthentication? 0x40 : 0;
+ data[2] |= IPMI_SOL_SERIAL_ALERT_MASK_DEFERRED;
+
+ if (ipmi_oem_active(intf, "intelplus")) {
+ data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE;
+ } else if (ipmi_oem_active(intf, "i82571spt")) {
+ /*
+ * A quote from Intel: "Engineering believes the problem
+ * lies within the Auxiliary data being sent with the
+ * 'Activate Payload' command from IPMITool. IPMITool
+ * sends a C6h which sets some bits having to do with
+ * encryption and some behavior dealing with CTS DCD/DSR.
+ * I recommend that the customer modify this request
+ * to send 08h instead. This is what our internal utility
+ * sends and it works without issue. I will work with
+ * engineering to ensure the settings that IPMITool uses
+ * (C6h) are supported in the future.
+ */
+ data[2] = 0x08;
+ } else {
+ data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE;
+ }
+
+ data[3] = 0x00; /* reserved */
+ data[4] = 0x00; /* reserved */
+ data[5] = 0x00; /* reserved */
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (NULL != rsp) {
+ switch (rsp->ccode) {
+ case 0x00:
+ if (rsp->data_len == 12) {
+ break;
+ } else {
+ lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+ "in payload activation response",
+ rsp->data_len);
+ return -1;
+ }
+ break;
+ case 0x80:
+ lprintf(LOG_ERR, "Info: SOL payload already active on another session");
+ return -1;
+ case 0x81:
+ lprintf(LOG_ERR, "Info: SOL payload disabled");
+ return -1;
+ case 0x82:
+ lprintf(LOG_ERR, "Info: SOL payload activation limit reached");
+ return -1;
+ case 0x83:
+ lprintf(LOG_ERR, "Info: cannot activate SOL payload with encryption");
+ return -1;
+ case 0x84:
+ lprintf(LOG_ERR, "Info: cannot activate SOL payload without encryption");
+ return -1;
+ default:
+ lprintf(LOG_ERR, "Error activating SOL payload: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ } else {
+ lprintf(LOG_ERR, "Error: No response activating SOL payload");
+ return -1;
+ }
+
+
+ memcpy(&ap_rsp, rsp->data, sizeof(struct activate_payload_rsp));
+
+ intf->session->sol_data.max_inbound_payload_size =
+ (ap_rsp.inbound_payload_size[1] << 8) |
+ ap_rsp.inbound_payload_size[0];
+
+ intf->session->sol_data.max_outbound_payload_size =
+ (ap_rsp.outbound_payload_size[1] << 8) |
+ ap_rsp.outbound_payload_size[0];
+
+ intf->session->sol_data.port =
+ (ap_rsp.payload_udp_port[1] << 8) |
+ ap_rsp.payload_udp_port[0];
+
+ intf->session->timeout = 1;
+
+
+ /* NOTE: the spec does allow for SOL traffic to be sent on
+ * a different port. we do not yet support that feature. */
+ if (intf->session->sol_data.port != intf->session->port)
+ {
+ /* try byteswapping port in case BMC sent it incorrectly */
+ uint16_t portswap = BSWAP_16(intf->session->sol_data.port);
+
+ if (portswap == intf->session->port) {
+ intf->session->sol_data.port = portswap;
+ }
+ else {
+ lprintf(LOG_ERR, "Error: BMC requests SOL session on different port");
+ return -1;
+ }
+ }
+
+ printf("[SOL Session operational. Use %c? for help]\n",
+ intf->session->sol_escape_char);
+
+ if(looptest == 1)
+ {
+ ipmi_sol_deactivate(intf, instance);
+ usleep(interval*1000);
+ return 0;
+ }
+
+ /*
+ * At this point we are good to go with our SOL session. We
+ * need to listen to
+ * 1) STDIN for user input
+ * 2) The FD for incoming SOL packets
+ */
+ if (ipmi_sol_red_pill(intf, instance))
+ {
+ lprintf(LOG_ERR, "Error in SOL session");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * print_sol_usage
+ */
+static void
+print_sol_usage(void)
+{
+ lprintf(LOG_NOTICE, "SOL Commands: info [<channel number>]");
+ lprintf(LOG_NOTICE, " set <parameter> <value> [channel]");
+ lprintf(LOG_NOTICE, " payload <enable|disable|status> [channel] [userid]");
+ lprintf(LOG_NOTICE, " activate [<usesolkeepalive|nokeepalive>] [instance=<number>]");
+ lprintf(LOG_NOTICE, " deactivate [instance=<number>]");
+ lprintf(LOG_NOTICE, " looptest [<loop times> [<loop interval(in ms)> [<instance>]]]");
+}
+
+
+
+/*
+ * print_sol_set_usage
+ */
+static void
+print_sol_set_usage(void)
+{
+ lprintf(LOG_NOTICE, "\nSOL set parameters and values: \n");
+ lprintf(LOG_NOTICE, " set-in-progress set-complete | "
+ "set-in-progress | commit-write");
+ lprintf(LOG_NOTICE, " enabled true | false");
+ lprintf(LOG_NOTICE, " force-encryption true | false");
+ lprintf(LOG_NOTICE, " force-authentication true | false");
+ lprintf(LOG_NOTICE, " privilege-level user | operator | admin | oem");
+ lprintf(LOG_NOTICE, " character-accumulate-level <in 5 ms increments>");
+ lprintf(LOG_NOTICE, " character-send-threshold N");
+ lprintf(LOG_NOTICE, " retry-count N");
+ lprintf(LOG_NOTICE, " retry-interval <in 10 ms increments>");
+ lprintf(LOG_NOTICE, " non-volatile-bit-rate "
+ "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
+ lprintf(LOG_NOTICE, " volatile-bit-rate "
+ "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
+ lprintf(LOG_NOTICE, "");
+}
+
+
+
+/* ipmi_sol_main */
+int
+ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int retval = 0;
+ if (!argc || !strncmp(argv[0], "help", 4)) {
+ /* Help */
+ print_sol_usage();
+ } else if (!strncmp(argv[0], "info", 4)) {
+ /* Info */
+ uint8_t channel;
+ if (argc == 1) {
+ /* Ask about the current channel */
+ channel = 0x0E;
+ } else if (argc == 2) {
+ if (is_ipmi_channel_num(argv[1], &channel) != 0) {
+ return (-1);
+ }
+ } else {
+ print_sol_usage();
+ return -1;
+ }
+ retval = ipmi_print_sol_info(intf, channel);
+ } else if (!strncmp(argv[0], "payload", 7)) {
+ /* Payload enable or disable */
+ uint8_t channel = 0xe;
+ uint8_t userid = 1;
+ int enable = -1;
+ if (argc == 1 || argc > 4) {
+ print_sol_usage();
+ return -1;
+ }
+ if (argc == 1 || argc > 4) {
+ print_sol_usage();
+ return -1;
+ }
+ if (argc >= 3) {
+ if (is_ipmi_channel_num(argv[2], &channel) != 0) {
+ return (-1);
+ }
+ }
+ if (argc == 4) {
+ if (is_ipmi_user_id(argv[3], &userid) != 0) {
+ return (-1);
+ }
+ }
+ if (!strncmp(argv[1], "enable", 6)) {
+ enable = 1;
+ } else if (!strncmp(argv[1], "disable", 7)) {
+ enable = 0;
+ } else if (!strncmp(argv[1], "status", 6)) {
+ return ipmi_sol_payload_access_status(intf, channel, userid);
+ } else {
+ print_sol_usage();
+ return -1;
+ }
+ retval = ipmi_sol_payload_access(intf, channel, userid, enable);
+ } else if (!strncmp(argv[0], "set", 3)) {
+ /* Set a parameter value */
+ uint8_t channel = 0xe;
+ uint8_t guard = 1;
+ if (argc == 3) {
+ channel = 0xe;
+ } else if (argc == 4) {
+ if (!strncmp(argv[3], "noguard", 7)) {
+ guard = 0;
+ } else {
+ if (is_ipmi_channel_num(argv[3], &channel) != 0) {
+ return (-1);
+ }
+ }
+ } else if (argc == 5) {
+ if (is_ipmi_channel_num(argv[3], &channel) != 0) {
+ return (-1);
+ }
+ if (!strncmp(argv[4], "noguard", 7)) {
+ guard = 0;
+ }
+ } else {
+ print_sol_set_usage();
+ return -1;
+ }
+ retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2], guard);
+ } else if (!strncmp(argv[0], "activate", 8)) {
+ /* Activate */
+ int i;
+ uint8_t instance = 1;
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "usesolkeepalive", 15)) {
+ _use_sol_for_keepalive = 1;
+ } else if (!strncmp(argv[i], "nokeepalive", 11)) {
+ _disable_keepalive = 1;
+ } else if (!strncmp(argv[i], "instance=", 9)) {
+ if (str2uchar(argv[i] + 9, &instance) != 0) {
+ lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9);
+ print_sol_usage();
+ return -1;
+ }
+ } else {
+ print_sol_usage();
+ return -1;
+ }
+ }
+ retval = ipmi_sol_activate(intf, 0, 0, instance);
+ } else if (!strncmp(argv[0], "deactivate", 10)) {
+ /* Dectivate */
+ int i;
+ uint8_t instance = 1;
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "instance=", 9)) {
+ if (str2uchar(argv[i] + 9, &instance) != 0) {
+ lprintf(LOG_ERR,
+ "Given instance '%s' is invalid.",
+ argv[i] + 9);
+ print_sol_usage();
+ return -1;
+ }
+ } else {
+ print_sol_usage();
+ return -1;
+ }
+ }
+ retval = ipmi_sol_deactivate(intf, instance);
+ } else if (!strncmp(argv[0], "looptest", 8)) {
+ /* SOL loop test: Activate and then Dectivate */
+ int cnt = 200;
+ int interval = 100; /* Unit is: ms */
+ uint8_t instance = 1;
+ if (argc > 4) {
+ print_sol_usage();
+ return -1;
+ }
+ if (argc != 1) {
+ /* at least 2 */
+ if (str2int(argv[1], &cnt) != 0) {
+ lprintf(LOG_ERR, "Given cnt '%s' is invalid.",
+ argv[1]);
+ return (-1);
+ }
+ if (cnt <= 0) {
+ cnt = 200;
+ }
+ }
+ if (argc >= 3) {
+ if (str2int(argv[2], &interval) != 0) {
+ lprintf(LOG_ERR, "Given interval '%s' is invalid.",
+ argv[2]);
+ return (-1);
+ }
+ if (interval < 0) {
+ interval = 0;
+ }
+ }
+ if (argc >= 4) {
+ if (str2uchar(argv[3], &instance) != 0) {
+ lprintf(LOG_ERR, "Given instance '%s' is invalid.",
+ argv[3]);
+ print_sol_usage();
+ return -1;
+ }
+ }
+
+ while (cnt > 0) {
+ printf("remain loop test counter: %d\n", cnt);
+ retval = ipmi_sol_activate(intf, 1, interval, instance);
+ if (retval) {
+ printf("SOL looptest failed: %d\n",
+ retval);
+ break;
+ }
+ cnt -= 1;
+ }
+ } else {
+ print_sol_usage();
+ retval = -1;
+ }
+ return retval;
+}
diff --git a/lib/ipmi_strings.c b/lib/ipmi_strings.c
new file mode 100644
index 0000000..277b82f
--- /dev/null
+++ b/lib/ipmi_strings.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stddef.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/ipmi_sensor.h>
+#include <ipmitool/ipmi_sel.h> /* for IPMI_OEM */
+
+const struct valstr ipmi_oem_info[] = {
+
+ { IPMI_OEM_UNKNOWN, "Unknown" },
+ { IPMI_OEM_HP, "Hewlett-Packard" },
+ { IPMI_OEM_SUN, "Sun Microsystems" },
+ { IPMI_OEM_INTEL, "Intel Corporation" },
+ { IPMI_OEM_LMC, "LMC" },
+ { IPMI_OEM_RADISYS, "RadiSys Corporation" },
+ { IPMI_OEM_TYAN, "Tyan Computer Corporation" },
+ { IPMI_OEM_NEWISYS, "Newisys" },
+ { IPMI_OEM_SUPERMICRO, "Supermicro" },
+ { IPMI_OEM_GOOGLE, "Google" },
+ { IPMI_OEM_KONTRON, "Kontron" },
+ { IPMI_OEM_NOKIA, "Nokia" },
+ { IPMI_OEM_PICMG, "PICMG" },
+ { IPMI_OEM_PEPPERCON, "Peppercon AG" },
+ { IPMI_OEM_DELL, "DELL Inc" },
+ { IPMI_OEM_NEC, "NEC" },
+ { IPMI_OEM_MAGNUM, "Magnum Technologies" },
+ { IPMI_OEM_FUJITSU_SIEMENS, "Fujitsu Siemens" },
+ { IPMI_OEM_TATUNG, "Tatung" },
+ { IPMI_OEM_AMI, "AMI" },
+ { IPMI_OEM_RARITAN, "Raritan" },
+ { IPMI_OEM_AVOCENT, "Avocent" },
+ { IPMI_OEM_OSA, "OSA" },
+ { IPMI_OEM_TOSHIBA, "Toshiba" },
+ { IPMI_OEM_HITACHI_116, "Hitachi" },
+ { IPMI_OEM_HITACHI_399, "Hitachi" },
+ { IPMI_OEM_NOKIA_SIEMENS_NETWORKS, "Nokia Siemens Networks" },
+ { IPMI_OEM_BULL, "Bull Company" },
+ { IPMI_OEM_PPS, "Pigeon Point Systems" },
+ { IPMI_OEM_BROADCOM, "Broadcom Corporation" },
+ { 0xffff , NULL },
+};
+
+const struct oemvalstr ipmi_oem_product_info[] = {
+ /* Keep OEM grouped together */
+ /* Intel stuff, thanks to Tim Bell */
+ { IPMI_OEM_INTEL, 0x000C, "TSRLT2" },
+ { IPMI_OEM_INTEL, 0x001B, "TIGPR2U" },
+ { IPMI_OEM_INTEL, 0x0022, "TIGI2U" },
+ { IPMI_OEM_INTEL, 0x0026, "Bridgeport" },
+ { IPMI_OEM_INTEL, 0x0028, "S5000PAL" },
+ { IPMI_OEM_INTEL, 0x0029, "S5000PSL" },
+ { IPMI_OEM_INTEL, 0x0100, "Tiger4" },
+ { IPMI_OEM_INTEL, 0x0103, "McCarran" },
+ { IPMI_OEM_INTEL, 0x0800, "ZT5504" },
+ { IPMI_OEM_INTEL, 0x0808, "MPCBL0001" },
+ { IPMI_OEM_INTEL, 0x0811, "TIGW1U" },
+ { IPMI_OEM_INTEL, 0x4311, "NSI2U" },
+ /* Kontron */
+ { IPMI_OEM_KONTRON,4000, "AM4000 AdvancedMC" },
+ { IPMI_OEM_KONTRON,4001, "AM4001 AdvancedMC" },
+ { IPMI_OEM_KONTRON,4002, "AM4002 AdvancedMC" },
+ { IPMI_OEM_KONTRON,4010, "AM4010 AdvancedMC" },
+ { IPMI_OEM_KONTRON,5503, "AM4500/4520 AdvancedMC" },
+ { IPMI_OEM_KONTRON,5504, "AM4300 AdvancedMC" },
+ { IPMI_OEM_KONTRON,5507, "AM4301 AdvancedMC" },
+ { IPMI_OEM_KONTRON,5508, "AM4330 AdvancedMC" },
+ { IPMI_OEM_KONTRON,5520, "KTC5520/EATX" },
+ { IPMI_OEM_KONTRON,5703, "RTM8020" },
+ { IPMI_OEM_KONTRON,5704, "RTM8030" },
+ { IPMI_OEM_KONTRON,5705, "RTM8050" },
+ { IPMI_OEM_KONTRON,6000, "CP6000" },
+ { IPMI_OEM_KONTRON,6006, "DT-64" },
+ { IPMI_OEM_KONTRON,6010, "CP6010" },
+ { IPMI_OEM_KONTRON,6011, "CP6011" },
+ { IPMI_OEM_KONTRON,6012, "CP6012" },
+ { IPMI_OEM_KONTRON,6014, "CP6014" },
+ { IPMI_OEM_KONTRON,5002, "AT8001" },
+ { IPMI_OEM_KONTRON,5003, "AT8010" },
+ { IPMI_OEM_KONTRON,5004, "AT8020" },
+ { IPMI_OEM_KONTRON,5006, "AT8030 IPMC" },
+ { IPMI_OEM_KONTRON,2025, "AT8030 MMC" },
+ { IPMI_OEM_KONTRON,5007, "AT8050" },
+ { IPMI_OEM_KONTRON,5301, "AT8400" },
+ { IPMI_OEM_KONTRON,5303, "AT8901" },
+ /* Broadcom */
+ { IPMI_OEM_BROADCOM, 5725, "BCM5725" },
+
+ { 0xffffff , 0xffff , NULL },
+ };
+
+const struct oemvalstr ipmi_oem_sdr_type_vals[] = {
+ /* Keep OEM grouped together */
+ { IPMI_OEM_KONTRON , 0xC0 , "OEM Firmware Info" },
+ { IPMI_OEM_KONTRON , 0xC2 , "OEM Init Agent" },
+ { IPMI_OEM_KONTRON , 0xC3 , "OEM IPMBL Link State" },
+ { IPMI_OEM_KONTRON , 0xC4 , "OEM Board Reset" },
+ { IPMI_OEM_KONTRON , 0xC5 , "OEM FRU Information Agent" },
+ { IPMI_OEM_KONTRON , 0xC6 , "OEM POST Value Sensor" },
+ { IPMI_OEM_KONTRON , 0xC7 , "OEM FWUM Status" },
+ { IPMI_OEM_KONTRON , 0xC8 , "OEM Switch Mngt Software Status" },
+ { IPMI_OEM_KONTRON , 0xC9 , "OEM OEM Diagnostic Status" },
+ { IPMI_OEM_KONTRON , 0xCA , "OEM Component Firmware Upgrade" },
+ { IPMI_OEM_KONTRON , 0xCB , "OEM FRU Over Current" },
+ { IPMI_OEM_KONTRON , 0xCC , "OEM FRU Sensor Error" },
+ { IPMI_OEM_KONTRON , 0xCD , "OEM FRU Power Denied" },
+ { IPMI_OEM_KONTRON , 0xCE , "OEM Reserved" },
+ { IPMI_OEM_KONTRON , 0xCF , "OEM Board Reset" },
+ { IPMI_OEM_KONTRON , 0xD0 , "OEM Clock Resource Control" },
+ { IPMI_OEM_KONTRON , 0xD1 , "OEM Power State" },
+ { IPMI_OEM_KONTRON , 0xD2 , "OEM FRU Mngt Power Failure" },
+ { IPMI_OEM_KONTRON , 0xD3 , "OEM Jumper Status" },
+ { IPMI_OEM_KONTRON , 0xF2 , "OEM RTM Module Hotswap" },
+
+ { IPMI_OEM_PICMG , 0xF0 , "PICMG FRU Hotswap" },
+ { IPMI_OEM_PICMG , 0xF1 , "PICMG IPMB0 Link State" },
+ { IPMI_OEM_PICMG , 0xF2 , "PICMG Module Hotswap" },
+
+ { 0xffffff, 0x00, NULL }
+};
+
+const struct valstr ipmi_netfn_vals[] = {
+ { IPMI_NETFN_CHASSIS, "Chassis" },
+ { IPMI_NETFN_BRIDGE, "Bridge" },
+ { IPMI_NETFN_SE, "SensorEvent" },
+ { IPMI_NETFN_APP, "Application" },
+ { IPMI_NETFN_FIRMWARE, "Firmware" },
+ { IPMI_NETFN_STORAGE, "Storage" },
+ { IPMI_NETFN_TRANSPORT, "Transport" },
+ { 0xff, NULL },
+};
+
+/*
+ * From table 26-4 of the IPMI v2 specification
+ */
+const struct valstr ipmi_bit_rate_vals[] = {
+ { 0x00, "IPMI-Over-Serial-Setting"}, /* Using the value in the IPMI Over Serial Config */
+ { 0x06, "9.6" },
+ { 0x07, "19.2" },
+ { 0x08, "38.4" },
+ { 0x09, "57.6" },
+ { 0x0A, "115.2" },
+ { 0x00, NULL },
+};
+
+const struct valstr ipmi_channel_activity_type_vals[] = {
+ { 0, "IPMI Messaging session active" },
+ { 1, "Callback Messaging session active" },
+ { 2, "Dial-out Alert active" },
+ { 3, "TAP Page Active" },
+ { 0x00, NULL },
+};
+
+
+const struct valstr ipmi_privlvl_vals[] = {
+ { IPMI_SESSION_PRIV_CALLBACK, "CALLBACK" },
+ { IPMI_SESSION_PRIV_USER, "USER" },
+ { IPMI_SESSION_PRIV_OPERATOR, "OPERATOR" },
+ { IPMI_SESSION_PRIV_ADMIN, "ADMINISTRATOR" },
+ { IPMI_SESSION_PRIV_OEM, "OEM" },
+ { 0xF, "NO ACCESS" },
+ { 0xFF, NULL },
+};
+
+
+const struct valstr ipmi_set_in_progress_vals[] = {
+ { IPMI_SET_IN_PROGRESS_SET_COMPLETE, "set-complete" },
+ { IPMI_SET_IN_PROGRESS_IN_PROGRESS, "set-in-progress" },
+ { IPMI_SET_IN_PROGRESS_COMMIT_WRITE, "commit-write" },
+ { 0, NULL },
+};
+
+
+const struct valstr ipmi_authtype_session_vals[] = {
+ { IPMI_SESSION_AUTHTYPE_NONE, "NONE" },
+ { IPMI_SESSION_AUTHTYPE_MD2, "MD2" },
+ { IPMI_SESSION_AUTHTYPE_MD5, "MD5" },
+ { IPMI_SESSION_AUTHTYPE_PASSWORD, "PASSWORD" },
+ { IPMI_SESSION_AUTHTYPE_OEM, "OEM" },
+ { IPMI_SESSION_AUTHTYPE_RMCP_PLUS,"RMCP+" },
+ { 0xFF, NULL },
+};
+
+
+const struct valstr ipmi_authtype_vals[] = {
+ { IPMI_1_5_AUTH_TYPE_BIT_NONE, "NONE" },
+ { IPMI_1_5_AUTH_TYPE_BIT_MD2, "MD2" },
+ { IPMI_1_5_AUTH_TYPE_BIT_MD5, "MD5" },
+ { IPMI_1_5_AUTH_TYPE_BIT_PASSWORD, "PASSWORD" },
+ { IPMI_1_5_AUTH_TYPE_BIT_OEM, "OEM" },
+ { 0, NULL },
+};
+
+const struct valstr entity_id_vals[] = {
+ { 0x00, "Unspecified" },
+ { 0x01, "Other" },
+ { 0x02, "Unknown" },
+ { 0x03, "Processor" },
+ { 0x04, "Disk or Disk Bay" },
+ { 0x05, "Peripheral Bay" },
+ { 0x06, "System Management Module" },
+ { 0x07, "System Board" },
+ { 0x08, "Memory Module" },
+ { 0x09, "Processor Module" },
+ { 0x0a, "Power Supply" },
+ { 0x0b, "Add-in Card" },
+ { 0x0c, "Front Panel Board" },
+ { 0x0d, "Back Panel Board" },
+ { 0x0e, "Power System Board" },
+ { 0x0f, "Drive Backplane" },
+ { 0x10, "System Internal Expansion Board" },
+ { 0x11, "Other System Board" },
+ { 0x12, "Processor Board" },
+ { 0x13, "Power Unit" },
+ { 0x14, "Power Module" },
+ { 0x15, "Power Management" },
+ { 0x16, "Chassis Back Panel Board" },
+ { 0x17, "System Chassis" },
+ { 0x18, "Sub-Chassis" },
+ { 0x19, "Other Chassis Board" },
+ { 0x1a, "Disk Drive Bay" },
+ { 0x1b, "Peripheral Bay" },
+ { 0x1c, "Device Bay" },
+ { 0x1d, "Fan Device" },
+ { 0x1e, "Cooling Unit" },
+ { 0x1f, "Cable/Interconnect" },
+ { 0x20, "Memory Device" },
+ { 0x21, "System Management Software" },
+ { 0x22, "BIOS" },
+ { 0x23, "Operating System" },
+ { 0x24, "System Bus" },
+ { 0x25, "Group" },
+ { 0x26, "Remote Management Device" },
+ { 0x27, "External Environment" },
+ { 0x28, "Battery" },
+ { 0x29, "Processing Blade" },
+ { 0x2A, "Connectivity Switch" },
+ { 0x2B, "Processor/Memory Module" },
+ { 0x2C, "I/O Module" },
+ { 0x2D, "Processor/IO Module" },
+ { 0x2E, "Management Controller Firmware" },
+ { 0x2F, "IPMI Channel" },
+ { 0x30, "PCI Bus" },
+ { 0x31, "PCI Express Bus" },
+ { 0x32, "SCSI Bus (parallel)" },
+ { 0x33, "SATA/SAS Bus" },
+ { 0x34, "Processor/Front-Side Bus" },
+ { 0x35, "Real Time Clock(RTC)" },
+ { 0x36, "Reserved" },
+ { 0x37, "Air Inlet" },
+ { 0x38, "Reserved" },
+ { 0x39, "Reserved" },
+ { 0x3A, "Reserved" },
+ { 0x3B, "Reserved" },
+ { 0x3C, "Reserved" },
+ { 0x3D, "Reserved" },
+ { 0x3E, "Reserved" },
+ { 0x3F, "Reserved" },
+ { 0x40, "Air Inlet" },
+ { 0x41, "Processor" },
+ { 0x42, "Baseboard/Main System Board" },
+ /* PICMG */
+ { 0xA0, "PICMG Front Board" },
+ { 0xC0, "PICMG Rear Transition Module" },
+ { 0xC1, "PICMG AdvancedMC Module" },
+ { 0xF0, "PICMG Shelf Management Controller" },
+ { 0xF1, "PICMG Filtration Unit" },
+ { 0xF2, "PICMG Shelf FRU Information" },
+ { 0xF3, "PICMG Alarm Panel" },
+ { 0x00, NULL },
+};
+
+const struct valstr entity_device_type_vals[] = {
+ { 0x00, "Reserved" },
+ { 0x01, "Reserved" },
+ { 0x02, "DS1624 temperature sensor" },
+ { 0x03, "DS1621 temperature sensor" },
+ { 0x04, "LM75 Temperature Sensor" },
+ { 0x05, "Heceta ASIC" },
+ { 0x06, "Reserved" },
+ { 0x07, "Reserved" },
+ { 0x08, "EEPROM, 24C01" },
+ { 0x09, "EEPROM, 24C02" },
+ { 0x0a, "EEPROM, 24C04" },
+ { 0x0b, "EEPROM, 24C08" },
+ { 0x0c, "EEPROM, 24C16" },
+ { 0x0d, "EEPROM, 24C17" },
+ { 0x0e, "EEPROM, 24C32" },
+ { 0x0f, "EEPROM, 24C64" },
+ { 0x1000, "IPMI FRU Inventory" },
+ { 0x1001, "DIMM Memory ID" },
+ { 0x1002, "IPMI FRU Inventory" },
+ { 0x1003, "System Processor Cartridge FRU" },
+ { 0x11, "Reserved" },
+ { 0x12, "Reserved" },
+ { 0x13, "Reserved" },
+ { 0x14, "PCF 8570 256 byte RAM" },
+ { 0x15, "PCF 8573 clock/calendar" },
+ { 0x16, "PCF 8574A I/O Port" },
+ { 0x17, "PCF 8583 clock/calendar" },
+ { 0x18, "PCF 8593 clock/calendar" },
+ { 0x19, "Clock calendar" },
+ { 0x1a, "PCF 8591 A/D, D/A Converter" },
+ { 0x1b, "I/O Port" },
+ { 0x1c, "A/D Converter" },
+ { 0x1d, "D/A Converter" },
+ { 0x1e, "A/D, D/A Converter" },
+ { 0x1f, "LCD Controller/Driver" },
+ { 0x20, "Core Logic (Chip set) Device" },
+ { 0x21, "LMC6874 Intelligent Battery controller" },
+ { 0x22, "Intelligent Batter controller" },
+ { 0x23, "Combo Management ASIC" },
+ { 0x24, "Maxim 1617 Temperature Sensor" },
+ { 0xbf, "Other/Unspecified" },
+ { 0x00, NULL },
+};
+
+const struct valstr ipmi_channel_protocol_vals[] = {
+ { 0x00, "reserved" },
+ { 0x01, "IPMB-1.0" },
+ { 0x02, "ICMB-1.0" },
+ { 0x03, "reserved" },
+ { 0x04, "IPMI-SMBus" },
+ { 0x05, "KCS" },
+ { 0x06, "SMIC" },
+ { 0x07, "BT-10" },
+ { 0x08, "BT-15" },
+ { 0x09, "TMode" },
+ { 0x1c, "OEM 1" },
+ { 0x1d, "OEM 2" },
+ { 0x1e, "OEM 3" },
+ { 0x1f, "OEM 4" },
+ { 0x00, NULL },
+};
+
+
+const struct valstr ipmi_channel_medium_vals[] = {
+ { IPMI_CHANNEL_MEDIUM_RESERVED, "reserved" },
+ { IPMI_CHANNEL_MEDIUM_IPMB_I2C, "IPMB (I2C)" },
+ { IPMI_CHANNEL_MEDIUM_ICMB_1, "ICMB v1.0" },
+ { IPMI_CHANNEL_MEDIUM_ICMB_09, "ICMB v0.9" },
+ { IPMI_CHANNEL_MEDIUM_LAN, "802.3 LAN" },
+ { IPMI_CHANNEL_MEDIUM_SERIAL, "Serial/Modem" },
+ { IPMI_CHANNEL_MEDIUM_LAN_OTHER,"Other LAN" },
+ { IPMI_CHANNEL_MEDIUM_SMBUS_PCI,"PCI SMBus" },
+ { IPMI_CHANNEL_MEDIUM_SMBUS_1, "SMBus v1.0/v1.1" },
+ { IPMI_CHANNEL_MEDIUM_SMBUS_2, "SMBus v2.0" },
+ { IPMI_CHANNEL_MEDIUM_USB_1, "USB 1.x" },
+ { IPMI_CHANNEL_MEDIUM_USB_2, "USB 2.x" },
+ { IPMI_CHANNEL_MEDIUM_SYSTEM, "System Interface" },
+ { 0x00, NULL },
+};
+
+const struct valstr completion_code_vals[] = {
+ { 0x00, "Command completed normally" },
+ { 0xc0, "Node busy" },
+ { 0xc1, "Invalid command" },
+ { 0xc2, "Invalid command on LUN" },
+ { 0xc3, "Timeout" },
+ { 0xc4, "Out of space" },
+ { 0xc5, "Reservation cancelled or invalid" },
+ { 0xc6, "Request data truncated" },
+ { 0xc7, "Request data length invalid" },
+ { 0xc8, "Request data field length limit exceeded" },
+ { 0xc9, "Parameter out of range" },
+ { 0xca, "Cannot return number of requested data bytes" },
+ { 0xcb, "Requested sensor, data, or record not found" },
+ { 0xcc, "Invalid data field in request" },
+ { 0xcd, "Command illegal for specified sensor or record type" },
+ { 0xce, "Command response could not be provided" },
+ { 0xcf, "Cannot execute duplicated request" },
+ { 0xd0, "SDR Repository in update mode" },
+ { 0xd1, "Device firmeware in update mode" },
+ { 0xd2, "BMC initialization in progress" },
+ { 0xd3, "Destination unavailable" },
+ { 0xd4, "Insufficient privilege level" },
+ { 0xd5, "Command not supported in present state" },
+ { 0xd6, "Cannot execute command, command disabled" },
+ { 0xff, "Unspecified error" },
+ { 0x00, NULL }
+};
+
+const struct valstr ipmi_chassis_power_control_vals[] = {
+ { IPMI_CHASSIS_CTL_POWER_DOWN, "Down/Off" },
+ { IPMI_CHASSIS_CTL_POWER_UP, "Up/On" },
+ { IPMI_CHASSIS_CTL_POWER_CYCLE, "Cycle" },
+ { IPMI_CHASSIS_CTL_HARD_RESET, "Reset" },
+ { IPMI_CHASSIS_CTL_PULSE_DIAG, "Diag" },
+ { IPMI_CHASSIS_CTL_ACPI_SOFT, "Soft" },
+ { 0x00, NULL },
+};
+
+const struct valstr ipmi_auth_algorithms[] = {
+ { IPMI_AUTH_RAKP_NONE, "none" },
+ { IPMI_AUTH_RAKP_HMAC_SHA1, "hmac_sha1" },
+ { IPMI_AUTH_RAKP_HMAC_MD5, "hmac_md5" },
+ { 0x00, NULL }
+};
+
+const struct valstr ipmi_integrity_algorithms[] = {
+ { IPMI_INTEGRITY_NONE, "none" },
+ { IPMI_INTEGRITY_HMAC_SHA1_96, "hmac_sha1_96" },
+ { IPMI_INTEGRITY_HMAC_MD5_128, "hmac_md5_128" },
+ { IPMI_INTEGRITY_MD5_128 , "md5_128" },
+ { 0x00, NULL }
+};
+
+const struct valstr ipmi_encryption_algorithms[] = {
+ { IPMI_CRYPT_NONE, "none" },
+ { IPMI_CRYPT_AES_CBC_128, "aes_cbc_128" },
+ { IPMI_CRYPT_XRC4_128, "xrc4_128" },
+ { IPMI_CRYPT_XRC4_40, "xrc4_40" },
+ { 0x00, NULL }
+};
+
+const struct valstr picmg_frucontrol_vals[] = {
+ { 0, "Cold Reset" },
+ { 1, "Warm Reset" },
+ { 2, "Graceful Reboot" },
+ { 3, "Issue Diagnostic Interrupt" },
+ { 4, "Quiesce" },
+ { 5, NULL },
+};
+
+const struct valstr picmg_clk_family_vals[] = {
+ { 0x00, "Unspecified" },
+ { 0x01, "SONET/SDH/PDH" },
+ { 0x02, "Reserved for PCI Express" },
+ { 0x03, "Reserved" }, /* from 03h to C8h */
+ { 0xC9, "Vendor defined clock family" }, /* from C9h to FFh */
+ { 0x00, NULL },
+};
+
+const struct oemvalstr picmg_clk_accuracy_vals[] = {
+ { 0x01, 10, "PRS" },
+ { 0x01, 20, "STU" },
+ { 0x01, 30, "ST2" },
+ { 0x01, 40, "TNC" },
+ { 0x01, 50, "ST3E" },
+ { 0x01, 60, "ST3" },
+ { 0x01, 70, "SMC" },
+ { 0x01, 80, "ST4" },
+ { 0x01, 90, "DUS" },
+ { 0x02, 0xE0, "PCI Express Generation 2" },
+ { 0x02, 0xF0, "PCI Express Generation 1" },
+ { 0xffffff, 0x00, NULL }
+};
+
+const struct oemvalstr picmg_clk_resource_vals[] = {
+ { 0x0, 0, "On-Carrier Device 0" },
+ { 0x0, 1, "On-Carrier Device 1" },
+ { 0x1, 1, "AMC Site 1 - A1" },
+ { 0x1, 2, "AMC Site 1 - A2" },
+ { 0x1, 3, "AMC Site 1 - A3" },
+ { 0x1, 4, "AMC Site 1 - A4" },
+ { 0x1, 5, "AMC Site 1 - B1" },
+ { 0x1, 6, "AMC Site 1 - B2" },
+ { 0x1, 7, "AMC Site 1 - B3" },
+ { 0x1, 8, "AMC Site 1 - B4" },
+ { 0x2, 0, "ATCA Backplane" },
+ { 0xffffff, 0x00, NULL }
+};
+
+const struct oemvalstr picmg_clk_id_vals[] = {
+ { 0x0, 0, "Clock 0" },
+ { 0x0, 1, "Clock 1" },
+ { 0x0, 2, "Clock 2" },
+ { 0x0, 3, "Clock 3" },
+ { 0x0, 4, "Clock 4" },
+ { 0x0, 5, "Clock 5" },
+ { 0x0, 6, "Clock 6" },
+ { 0x0, 7, "Clock 7" },
+ { 0x0, 8, "Clock 8" },
+ { 0x0, 9, "Clock 9" },
+ { 0x0, 10, "Clock 10" },
+ { 0x0, 11, "Clock 11" },
+ { 0x0, 12, "Clock 12" },
+ { 0x0, 13, "Clock 13" },
+ { 0x0, 14, "Clock 14" },
+ { 0x0, 15, "Clock 15" },
+ { 0x1, 1, "TCLKA" },
+ { 0x1, 2, "TCLKB" },
+ { 0x1, 3, "TCLKC" },
+ { 0x1, 4, "TCLKD" },
+ { 0x1, 5, "FLCKA" },
+ { 0x2, 1, "CLK1A" },
+ { 0x2, 2, "CLK1A" },
+ { 0x2, 3, "CLK1A" },
+ { 0x2, 4, "CLK1A" },
+ { 0x2, 5, "CLK1A" },
+ { 0x2, 6, "CLK1A" },
+ { 0x2, 7, "CLK1A" },
+ { 0x2, 8, "CLK1A" },
+ { 0x2, 9, "CLK1A" },
+ { 0xffffff, 0x00, NULL }
+};
+
+const struct valstr picmg_busres_id_vals[] = {
+ { 0x0, "Metallic Test Bus pair #1" },
+ { 0x1, "Metallic Test Bus pair #2" },
+ { 0x2, "Synch clock group 1 (CLK1)" },
+ { 0x3, "Synch clock group 2 (CLK2)" },
+ { 0x4, "Synch clock group 3 (CLK3)" },
+ { 0x5, NULL }
+};
+const struct valstr picmg_busres_board_cmd_vals[] = {
+ { 0x0, "Query" },
+ { 0x1, "Release" },
+ { 0x2, "Force" },
+ { 0x3, "Bus Free" },
+ { 0x4, NULL }
+};
+
+const struct valstr picmg_busres_shmc_cmd_vals[] = {
+ { 0x0, "Request" },
+ { 0x1, "Relinquish" },
+ { 0x2, "Notify" },
+ { 0x3, NULL }
+};
+
+const struct oemvalstr picmg_busres_board_status_vals[] = {
+ { 0x0, 0x0, "In control" },
+ { 0x0, 0x1, "No control" },
+ { 0x1, 0x0, "Ack" },
+ { 0x1, 0x1, "Refused" },
+ { 0x1, 0x2, "No control" },
+ { 0x2, 0x0, "Ack" },
+ { 0x2, 0x1, "No control" },
+ { 0x3, 0x0, "Accept" },
+ { 0x3, 0x1, "Not Needed" },
+ { 0xffffff, 0x00, NULL }
+};
+
+const struct oemvalstr picmg_busres_shmc_status_vals[] = {
+ { 0x0, 0x0, "Grant" },
+ { 0x0, 0x1, "Busy" },
+ { 0x0, 0x2, "Defer" },
+ { 0x0, 0x3, "Deny" },
+
+ { 0x1, 0x0, "Ack" },
+ { 0x1, 0x1, "Error" },
+
+ { 0x2, 0x0, "Ack" },
+ { 0x2, 0x1, "Error" },
+ { 0x2, 0x2, "Deny" },
+
+ { 0xffffff, 0x00, NULL }
+};
diff --git a/lib/ipmi_sunoem.c b/lib/ipmi_sunoem.c
new file mode 100644
index 0000000..16a6090
--- /dev/null
+++ b/lib/ipmi_sunoem.c
@@ -0,0 +1,2434 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <signal.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include <termios.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi_sel.h>
+#include <ipmitool/ipmi_sdr.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_channel.h>
+#include <ipmitool/ipmi_sunoem.h>
+#include <ipmitool/ipmi_raw.h>
+
+static const struct valstr sunoem_led_type_vals[] = {
+ { 0, "OK2RM" },
+ { 1, "SERVICE" },
+ { 2, "ACT" },
+ { 3, "LOCATE" },
+ { 0xFF, NULL },
+};
+
+static const struct valstr sunoem_led_mode_vals[] = {
+ { 0, "OFF" },
+ { 1, "ON" },
+ { 2, "STANDBY" },
+ { 3, "SLOW" },
+ { 4, "FAST" },
+ { 0xFF, NULL },
+};
+
+static const struct valstr sunoem_led_mode_optvals[] = {
+ { 0, "STEADY_OFF" },
+ { 1, "STEADY_ON" },
+ { 2, "STANDBY_BLINK" },
+ { 3, "SLOW_BLINK" },
+ { 4, "FAST_BLINK" },
+ { 0xFF, NULL },
+};
+
+#define SUNOEM_SUCCESS 1
+
+#define IPMI_SUNOEM_GETFILE_VERSION {3,2,0,0}
+#define IPMI_SUNOEM_GETBEHAVIOR_VERSION {3,2,0,0}
+
+/*
+ * PRINT_NORMAL: print out the LED value as normal
+ * PRINT_ERROR: print out "na" for the LED value
+ */
+typedef enum
+{
+ PRINT_NORMAL = 0, PRINT_ERROR
+} print_status_t;
+
+int ret_get = 0;
+int ret_set = 0;
+
+static void
+ipmi_sunoem_usage(void)
+{
+ lprintf(LOG_NOTICE, "Usage: sunoem <command> [option...]");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, "Commands:");
+ lprintf(LOG_NOTICE, " - cli [<command string> ...]");
+ lprintf(LOG_NOTICE, " Execute SP CLI commands.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - led get [<sensor_id>] [ledtype]");
+ lprintf(LOG_NOTICE, " - Read status of LED found in Generic Device Locator.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - led set <sensor_id> <led_mode> [led_type]");
+ lprintf(LOG_NOTICE, " - Set mode of LED found in Generic Device Locator.");
+ lprintf(LOG_NOTICE, " - You can pass 'all' as the <senso_rid> to change the LED mode of all sensors.");
+ lprintf(LOG_NOTICE, " - Use 'sdr list generic' command to get list of Generic");
+ lprintf(LOG_NOTICE, " - Devices that are controllable LEDs.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - Required SIS LED Mode:");
+ lprintf(LOG_NOTICE, " OFF Off");
+ lprintf(LOG_NOTICE, " ON Steady On");
+ lprintf(LOG_NOTICE, " STANDBY 100ms on 2900ms off blink rate");
+ lprintf(LOG_NOTICE, " SLOW 1HZ blink rate");
+ lprintf(LOG_NOTICE, " FAST 4HZ blink rate");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - Optional SIS LED Type:");
+ lprintf(LOG_NOTICE, " OK2RM OK to Remove");
+ lprintf(LOG_NOTICE, " SERVICE Service Required");
+ lprintf(LOG_NOTICE, " ACT Activity");
+ lprintf(LOG_NOTICE, " LOCATE Locate");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - nacname <ipmi_nac_name>");
+ lprintf(LOG_NOTICE, " - Returns the full nac name");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - ping NUMBER <q>");
+ lprintf(LOG_NOTICE, " - Send and Receive NUMBER (64 Byte) packets.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - q - Quiet. Displays output at start and end");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - getval <target_name>");
+ lprintf(LOG_NOTICE, " - Returns the ILOM property value");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - setval <property name> <property value> <timeout>");
+ lprintf(LOG_NOTICE, " - Sets the ILOM property value");
+ lprintf(LOG_NOTICE, " - If timeout is not specified, the default is 5 sec.");
+ lprintf(LOG_NOTICE, " - NOTE: must be executed locally on host, not remotely over LAN!");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - sshkey del <user_id>");
+ lprintf(LOG_NOTICE, " - Delete ssh key for user id from authorized_keys,");
+ lprintf(LOG_NOTICE, " - view users with 'user list' command.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - sshkey set <user_id> <id_rsa.pub>");
+ lprintf(LOG_NOTICE, " - Set ssh key for a userid into authorized_keys,");
+ lprintf(LOG_NOTICE, " - view users with 'user list' command.");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - version");
+ lprintf(LOG_NOTICE, " - Display the software version");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - nacname <ipmi_nac_name>");
+ lprintf(LOG_NOTICE, " - Returns the full nac name");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - getfile <file_string_id> <destination_file_name>");
+ lprintf(LOG_NOTICE, " - Copy file <file_string_id> to <destination_file_name>");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - File string ids:");
+ lprintf(LOG_NOTICE, " SSH_PUBKEYS");
+ lprintf(LOG_NOTICE, " DIAG_PASSED");
+ lprintf(LOG_NOTICE, " DIAG_FAILED");
+ lprintf(LOG_NOTICE, " DIAG_END_TIME");
+ lprintf(LOG_NOTICE, " DIAG_INVENTORY");
+ lprintf(LOG_NOTICE, " DIAG_TEST_LOG");
+ lprintf(LOG_NOTICE, " DIAG_START_TIME");
+ lprintf(LOG_NOTICE, " DIAG_UEFI_LOG");
+ lprintf(LOG_NOTICE, " DIAG_TEST_LOG");
+ lprintf(LOG_NOTICE, " DIAG_LAST_LOG");
+ lprintf(LOG_NOTICE, " DIAG_LAST_CMD");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - getbehavior <behavior_string_id>");
+ lprintf(LOG_NOTICE, " - Test if ILOM behavior is enabled");
+ lprintf(LOG_NOTICE, "");
+ lprintf(LOG_NOTICE, " - Behavior string ids:");
+ lprintf(LOG_NOTICE, " SUPPORTS_SIGNED_PACKAGES");
+ lprintf(LOG_NOTICE, " REQUIRES_SIGNED_PACKAGES");
+ lprintf(LOG_NOTICE, "");
+}
+
+#define SUNOEM_FAN_MODE_AUTO 0x00
+#define SUNOEM_FAN_MODE_MANUAL 0x01
+
+static void
+__sdr_list_empty(struct sdr_record_list * head)
+{
+ struct sdr_record_list * e, *f;
+ for (e = head; e != NULL; e = f) {
+ f = e->next;
+ free(e);
+ }
+ head = NULL;
+}
+
+/*
+ * led_print
+ * Print out the led name and the state, if stat is PRINT_NORMAL.
+ * Otherwise, print out the led name and "na".
+ * The state parameter is not referenced if stat is not PRINT_NORMAL.
+ */
+static void
+led_print(const char * name, print_status_t stat, uint8_t state)
+{
+ const char *theValue;
+
+ if (stat == PRINT_NORMAL) {
+ theValue = val2str(state, sunoem_led_mode_vals);
+ } else {
+ theValue = "na";
+ }
+
+ if (csv_output) {
+ printf("%s,%s\n", name, theValue);
+ } else {
+ printf("%-16s | %s\n", name, theValue);
+ }
+}
+
+#define CC_NORMAL 0x00
+#define CC_PARAM_OUT_OF_RANGE 0xc9
+#define CC_DEST_UNAVAILABLE 0xd3
+#define CC_UNSPECIFIED_ERR 0xff
+#define CC_INSUFFICIENT_PRIVILEGE 0xd4
+#define CC_INV_CMD 0xc1
+#define CC_INV_DATA_FIELD 0xcc
+
+/*
+ * sunoem_led_get(....)
+ *
+ * OUTPUT:
+ * SUNOEM_EC_INVALID_ARG if dev is NULL,
+ * SUNOEM_EC_BMC_NOT_RESPONDING if no reply is obtained from BMC,
+ * SUNOEM_EC_BMC_CCODE_NONZERO if completion code is nonzero,
+ * SUNOEM_EC_SUCCESS otherwise.
+ */
+static sunoem_ec_t
+sunoem_led_get(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev,
+ int ledtype, struct ipmi_rs **loc_rsp)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[7];
+ int rqdata_len;
+
+ if (dev == NULL) {
+ *loc_rsp = NULL;
+ return (SUNOEM_EC_INVALID_ARG);
+ }
+
+ rqdata[0] = dev->dev_slave_addr;
+ if (ledtype == 0xFF)
+ rqdata[1] = dev->oem;
+ else
+ rqdata[1] = ledtype;
+
+ rqdata[2] = dev->dev_access_addr;
+ rqdata[3] = dev->oem;
+ rqdata[4] = dev->entity.id;
+ rqdata[5] = dev->entity.instance;
+ rqdata[6] = 0;
+ rqdata_len = 7;
+
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_LED_GET;
+ req.msg.lun = dev->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = rqdata_len;
+
+ rsp = intf->sendrecv(intf, &req);
+ /*
+ * Just return NULL if there was
+ * an error.
+ */
+ if (rsp == NULL) {
+ *loc_rsp = NULL;
+ return (SUNOEM_EC_BMC_NOT_RESPONDING);
+ } else if (rsp->ccode > 0) {
+ *loc_rsp = rsp;
+ return (SUNOEM_EC_BMC_CCODE_NONZERO);
+ } else {
+ *loc_rsp = rsp;
+ return (SUNOEM_EC_SUCCESS);
+ }
+}
+
+static struct ipmi_rs *
+sunoem_led_set(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev,
+ int ledtype, int ledmode)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t rqdata[9];
+ int rqdata_len;
+
+ if (dev == NULL)
+ return NULL;
+
+ rqdata[0] = dev->dev_slave_addr;
+
+ if (ledtype == 0xFF)
+ rqdata[1] = dev->oem;
+ else
+ rqdata[1] = ledtype;
+
+ rqdata[2] = dev->dev_access_addr;
+ rqdata[3] = dev->oem;
+ rqdata[4] = ledmode;
+ rqdata[5] = dev->entity.id;
+ rqdata[6] = dev->entity.instance;
+ rqdata[7] = 0;
+ rqdata[8] = 0;
+ rqdata_len = 9;
+
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_LED_SET;
+ req.msg.lun = dev->lun;
+ req.msg.data = rqdata;
+ req.msg.data_len = rqdata_len;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM Set LED command failed.");
+ return NULL;
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Sun OEM Set LED command failed: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return NULL;
+ }
+
+ return (rsp);
+}
+
+static void
+sunoem_led_get_byentity(struct ipmi_intf * intf, uint8_t entity_id,
+ uint8_t entity_inst, int ledtype)
+{
+ struct ipmi_rs * rsp;
+ struct sdr_record_list *elist, *e;
+ struct entity_id entity;
+ sunoem_ec_t res;
+
+ if (entity_id == 0)
+ return;
+
+ /* lookup sdrs with this entity */
+ memset(&entity, 0, sizeof(struct entity_id));
+ entity.id = entity_id;
+ entity.instance = entity_inst;
+
+ elist = ipmi_sdr_find_sdr_byentity(intf, &entity);
+
+ if (elist == NULL)
+ ret_get = -1;
+
+ /* for each generic sensor get its led state */
+ for (e = elist; e != NULL; e = e->next) {
+ if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+
+ res = sunoem_led_get(intf, e->record.genloc, ledtype, &rsp);
+
+ if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) {
+ led_print((const char *) e->record.genloc->id_string, PRINT_NORMAL,
+ rsp->data[0]);
+ } else {
+ led_print((const char *) e->record.genloc->id_string, PRINT_ERROR,
+ 0);
+ if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp
+ || rsp->ccode != CC_DEST_UNAVAILABLE) {
+ ret_get = -1;
+ }
+ }
+ }
+ __sdr_list_empty(elist);
+}
+
+static void
+sunoem_led_set_byentity(struct ipmi_intf * intf, uint8_t entity_id,
+ uint8_t entity_inst, int ledtype, int ledmode)
+{
+ struct ipmi_rs * rsp;
+ struct sdr_record_list *elist, *e;
+ struct entity_id entity;
+
+ if (entity_id == 0)
+ return;
+
+ /* lookup sdrs with this entity */
+ memset(&entity, 0, sizeof(struct entity_id));
+ entity.id = entity_id;
+ entity.instance = entity_inst;
+
+ elist = ipmi_sdr_find_sdr_byentity(intf, &entity);
+
+ if (elist == NULL)
+ ret_set = -1;
+
+ /* for each generic sensor set its led state */
+ for (e = elist; e != NULL; e = e->next) {
+
+ if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+
+ rsp = sunoem_led_set(intf, e->record.genloc, ledtype, ledmode);
+ if (rsp && rsp->data_len == 0) {
+ led_print((const char *) e->record.genloc->id_string, PRINT_NORMAL,
+ ledmode);
+ } else if (rsp == NULL) {
+ ret_set = -1;
+ }
+ }
+
+ __sdr_list_empty(elist);
+}
+
+/*
+ * IPMI Request Data: 5 bytes
+ *
+ * [byte 0] devAddr Value from the "Device Slave Address" field in
+ * LED's Generic Device Locator record in the SDR
+ * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE
+ * [byte 2] ctrlrAddr Controller address; value from the "Device
+ * Access Address" field, 0x20 if the LED is local
+ * [byte 3] hwInfo The OEM field from the SDR record
+ * [byte 4] force 1 = directly access the device
+ * 0 = go thru its controller
+ * Ignored if LED is local
+ *
+ * The format below is for Sun Blade Modular systems only
+ * [byte 4] entityID The entityID field from the SDR record
+ * [byte 5] entityIns The entityIns field from the SDR record
+ * [byte 6] force 1 = directly access the device
+ * 0 = go thru its controller
+ * Ignored if LED is local
+ */
+static int
+ipmi_sunoem_led_get(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct sdr_record_list *sdr;
+ struct sdr_record_list *alist, *a;
+ struct sdr_record_entity_assoc *assoc;
+ int ledtype = 0xFF;
+ int i;
+ sunoem_ec_t res;
+
+ /*
+ * sunoem led/sbled get <id> [type]
+ */
+
+ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
+ ipmi_sunoem_usage();
+ return (0);
+ }
+
+ if (argc > 1) {
+ ledtype = str2val(argv[1], sunoem_led_type_vals);
+ if (ledtype == 0xFF)
+ lprintf(LOG_ERR,
+ "Unknow ledtype, will use data from the SDR oem field");
+ }
+
+ if (strncasecmp(argv[0], "all", 3) == 0) {
+ /* do all generic sensors */
+ alist = ipmi_sdr_find_sdr_bytype(intf,
+ SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
+
+ if (alist == NULL)
+ return (-1);
+
+ for (a = alist; a != NULL; a = a->next) {
+ if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+ if (a->record.genloc->entity.logical)
+ continue;
+
+ res = sunoem_led_get(intf, a->record.genloc, ledtype, &rsp);
+
+ if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) {
+ led_print((const char *) a->record.genloc->id_string,
+ PRINT_NORMAL, rsp->data[0]);
+ } else {
+ led_print((const char *) a->record.genloc->id_string,
+ PRINT_ERROR, 0);
+ if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp ||
+ rsp->ccode != CC_DEST_UNAVAILABLE) {
+ ret_get = -1;
+ }
+ }
+ }
+ __sdr_list_empty(alist);
+
+ if (ret_get == -1)
+ return (-1);
+
+ return (0);
+ }
+
+ /* look up generic device locator record in SDR */
+ sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]);
+
+ if (sdr == NULL) {
+ lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]);
+ return (-1);
+ }
+
+ if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) {
+ lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type);
+ return (-1);
+ }
+
+ if (!sdr->record.genloc->entity.logical) {
+ /*
+ * handle physical entity
+ */
+
+ res = sunoem_led_get(intf, sdr->record.genloc, ledtype, &rsp);
+
+ if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) {
+ led_print((const char *) sdr->record.genloc->id_string,
+ PRINT_NORMAL, rsp->data[0]);
+
+ } else {
+ led_print((const char *) sdr->record.genloc->id_string, PRINT_ERROR,
+ 0);
+ if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp
+ || rsp->ccode != CC_DEST_UNAVAILABLE) {
+ ret_get = -1;
+ }
+ }
+
+ if (ret_get == -1)
+ return (-1);
+
+ return (0);
+ }
+
+ /*
+ * handle logical entity for LED grouping
+ */
+
+ lprintf(LOG_INFO, "LED %s is logical device", argv[0]);
+
+ /* get entity assoc records */
+ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC);
+
+ if (alist == NULL)
+ return (-1);
+
+ for (a = alist; a != NULL; a = a->next) {
+ if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC)
+ continue;
+ assoc = a->record.entassoc;
+ if (assoc == NULL)
+ continue;
+
+ /* check that the entity id/instance matches our generic record */
+ if (assoc->entity.id != sdr->record.genloc->entity.id
+ || assoc->entity.instance
+ != sdr->record.genloc->entity.instance)
+ continue;
+
+ if (assoc->flags.isrange) {
+ /*
+ * handle ranged entity associations
+ *
+ * the test for non-zero entity id is handled in
+ * sunoem_led_get_byentity()
+ */
+
+ /* first range set - id 1 and 2 must be equal */
+ if (assoc->entity_id_1 == assoc->entity_id_2)
+ for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++)
+ sunoem_led_get_byentity(intf, assoc->entity_id_1, i,
+ ledtype);
+
+ /* second range set - id 3 and 4 must be equal */
+ if (assoc->entity_id_3 == assoc->entity_id_4)
+ for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++)
+ sunoem_led_get_byentity(intf, assoc->entity_id_3, i,
+ ledtype);
+ } else {
+ /*
+ * handle entity list
+ */
+ sunoem_led_get_byentity(intf, assoc->entity_id_1,
+ assoc->entity_inst_1, ledtype);
+ sunoem_led_get_byentity(intf, assoc->entity_id_2,
+ assoc->entity_inst_2, ledtype);
+ sunoem_led_get_byentity(intf, assoc->entity_id_3,
+ assoc->entity_inst_3, ledtype);
+ sunoem_led_get_byentity(intf, assoc->entity_id_4,
+ assoc->entity_inst_4, ledtype);
+ }
+ }
+
+ __sdr_list_empty(alist);
+
+ if (ret_get == -1)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * IPMI Request Data: 7 bytes
+ *
+ * [byte 0] devAddr Value from the "Device Slave Address" field in
+ * LED's Generic Device Locator record in the SDR
+ * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE
+ * [byte 2] ctrlrAddr Controller address; value from the "Device
+ * Access Address" field, 0x20 if the LED is local
+ * [byte 3] hwInfo The OEM field from the SDR record
+ * [byte 4] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST
+ * [byte 5] force TRUE - directly access the device
+ * FALSE - go thru its controller
+ * Ignored if LED is local
+ * [byte 6] role Used by BMC for authorization purposes
+ *
+ * The format below is for Sun Blade Modular systems only
+ * [byte 5] entityID The entityID field from the SDR record
+ * [byte 6] entityIns The entityIns field from the SDR record
+ * [byte 7] force TRUE - directly access the device
+ * FALSE - go thru its controller
+ * Ignored if LED is local
+ * [byte 8] role Used by BMC for authorization purposes
+ *
+ *
+ * IPMI Response Data: 1 byte
+ *
+ * [byte 0] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST
+ */
+
+static int
+ipmi_sunoem_led_set(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct ipmi_rs * rsp;
+ struct sdr_record_list *sdr;
+ struct sdr_record_list *alist, *a;
+ struct sdr_record_entity_assoc *assoc;
+ int ledmode;
+ int ledtype = 0xFF;
+ int i;
+
+ /*
+ * sunoem led/sbled set <id> <mode> [type]
+ */
+
+ if (argc < 2 || strncmp(argv[0], "help", 4) == 0) {
+ ipmi_sunoem_usage();
+ return (0);
+ }
+
+ ledmode = str2val(argv[1], sunoem_led_mode_vals);
+ if (ledmode == 0xFF) {
+ ledmode = str2val(argv[1], sunoem_led_mode_optvals);
+ if (ledmode == 0xFF) {
+ lprintf(LOG_NOTICE, "Invalid LED Mode: %s", argv[1]);
+ return (-1);
+ }
+ }
+
+ if (argc > 3) {
+ ledtype = str2val(argv[2], sunoem_led_type_vals);
+ if (ledtype == 0xFF)
+ lprintf(LOG_ERR,
+ "Unknow ledtype, will use data from the SDR oem field");
+ }
+
+ if (strncasecmp(argv[0], "all", 3) == 0) {
+ /* do all generic sensors */
+ alist = ipmi_sdr_find_sdr_bytype(intf,
+ SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
+
+ if (alist == NULL)
+ return (-1);
+
+ for (a = alist; a != NULL; a = a->next) {
+ if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR)
+ continue;
+ if (a->record.genloc->entity.logical)
+ continue;
+ rsp = sunoem_led_set(intf, a->record.genloc, ledtype, ledmode);
+ if (rsp && rsp->ccode == 0)
+ led_print((const char *) a->record.genloc->id_string,
+ PRINT_NORMAL, ledmode);
+ else
+ ret_set = -1;
+ }
+ __sdr_list_empty(alist);
+
+ if (ret_set == -1)
+ return (-1);
+
+ return (0);
+ }
+
+ /* look up generic device locator records in SDR */
+ sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]);
+
+ if (sdr == NULL) {
+ lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]);
+ return (-1);
+ }
+
+ if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) {
+ lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type);
+ return (-1);
+ }
+
+ if (!sdr->record.genloc->entity.logical) {
+ /*
+ * handle physical entity
+ */
+ rsp = sunoem_led_set(intf, sdr->record.genloc, ledtype, ledmode);
+ if (rsp && rsp->ccode == 0)
+ led_print(argv[0], PRINT_NORMAL, ledmode);
+ else
+ return (-1);
+
+ return (0);
+ }
+
+ /*
+ * handle logical entity for LED grouping
+ */
+
+ lprintf(LOG_INFO, "LED %s is logical device", argv[0]);
+
+ /* get entity assoc records */
+ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC);
+
+ if (alist == NULL)
+ return (-1);
+
+ for (a = alist; a != NULL; a = a->next) {
+ if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC)
+ continue;
+ assoc = a->record.entassoc;
+ if (assoc == NULL)
+ continue;
+
+ /* check that the entity id/instance matches our generic record */
+ if (assoc->entity.id != sdr->record.genloc->entity.id
+ || assoc->entity.instance
+ != sdr->record.genloc->entity.instance)
+ continue;
+
+ if (assoc->flags.isrange) {
+ /*
+ * handle ranged entity associations
+ *
+ * the test for non-zero entity id is handled in
+ * sunoem_led_get_byentity()
+ */
+
+ /* first range set - id 1 and 2 must be equal */
+ if (assoc->entity_id_1 == assoc->entity_id_2)
+ for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++)
+ sunoem_led_set_byentity(intf, assoc->entity_id_1, i,
+ ledtype, ledmode);
+
+ /* second range set - id 3 and 4 must be equal */
+ if (assoc->entity_id_3 == assoc->entity_id_4)
+ for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++)
+ sunoem_led_set_byentity(intf, assoc->entity_id_3, i,
+ ledtype, ledmode);
+ } else {
+ /*
+ * handle entity list
+ */
+ sunoem_led_set_byentity(intf, assoc->entity_id_1,
+ assoc->entity_inst_1, ledtype, ledmode);
+ sunoem_led_set_byentity(intf, assoc->entity_id_2,
+ assoc->entity_inst_2, ledtype, ledmode);
+ sunoem_led_set_byentity(intf, assoc->entity_id_3,
+ assoc->entity_inst_3, ledtype, ledmode);
+ sunoem_led_set_byentity(intf, assoc->entity_id_4,
+ assoc->entity_inst_4, ledtype, ledmode);
+ }
+ }
+
+ __sdr_list_empty(alist);
+
+ if (ret_set == -1)
+ return (-1);
+
+ return (0);
+}
+
+static int
+ipmi_sunoem_sshkey_del(struct ipmi_intf * intf, uint8_t uid)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(struct ipmi_rq));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_DEL_SSH_KEY;
+ req.msg.data = &uid;
+ req.msg.data_len = 1;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to delete ssh key for UID %d", uid);
+ return (-1);
+ } else if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Unable to delete ssh key for UID %d: %s", uid,
+ val2str(rsp->ccode, completion_code_vals));
+ return (-1);
+ }
+
+ printf("Deleted SSH key for user id %d\n", uid);
+ return (0);
+}
+
+#define SSHKEY_BLOCK_SIZE 64
+static int
+ipmi_sunoem_sshkey_set(struct ipmi_intf * intf, uint8_t uid, char * ifile)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ FILE * fp;
+ int count = 0;
+ uint8_t wbuf[SSHKEY_BLOCK_SIZE + 3];
+ int32_t i_size = 0;
+ int32_t r = 0;
+ int32_t size = 0;
+
+ if (ifile == NULL) {
+ lprintf(LOG_ERR, "Invalid or misisng input filename.");
+ return (-1);
+ }
+
+ fp = ipmi_open_file_read(ifile);
+ if (fp == NULL) {
+ lprintf(LOG_ERR, "Unable to open file '%s' for reading.", ifile);
+ return (-1);
+ }
+
+ memset(&req, 0, sizeof(struct ipmi_rq));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_SET_SSH_KEY;
+ req.msg.data = wbuf;
+
+ if (fseek(fp, 0, SEEK_END) == (-1)) {
+ lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile);
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ }
+
+ size = (int32_t) ftell(fp);
+ if (size < 0) {
+ lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile);
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ } else if (size == 0) {
+ lprintf(LOG_ERR, "File '%s' is empty.", ifile);
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ }
+
+ if (fseek(fp, 0, SEEK_SET) == (-1)) {
+ lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile);
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ }
+
+ printf("Setting SSH key for user id %d...", uid);
+
+ for (r = 0; r < size; r += i_size) {
+ i_size = size - r;
+ if (i_size > SSHKEY_BLOCK_SIZE)
+ i_size = SSHKEY_BLOCK_SIZE;
+
+ memset(wbuf, 0, SSHKEY_BLOCK_SIZE);
+ fseek(fp, r, SEEK_SET);
+ count = fread(wbuf + 3, 1, i_size, fp);
+ if (count != i_size) {
+ printf("failed\n");
+ lprintf(LOG_ERR, "Unable to read %ld bytes from file '%s'.", i_size,
+ ifile);
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ }
+
+ printf(".");
+ fflush(stdout);
+
+ wbuf[0] = uid;
+ if ((r + SSHKEY_BLOCK_SIZE) >= size)
+ wbuf[1] = 0xff;
+ else {
+ if ((r / SSHKEY_BLOCK_SIZE) > UINT8_MAX) {
+ printf("failed\n");
+ lprintf(LOG_ERR, "Unable to pack byte %ld from file '%s'.", r,
+ ifile);
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ }
+ wbuf[1] = (uint8_t) (r / SSHKEY_BLOCK_SIZE);
+ }
+
+ wbuf[2] = (uint8_t) i_size;
+
+ req.msg.data_len = i_size + 3;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ printf("failed\n");
+ lprintf(LOG_ERR, "Unable to set ssh key for UID %d.", uid);
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ } /* if (rsp == NULL) */
+ if (rsp->ccode != 0) {
+ printf("failed\n");
+ lprintf(LOG_ERR, "Unable to set ssh key for UID %d, %s.", uid,
+ val2str(rsp->ccode, completion_code_vals));
+ if (fp != NULL)
+ fclose(fp);
+
+ return (-1);
+ } /* if (rsp->ccode != 0) */
+ }
+
+ printf("done\n");
+
+ fclose(fp);
+ return (0);
+}
+
+/*
+ * This structure is used in both the request to and response from the BMC.
+ */
+#define SUNOEM_CLI_LEGACY_VERSION 1
+#define SUNOEM_CLI_SEQNUM_VERSION 2
+#define SUNOEM_CLI_VERSION SUNOEM_CLI_SEQNUM_VERSION
+#define SUNOEM_CLI_HEADER 8 /* command + spare + handle */
+#define SUNOEM_CLI_BUF_SIZE (80 - SUNOEM_CLI_HEADER) /* Total 80 bytes */
+#define SUNOEM_CLI_MSG_SIZE(msg) (SUNOEM_CLI_HEADER + strlen((msg).buf) + 1)
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ /*
+ * Set version to SUNOEM_CLI_VERSION.
+ */
+ uint8_t version;
+ /*
+ * The command in a request, or in a response indicates an error if
+ * non-zero.
+ */
+ uint8_t command_response;
+ uint8_t seqnum;
+ uint8_t spare;
+ /*
+ * Opaque 4-byte handle, supplied in the response to an OPEN request,
+ * and used in all subsequent POLL and CLOSE requests.
+ */
+ uint8_t handle[4];
+ /*
+ * The client data in a request, or the server data in a response. Must
+ * by null terminated, i.e., it must be at least one byte, but can be
+ * smaller if there's less data.
+ */
+ char buf[SUNOEM_CLI_BUF_SIZE];
+}__attribute__((packed)) sunoem_cli_msg_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/*
+ * Command codes for the command_request field in each request.
+ */
+#define SUNOEM_CLI_CMD_OPEN 0 /* Open a new connection */
+#define SUNOEM_CLI_CMD_FORCE 1 /* Close any existing connection, then open */
+#define SUNOEM_CLI_CMD_CLOSE 2 /* Close the current connection */
+#define SUNOEM_CLI_CMD_POLL 3 /* Poll for new data to/from the server */
+#define SUNOEM_CLI_CMD_EOF 4 /* Poll, client is out of data */
+
+#define SUNOEM_CLI_MAX_RETRY 3 /* Maximum number of retries */
+
+#define SUNOEM_CLI_INVALID_VER_ERR "Invalid version"
+#define SUNOEM_CLI_BUSY_ERR "Busy"
+
+typedef enum
+{
+ C_CTL_B = 0x02, /* same as left arrow */
+ C_CTL_C = 0x03,
+ C_CTL_D = 0x04,
+ C_CTL_F = 0x06, /* same as right arrow */
+ C_CTL_N = 0x0E, /* same as down arrow */
+ C_CTL_P = 0x10, /* same as up arrow */
+ C_DEL = 0x7f
+} canon_char_t;
+
+static int
+sunoem_cli_unbufmode_start(FILE *f, struct termios *orig_ts)
+{
+ struct termios ts;
+ int rc;
+
+ if ((rc = tcgetattr(fileno(f), &ts))) {
+ return (rc);
+ }
+ *orig_ts = ts;
+ ts.c_lflag &= ~(ICANON | ECHO | ISIG);
+ ts.c_cc[VMIN] = 1;
+ if ((rc = tcsetattr(fileno(f), TCSAFLUSH, &ts))) {
+ return (rc);
+ }
+
+ return (0);
+}
+
+static int
+sunoem_cli_unbufmode_stop(FILE *f, struct termios *ts)
+{
+ int rc;
+
+ if ((rc = tcsetattr(fileno(f), TCSAFLUSH, ts))) {
+ return (rc);
+ }
+
+ return (0);
+}
+
+static int
+ipmi_sunoem_cli(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ sunoem_cli_msg_t cli_req;
+ sunoem_cli_msg_t *cli_rsp;
+ int arg_num = 0;
+ int arg_pos = 0;
+ time_t wait_time = 0;
+ int retries;
+ static uint8_t SunOemCliActingVersion = SUNOEM_CLI_VERSION;
+
+ unsigned short first_char = 0; /*first char on the line*/
+ struct termios orig_ts;
+ int error = 0;
+
+ time_t now = 0;
+ int delay = 0;
+
+ /* Prepare to open an SP shell session */
+ memset(&cli_req, 0, sizeof(cli_req));
+ cli_req.version = SunOemCliActingVersion;
+ cli_req.command_response = SUNOEM_CLI_CMD_OPEN;
+ if (argc > 0 && strcmp(argv[0], "force") == 0) {
+ cli_req.command_response = SUNOEM_CLI_CMD_FORCE;
+ argc--;
+ argv++;
+ }
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_CLI;
+ req.msg.data = (uint8_t *) &cli_req;
+ req.msg.data_len = SUNOEM_CLI_HEADER + 1;
+ retries = 0;
+ while (1) {
+ cli_req.version = SunOemCliActingVersion;
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM cli command failed");
+ return (-1);
+ }
+ cli_rsp = (sunoem_cli_msg_t *) rsp->data;
+ if ((cli_rsp->command_response != 0) || (rsp->ccode != 0)) {
+ if (strncmp(cli_rsp->buf, SUNOEM_CLI_INVALID_VER_ERR,
+ sizeof(SUNOEM_CLI_INVALID_VER_ERR) - 1) == 0
+ || strncmp(&(cli_rsp->buf[1]), SUNOEM_CLI_INVALID_VER_ERR,
+ sizeof(SUNOEM_CLI_INVALID_VER_ERR) - 1) == 0) {
+ if (SunOemCliActingVersion == SUNOEM_CLI_VERSION) {
+ /* Server doesn't support version SUNOEM_CLI_VERSION
+ Fall back to legacy version, and try again*/
+ SunOemCliActingVersion = SUNOEM_CLI_LEGACY_VERSION;
+ continue;
+ }
+ /* Server doesn't support legacy version either */
+ lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf);
+ return (-1);
+ } else if (strncmp(cli_rsp->buf, SUNOEM_CLI_BUSY_ERR,
+ sizeof(SUNOEM_CLI_BUSY_ERR) - 1) == 0) {
+ if (retries++ < SUNOEM_CLI_MAX_RETRY) {
+ lprintf(LOG_INFO, "Failed to connect: %s, retrying",
+ cli_rsp->buf);
+ sleep(2);
+ continue;
+ }
+ lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf);
+ return (-1);
+ } else {
+ lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf);
+ return (-1);
+ }
+ }
+ break;
+ }
+ if (SunOemCliActingVersion == SUNOEM_CLI_SEQNUM_VERSION) {
+ /*
+ * Bit 1 of seqnum is used as an alternating sequence number
+ * to allow a server that supports it to detect when a retry is being sent from the host IPMI driver.
+ * Typically when this occurs, the server's last response message would have been dropped.
+ * Once the server detects this condition, it will know that it should retry sending the response.
+ */
+ cli_req.seqnum ^= 0x1;
+ }
+ printf("Connected. Use ^D to exit.\n");
+ fflush(NULL);
+
+ /*
+ * Remember the handle provided in the response, and issue a
+ * series of "poll" commands to send and get data
+ */
+ memcpy(cli_req.handle, cli_rsp->handle, 4);
+ cli_req.command_response = SUNOEM_CLI_CMD_POLL;
+ /*
+ * If no arguments make input unbuffered and so interactive
+ */
+ if (argc == 0) {
+ if (sunoem_cli_unbufmode_start(stdin, &orig_ts)) {
+ lprintf(LOG_ERR, "Failed to set interactive mode: %s",
+ strerror(errno));
+ return (-1);
+ }
+ }
+ while (rsp->ccode == 0 && cli_rsp->command_response == 0) {
+ int rc = 0;
+ int count = 0;
+ cli_req.buf[0] = '\0';
+ if (argc == 0) {
+ /*
+ * Accept input from stdin. Use select so we don't hang if
+ * there's no input to read. Select timeout is 500 msec.
+ */
+ struct timeval tv = { 0, 500000 }; /* 500 msec */
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(0, &rfds);
+ rc = select(1, &rfds, NULL, NULL, &tv);
+ if (rc < 0) {
+ /* Select returned an error so close and exit */
+ printf("Broken pipe\n");
+ cli_req.command_response = SUNOEM_CLI_CMD_CLOSE;
+ } else if (rc > 0) {
+ /* Read data from stdin */
+ count = read(0, cli_req.buf, 1 /* sizeof (cli_req.buf) - 1 */);
+ /*
+ * If select said there was data but there was nothing to
+ * read. This implies user hit ^D.
+ * Also handle ^D input when pressed as first char at a new line.
+ */
+ if (count <= 0 || (first_char && cli_req.buf[0] == C_CTL_D)) {
+ cli_req.command_response = SUNOEM_CLI_CMD_EOF;
+ count = 0;
+ }
+ first_char = cli_req.buf[0] == '\n' || cli_req.buf[0] == '\r';
+ }
+ } else {
+ /*
+ * Get data from command line arguments
+ */
+ now = time(NULL);
+ if (now < wait_time) {
+ /* Do nothing; we're waiting */
+ } else if (arg_num >= argc) {
+ /* Last arg was sent. Set EOF */
+ cli_req.command_response = SUNOEM_CLI_CMD_EOF;
+ } else if (strncmp(argv[arg_num], "@wait=", 6) == 0) {
+ /* This is a wait command */
+ char *s = &argv[arg_num][6];
+ delay = 0;
+ if (*s != '\0') {
+ if (str2int(s, &delay)) {
+ delay = 0;
+ }
+ if (delay < 0) {
+ delay = 0;
+ }
+ }
+ wait_time = now + delay;
+ arg_num++;
+ } else {
+ /*
+ * Take data from args. It may be that the argument is larger
+ * than the request buffer can hold. So pull off BUF_SIZE
+ * number of characters at a time. When we've consumed the
+ * entire arg, append a newline and advance to the next arg.
+ */
+ int i;
+ char *s = argv[arg_num];
+ for (i = arg_pos;
+ s[i] != '\0' && count < (SUNOEM_CLI_BUF_SIZE - 2);
+ i++, count++) {
+ cli_req.buf[count] = s[i];
+ }
+ if (s[i] == '\0') {
+ /* Reached end of the arg string, so append a newline */
+ cli_req.buf[count++] = '\n';
+ /* Reset pos to 0 and advance to the next arg next time */
+ arg_pos = 0;
+ arg_num++;
+ } else {
+ /*
+ * Otherwise, there's still more characters in the arg
+ * to send, so remember where we left off
+ */
+ arg_pos = i;
+ }
+ }
+ }
+ /*
+ * Now send the clients's data (if any) and get data back from the
+ * server. Loop while the server is giving us data until we suck
+ * it dry.
+ */
+ do {
+ cli_req.buf[count++] = '\0'; /* Terminate the string */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = 0x19;
+ req.msg.data = (uint8_t *) &cli_req;
+ req.msg.data_len = SUNOEM_CLI_HEADER + count;
+ for (retries = 0; retries <= SUNOEM_CLI_MAX_RETRY; retries++) {
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Communication error.");
+ error = 1;
+ goto cleanup;
+ }
+ if (rsp->ccode == IPMI_CC_TIMEOUT) { /* Retry if timed out. */
+ if (retries == SUNOEM_CLI_MAX_RETRY) { /* If it's the last retry. */
+ lprintf(LOG_ERR, "Excessive timeout.");
+ error = 1;
+ goto cleanup;
+ }
+ continue;
+ }
+ break;
+ } /* for (retries = 0; retries <= SUNOEM_CLI_MAX_RETRY; retries++) */
+
+ if (SunOemCliActingVersion == SUNOEM_CLI_SEQNUM_VERSION) {
+ cli_req.seqnum ^= 0x1; /* Toggle sequence number after request is sent */
+ }
+
+ cli_rsp = (sunoem_cli_msg_t *) rsp->data;
+ /* Make sure response string is null terminated */
+ cli_rsp->buf[sizeof(cli_rsp->buf) - 1] = '\0';
+ printf("%s", cli_rsp->buf);
+ fflush(NULL); /* Flush partial lines to stdout */
+ count = 0; /* Don't re-send the client's data */
+ if (cli_req.command_response == SUNOEM_CLI_CMD_EOF
+ && cli_rsp->command_response != 0 && rsp->ccode == 0) {
+ cli_rsp->command_response = 1;
+ }
+ } while (cli_rsp->command_response == 0 && cli_rsp->buf[0] != '\0');
+ }
+
+cleanup:
+ /* Restore original input mode if cli was running interactively */
+ if (argc == 0) {
+ if (sunoem_cli_unbufmode_stop(stdin, &orig_ts)) {
+ lprintf(LOG_ERR, "Failed to restore interactive mode: %s",
+ strerror(errno));
+ return (-1);
+ }
+ }
+
+ return ((error == 0 && cli_rsp->command_response == SUNOEM_SUCCESS) ? 0 : -1);
+}
+#define ECHO_DATA_SIZE 64
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ uint16_t seq_num;
+ unsigned char data[ECHO_DATA_SIZE];
+}__attribute__((packed)) sunoem_echo_msg_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/*
+ * Send and receive X packets to the BMC. Each packet has a
+ * payload size of (sunoem_echo_msg_t) bytes. Each packet is tagged with a
+ * sequence number
+ */
+static int
+ipmi_sunoem_echo(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ sunoem_echo_msg_t echo_req;
+ sunoem_echo_msg_t *echo_rsp;
+ struct timeval start_time;
+ struct timeval end_time;
+
+ int rc = 0;
+ int received = 0;
+ int transmitted = 0;
+ int quiet_mode = 0;
+
+ uint16_t num, i, j;
+ uint32_t total_time, resp_time, min_time, max_time;
+
+ if (argc < 1) {
+ return (1);
+ }
+
+ if (argc == 2) {
+ if (*(argv[1]) == 'q') {
+ quiet_mode = 1;
+ } else {
+ lprintf(LOG_ERR, "Unknown option '%s' given.", argv[1]);
+ return (-1);
+ }
+ } else if (argc > 2) {
+ lprintf(LOG_ERR,
+ "Too many parameters given. See help for more information.");
+ return (-1);
+ }
+ /* The number of packets to send/receive */
+ if (str2ushort(argv[0], &num) != 0) {
+ lprintf(LOG_ERR,
+ "Given number of packets is either invalid or out of range.");
+ return (-1);
+ }
+
+ /* Fill in data packet */
+ for (i = 0; i < ECHO_DATA_SIZE; i++) {
+ if (i > UINT8_MAX)
+ break;
+
+ echo_req.data[i] = (uint8_t) i;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_ECHO;
+ req.msg.data = (uint8_t *) &echo_req;
+ req.msg.data_len = sizeof(sunoem_echo_msg_t);
+ echo_req.seq_num = i;
+ min_time = INT_MAX;
+ max_time = 0;
+ total_time = 0;
+ for (i = 0; i < num; i++) {
+ echo_req.seq_num = i;
+ transmitted++;
+ gettimeofday(&start_time, NULL);
+ rsp = intf->sendrecv(intf, &req);
+ gettimeofday(&end_time, NULL);
+ resp_time = ((end_time.tv_sec - start_time.tv_sec) * 1000)
+ + ((end_time.tv_usec - start_time.tv_usec) / 1000);
+ if ((rsp == NULL) || (rsp->ccode != 0)) {
+ lprintf(LOG_ERR, "Sun OEM echo command failed. Seq # %d",
+ echo_req.seq_num);
+ rc = (-2);
+ break;
+ }
+ echo_rsp = (sunoem_echo_msg_t *) rsp->data;
+
+ /* Test if sequence # is valid */
+ if (echo_rsp->seq_num != echo_req.seq_num) {
+ printf("Invalid Seq # Expecting %d Received %d\n", echo_req.seq_num,
+ echo_rsp->seq_num);
+ rc = (-2);
+ break;
+ }
+
+ /* Test if response length is valid */
+ if (rsp->session.msglen == req.msg.data_len) {
+ printf("Invalid payload size for seq # %d. "
+ "Expecting %d Received %d\n", echo_rsp->seq_num,
+ req.msg.data_len, rsp->session.msglen);
+ rc = (-2);
+ break;
+ }
+
+ /* Test if the data is valid */
+ for (j = 0; j < ECHO_DATA_SIZE; j++) {
+ if (echo_rsp->data[j] != j) {
+ printf("Corrupt data packet. Seq # %d Offset %d\n",
+ echo_rsp->seq_num, j);
+ break;
+ }
+ } /* for (j = 0; j < ECHO_DATA_SIZE; j++) */
+
+ /* If the for loop terminated early - data is corrupt */
+ if (j != ECHO_DATA_SIZE) {
+ rc = (-2);
+ break;
+ }
+
+ /* cumalative time */
+ total_time += resp_time;
+
+ /* min time */
+ if (resp_time < min_time) {
+ min_time = resp_time;
+ }
+
+ /* max time */
+ if (resp_time > max_time) {
+ max_time = resp_time;
+ }
+
+ received++;
+ if (!quiet_mode) {
+ printf("Receive %u Bytes - Seq. # %d time=%d ms\n",
+ sizeof(sunoem_echo_msg_t), echo_rsp->seq_num, resp_time);
+ }
+ } /* for (i = 0; i < num; i++) */
+ printf("%d packets transmitted, %d packets received\n", transmitted,
+ received);
+ if (received) {
+ printf("round-trip min/avg/max = %d/%d/%d ms\n", min_time,
+ total_time / received, max_time);
+ }
+
+ return (rc);
+} /* ipmi_sunoem_echo(...) */
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ unsigned char oem_record_ver_num;
+ unsigned char major;
+ unsigned char minor;
+ unsigned char update;
+ unsigned char micro;
+ char nano[10];
+ char revision[10];
+ char version[40];
+ /*
+ * When adding new fields (using the spare bytes),
+ * add it immediately after the spare field to
+ * ensure backward compatability.
+ *
+ * e.g. char version[40];
+ * unsigned char spare[11];
+ * int new_item;
+ * } sunoem_version_response_t;
+ */
+ unsigned char spare[15];
+}__attribute__((packed)) sunoem_version_response_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+typedef struct
+{
+ unsigned char major;
+ unsigned char minor;
+ unsigned char update;
+ unsigned char micro;
+} supported_version_t;
+
+static int
+ipmi_sunoem_getversion(struct ipmi_intf * intf,
+ sunoem_version_response_t **version_rsp)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_VERSION;
+ req.msg.data = NULL;
+ req.msg.data_len = 0;
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM Get SP Version Failed.");
+ return (-1);
+ }
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM Get SP Version Failed: %d", rsp->ccode);
+ return (-1);
+ }
+
+ *version_rsp = (sunoem_version_response_t *) rsp->data;
+
+ return (0);
+}
+
+static void
+ipmi_sunoem_print_required_version(const supported_version_t* supp_ver)
+{
+ lprintf(LOG_ERR, "Command is not supported by this version of ILOM,"
+ " required at least: %d.%d.%d.%d", supp_ver->major, supp_ver->minor,
+ supp_ver->update, supp_ver->micro);
+}
+
+/*
+ * Function checks current version result against required version.
+ * Returns:
+ * - negative value if current ILOM version is smaller than required or
+ * in case of error
+ * - positive value if current ILOM version is greater than required
+ * - 0 if there is an exact ILOM version match
+ */
+static int
+ipmi_sunoem_checkversion(struct ipmi_intf * intf, supported_version_t* supp_ver)
+{
+ sunoem_version_response_t *version_rsp;
+ int i = 1;
+
+ if (ipmi_sunoem_getversion(intf, &version_rsp)) {
+ lprintf(LOG_ERR, "Unable to get ILOM version");
+ return (-1);
+ }
+
+ if (version_rsp->major < supp_ver->major) return (-i);
+ if (version_rsp->major > supp_ver->major) return (i);
+ /*version_rsp->major == supp_ver->major*/
+ ++i;
+
+ if (version_rsp->minor < supp_ver->minor) return (-i);
+ if (version_rsp->minor > supp_ver->minor) return (i);
+ /*version_rsp->minor == supp_ver->minor*/
+ ++i;
+
+ if (version_rsp->update < supp_ver->update) return (-i);
+ if (version_rsp->update > supp_ver->update) return (i);
+ /*version_rsp->update == supp_ver->update*/
+ ++i;
+
+ if (version_rsp->micro < supp_ver->micro) return (-i);
+ if (version_rsp->micro > supp_ver->micro) return (i);
+ /*version_rsp->micro == supp_ver->micro*/
+
+ return (0);
+}
+
+/*
+ * Extract the SP version data including
+ * - major #
+ * - minor #
+ * - update #
+ * - micro #
+ * - nano #
+ * - Revision/Build #
+ */
+static int
+ipmi_sunoem_version(struct ipmi_intf * intf)
+{
+ sunoem_version_response_t *version_rsp;
+ int rc = ipmi_sunoem_getversion(intf, &version_rsp);
+
+ if (!rc) {
+ printf("Version: %s\n", version_rsp->version);
+ }
+
+ return (rc);
+}
+
+/*
+ * IPMI Max string length is 16 bytes
+ * define in usr/src/common/include/ami/IPMI_SDRRecord.h
+ */
+#define MAX_ID_STR_LEN 16
+#define MAX_SUNOEM_NAC_SIZE 64
+#define LUAPI_MAX_OBJ_PATH_LEN 256
+#define LUAPI_MAX_OBJ_VAL_LEN 1024
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ unsigned char seq_num;
+ char nac_name[MAX_SUNOEM_NAC_SIZE];
+}__attribute__((packed)) sunoem_nacname_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/*
+ * Retrieve the full NAC name of the IPMI target.
+ *
+ * The returned nac name may be larger than the payload size.
+ * In which case, it make take several request/payload to retrieve
+ * the entire full path name
+ *
+ * The initial seq_num is set to 0. If the return seq_num is incremented,
+ * only the 1st 72 bytes of the nac name is returned and the caller
+ * needs to get the next set of string data.
+ * If the returned seq_num is identical to the input seq_num, all data
+ * has been returned.
+ */
+static int
+ipmi_sunoem_nacname(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ sunoem_nacname_t nacname_req;
+ sunoem_nacname_t *nacname_rsp;
+ char full_nac_name[LUAPI_MAX_OBJ_PATH_LEN];
+
+ if (argc < 1) {
+ return (1);
+ }
+
+ if (strlen(argv[0]) > MAX_ID_STR_LEN) {
+ lprintf(LOG_ERR,
+ "Sun OEM nacname command failed: Max size on IPMI name");
+ return (-1);
+ }
+
+ nacname_req.seq_num = 0;
+ strcpy(nacname_req.nac_name, argv[0]);
+
+ full_nac_name[0] = '\0';
+ while (1) {
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_NACNAME;
+ req.msg.data = (uint8_t *) &nacname_req;
+ req.msg.data_len = sizeof(sunoem_nacname_t);
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM nacname command failed.");
+ return (-1);
+ }
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM nacname command failed: %d", rsp->ccode);
+ return (-1);
+ }
+
+ nacname_rsp = (sunoem_nacname_t *) rsp->data;
+ strncat(full_nac_name, nacname_rsp->nac_name, MAX_SUNOEM_NAC_SIZE);
+
+ /*
+ * break out of the loop if there is no more data
+ * In most cases, if not all, the NAC name fits into a
+ * single payload
+ */
+ if (nacname_req.seq_num == nacname_rsp->seq_num) {
+ break;
+ }
+
+ /* Get the next seq of string bytes */
+ nacname_req.seq_num = nacname_rsp->seq_num;
+
+ /* Check if we exceeded the size of the full nac name */
+ if ((nacname_req.seq_num * MAX_SUNOEM_NAC_SIZE) > LUAPI_MAX_OBJ_PATH_LEN) {
+ lprintf(LOG_ERR,
+ "Sun OEM nacname command failed: invalid path length");
+ return (-1);
+ }
+ }
+
+ printf("NAC Name: %s\n", full_nac_name);
+ return (0);
+}
+
+/* Constants used by ipmi_sunoem_getval */
+#define MAX_SUNOEM_VAL_PAYLOAD 79
+#define MAX_SUNOEM_VAL_COMPACT_PAYLOAD 56
+
+/*
+ * SUNOEM GET/SET LUAPI Commands
+ *
+ * SUNOEM_REQ_VAL - Request LUAPI Property Value
+ * SUNOEM_GET_VAL - Return the value from SUNOEM_REQ_VAL
+ * SUNOEM_SET_VAL - Set the LUAPI Property value
+ * SUNOEM_GET_STATUS - Return the Status from SUNOEM_SET_VAL
+ */
+#define SUNOEM_REQ_VAL 1
+#define SUNOEM_GET_VAL 2
+#define SUNOEM_SET_VAL 3
+#define SUNOEM_GET_STATUS 4
+
+/* Status Code */
+#define SUNOEM_REQ_RECV 1
+#define SUNOEM_REQ_FAILED 2
+#define SUNOEM_DATA_READY 3
+#define SUNOEM_DATA_NOT_READY 4
+#define SUNOEM_DATA_NOT_FOUND 5
+#define GETVAL_MAX_RETRIES 5
+
+/* Parameter type Codes */
+#define SUNOEM_LUAPI_TARGET 0
+#define SUNOEM_LUAPI_VALUE 1
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ unsigned char cmd_code;
+ unsigned char luapi_value[MAX_SUNOEM_VAL_PAYLOAD];
+}__attribute__((packed)) sunoem_getval_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/*
+ * REQUEST PAYLOAD
+ *
+ * cmd_code - SUNOEM GET/SET LUAPI Cmds - see above
+ * param_type: 0: luapi_data contains the luapi property name
+ * 1: luapi_data contains the luapi value
+ * luapi_data: Either luapi property name or value
+ * tid: Transaction ID. If 0. This is the initial request for the
+ * param_type. If tid > 0, this luapi_data string is a concatenation
+ * of the previous request. Handle cases where the LUAPI target name
+ * or value is > MAX_SUNOEM_VAL_COMPACT_PAYLOAD
+ * eof: If non zero, this is the last payload for the request
+ */
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ unsigned char cmd_code;
+ unsigned char param_type;
+ unsigned char tid;
+ unsigned char eof;
+ char luapi_data[MAX_SUNOEM_VAL_COMPACT_PAYLOAD];
+}__attribute__((packed)) sunoem_setval_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/*
+ * RESPONSE PAYLOAD
+ *
+ * status_code - see above for code definitions
+ * tid - transaction ID - assigned ny the ILOM stack
+ */
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ unsigned char status_code;
+ unsigned char tid;
+}__attribute__((packed)) sunoem_setval_resp_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+/*
+ * Return the ILOM target property value
+ */
+static int
+ipmi_sunoem_getval(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ sunoem_getval_t getval_req;
+ sunoem_getval_t *getval_rsp;
+ int i;
+
+ const char* sp_path = "/SP";
+ supported_version_t supp_ver = { 3, 2, 0, 0 };
+
+ if (argc < 1) {
+ return (1);
+ }
+
+ if (strlen(argv[0]) > MAX_SUNOEM_VAL_PAYLOAD) {
+ lprintf(LOG_ERR,
+ "Sun OEM get value command failed: Max size on IPMI name");
+ return (-1);
+ }
+
+ if ((ipmi_sunoem_checkversion(intf, &supp_ver) < 0)
+ && (!strncmp(argv[0], sp_path, strlen(sp_path)))) {
+ argv[0][1] = 'X'; /*replace SP by X to gain access to hidden properties*/
+ memmove(&argv[0][2], &argv[0][3], strlen(argv[0]) - 2);
+ }
+
+ /*
+ * Setup the initial request to fetch the data.
+ * Upon function return, the next cmd (SUNOEM_GET_VAL)
+ * can be requested.
+ */
+ memset(&getval_req, 0, sizeof(getval_req));
+ strncpy((char*) getval_req.luapi_value, argv[0], MAX_SUNOEM_VAL_PAYLOAD);
+ getval_req.cmd_code = SUNOEM_REQ_VAL;
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_GETVAL;
+ req.msg.data = (uint8_t *) &getval_req;
+ req.msg.data_len = sizeof(sunoem_getval_t);
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM getval1 command failed.");
+ return (-1);
+ }
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM getval1 command failed: %d", rsp->ccode);
+ return (-1);
+ }
+
+ /*
+ * Fetch the data value - if it is not ready,
+ * retry the request up to GETVAL_MAX_RETRIES
+ */
+ for (i = 0; i < GETVAL_MAX_RETRIES; i++) {
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_GETVAL;
+ getval_req.cmd_code = SUNOEM_GET_VAL;
+ req.msg.data = (uint8_t *) &getval_req;
+ req.msg.data_len = sizeof(sunoem_getval_t);
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM getval2 command failed.");
+ return (-1);
+ }
+
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM getval2 command failed: %d", rsp->ccode);
+ return (-1);
+ }
+
+ getval_rsp = (sunoem_getval_t *) rsp->data;
+
+ if (getval_rsp->cmd_code == SUNOEM_DATA_READY) {
+ printf("Target Value: %s\n", getval_rsp->luapi_value);
+ return (0);
+ } else if (getval_rsp->cmd_code == SUNOEM_DATA_NOT_FOUND) {
+ lprintf(LOG_ERR, "Target: %s not found", getval_req.luapi_value);
+ return (-1);
+ }
+
+ sleep(1);
+ }
+
+ lprintf(LOG_ERR, "Unable to retrieve target value.");
+ return (-1);
+}
+
+static int
+send_luapi_prop_name(struct ipmi_intf * intf, int len, char *prop_name,
+ unsigned char *tid_num)
+{
+ int i = 0;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ sunoem_setval_t setval_req;
+ sunoem_setval_resp_t *setval_rsp;
+
+ *tid_num = 0;
+ while (i < len) {
+ /*
+ * Setup the request,
+ * Upon function return, the next cmd (SUNOEM_SET_VAL)
+ * can be requested.
+ */
+ memset(&req, 0, sizeof(req));
+ memset(&setval_req, 0, sizeof(sunoem_setval_t));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_SETVAL;
+ setval_req.cmd_code = SUNOEM_SET_VAL;
+ setval_req.param_type = SUNOEM_LUAPI_TARGET;
+ setval_req.tid = *tid_num;
+ setval_req.eof = 0;
+ /*
+ * If the property name is > payload, only copy
+ * the payload size and increment the string offset (i)
+ * for the next payload
+ */
+ if (strlen(&(prop_name[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) {
+ strncpy(setval_req.luapi_data, &(prop_name[i]),
+ MAX_SUNOEM_VAL_COMPACT_PAYLOAD);
+ } else {
+ strncpy(setval_req.luapi_data, &(prop_name[i]),
+ strlen(&(prop_name[i])));
+ }
+ req.msg.data = (uint8_t *) &setval_req;
+ req.msg.data_len = sizeof(sunoem_setval_t);
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM setval prop name: response is NULL");
+ return (-1);
+ }
+
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM setval prop name: request failed: %d",
+ rsp->ccode);
+ return (-1);
+ }
+
+ setval_rsp = (sunoem_setval_resp_t *) rsp->data;
+
+ /*
+ * If the return code is other than data received, the
+ * request failed
+ */
+ if (setval_rsp->status_code != SUNOEM_REQ_RECV) {
+ lprintf(LOG_ERR,
+ "Sun OEM setval prop name: invalid status code: %d",
+ setval_rsp->status_code);
+ return (-1);
+ }
+ /* Use the tid returned by ILOM */
+ *tid_num = setval_rsp->tid;
+ /* Increment the string offset */
+ i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD;
+ }
+
+ return (0);
+}
+
+static int
+send_luapi_prop_value(struct ipmi_intf * intf, int len, char *prop_value,
+ unsigned char tid_num)
+{
+ int i = 0;
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ sunoem_setval_t setval_req;
+ sunoem_setval_resp_t *setval_rsp;
+
+ while (i < len) {
+ /*
+ * Setup the request,
+ * Upon function return, the next cmd (SUNOEM_GET_VAL)
+ * can be requested.
+ */
+ memset(&req, 0, sizeof(req));
+ memset(&setval_req, 0, sizeof(sunoem_setval_t));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_SETVAL;
+ setval_req.cmd_code = SUNOEM_SET_VAL;
+ setval_req.param_type = SUNOEM_LUAPI_VALUE;
+ setval_req.tid = tid_num;
+ /*
+ * If the property name is > payload, only copy the
+ * the payload size and increment the string offset
+ * for the next payload
+ */
+ if (strlen(&(prop_value[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) {
+ strncpy(setval_req.luapi_data, &(prop_value[i]),
+ MAX_SUNOEM_VAL_COMPACT_PAYLOAD);
+ } else {
+ /* Captured the entire string, mark this as the last payload */
+ strncpy(setval_req.luapi_data, &(prop_value[i]),
+ strlen(&(prop_value[i])));
+ setval_req.eof = 1;
+ }
+ req.msg.data = (uint8_t *) &setval_req;
+ req.msg.data_len = sizeof(sunoem_setval_t);
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM setval prop value: response is NULL");
+ return (-1);
+ }
+
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM setval prop value: request failed: %d",
+ rsp->ccode);
+ return (-1);
+ }
+
+ setval_rsp = (sunoem_setval_resp_t *) rsp->data;
+
+ /*
+ * If the return code is other than data received, the
+ * request failed
+ */
+ if (setval_rsp->status_code != SUNOEM_REQ_RECV) {
+ lprintf(LOG_ERR,
+ "Sun OEM setval prop value: invalid status code: %d",
+ setval_rsp->status_code);
+ return (-1);
+ }
+
+ /* Increment the string offset */
+ i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD;
+ }
+ return (0);
+}
+
+static int
+ipmi_sunoem_setval(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ sunoem_setval_t setval_req;
+ sunoem_setval_resp_t *setval_rsp;
+ int prop_len;
+ int value_len;
+ int i;
+ unsigned char tid_num;
+ int retries;
+
+ prop_len = strlen(argv[0]);
+ value_len = strlen(argv[1]);
+ if (prop_len > LUAPI_MAX_OBJ_PATH_LEN) {
+ lprintf(LOG_ERR,
+ "Sun OEM set value command failed: Max size on property name");
+ return (-1);
+ }
+ if (value_len > LUAPI_MAX_OBJ_VAL_LEN) {
+ lprintf(LOG_ERR,
+ "Sun OEM set value command failed: Max size on property value");
+ return (-1);
+ }
+
+ /* Test if there is a timeout specified */
+ if (argc == 3) {
+ if ((str2int(argv[2], &retries) != 0) || retries < 0) {
+ lprintf(LOG_ERR,
+ "Invalid input given or out of range for time-out parameter.");
+ return (-1);
+ }
+ } else {
+ retries = GETVAL_MAX_RETRIES;
+ }
+
+ /* Send the property name 1st */
+ if (send_luapi_prop_name(intf, prop_len, argv[0], &tid_num) != 0) {
+ /* return if there is an error */
+ return (-1);
+ }
+
+ if (send_luapi_prop_value(intf, value_len, argv[1], tid_num) != 0) {
+ /* return if there is an error */
+ return (-1);
+ }
+
+ /*
+ * Get The status of the command.
+ * if it is not ready, retry the request up to
+ * GETVAL_MAX_RETRIES
+ */
+ for (i = 0; i < retries; i++) {
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_SETVAL;
+ setval_req.cmd_code = SUNOEM_GET_STATUS;
+ setval_req.tid = tid_num;
+ req.msg.data = (uint8_t *) &setval_req;
+ req.msg.data_len = sizeof(sunoem_setval_t);
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM setval command failed.");
+ return (-1);
+ }
+
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM setval command failed: %d", rsp->ccode);
+ return (-1);
+ }
+
+ setval_rsp = (sunoem_setval_resp_t *) rsp->data;
+
+ if (setval_rsp->status_code == SUNOEM_DATA_READY) {
+ printf("Sun OEM setval command successful.\n");
+ return (0);
+ } else if (setval_rsp->status_code != SUNOEM_DATA_NOT_READY) {
+ lprintf(LOG_ERR, "Sun OEM setval command failed.");
+ return (-1);
+ }
+
+ sleep(1);
+ }
+ /* If we reached here, retries exceeded */
+ lprintf(LOG_ERR, "Sun OEM setval command failed: Command Timed Out");
+
+ return (-1);
+}
+
+#define MAX_FILE_DATA_SIZE 1024
+#define MAX_FILEID_LEN 16
+#define CORE_TUNNEL_SUBCMD_GET_FILE 11
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ unsigned char cmd_code;
+ unsigned char file_id[MAX_FILEID_LEN];
+ unsigned int block_num;
+}__attribute__((packed)) getfile_req_t;
+
+typedef struct
+{
+ unsigned int block_num;
+ unsigned int data_size;
+ unsigned char eof;
+ unsigned char data[MAX_FILE_DATA_SIZE];
+}__attribute__((packed)) getfile_rsp_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+static int
+ipmi_sunoem_getfile(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ getfile_req_t getfile_req;
+ getfile_rsp_t *getfile_rsp;
+ int block_num = 0;
+ int nbo_blk_num; /* Network Byte Order Block Num */
+ FILE *fp;
+ unsigned data_size;
+ supported_version_t supp_ver = IPMI_SUNOEM_GETFILE_VERSION;
+
+ if (argc < 1) {
+ return (-1);
+ }
+
+ /*check if command is supported by this version of ilom*/
+ if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) {
+ ipmi_sunoem_print_required_version(&supp_ver);
+ return (-1);
+ }
+
+ /*
+ * File ID is < MAX_FILEID_LEN
+ * Save 1 byte for null Terminated string
+ */
+ if (strlen(argv[0]) >= MAX_FILE_DATA_SIZE) {
+ lprintf(LOG_ERR, "File ID >= %d characters", MAX_FILEID_LEN);
+ return (-1);
+ }
+
+ memset(&getfile_req, 0, sizeof(getfile_req));
+ strncpy((char*) getfile_req.file_id, argv[0], MAX_FILEID_LEN - 1);
+
+ /* Create the destination file */
+ fp = ipmi_open_file_write(argv[1]);
+ if (fp == NULL) {
+ lprintf(LOG_ERR, "Unable to open file: %s", argv[1]);
+ return (-1);
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL;
+ req.msg.data = (uint8_t *) &getfile_req;
+ req.msg.data_len = sizeof(getfile_req_t);
+ getfile_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_FILE;
+
+ do {
+
+ nbo_blk_num = htonl(block_num);
+ /* Block Num must be in network byte order */
+ memcpy(&(getfile_req.block_num), &nbo_blk_num,
+ sizeof(getfile_req.block_num));
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM getfile command failed.");
+ fclose(fp);
+ return (-1);
+ }
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM getfile command failed: %d", rsp->ccode);
+ fclose(fp);
+ return (-1);
+ }
+
+ getfile_rsp = (getfile_rsp_t *) rsp->data;
+
+ memcpy(&data_size, &(getfile_rsp->data_size),
+ sizeof(getfile_rsp->data_size));
+ data_size = ntohl(data_size);
+
+ if (data_size > MAX_FILE_DATA_SIZE) {
+ lprintf(LOG_ERR, "Sun OEM getfile invalid data size: %d",
+ data_size);
+ fclose(fp);
+ return (-1);
+ }
+
+ /* Check if Block Num matches */
+ if (memcmp(&(getfile_req.block_num), &(getfile_rsp->block_num),
+ sizeof(getfile_req.block_num)) != 0) {
+ lprintf(LOG_ERR, "Sun OEM getfile Incorrect Block Num Returned");
+ lprintf(LOG_ERR, "Expecting: %x Received: %x",
+ getfile_req.block_num, getfile_rsp->block_num);
+ fclose(fp);
+ return (-1);
+ }
+
+ if (fwrite(getfile_rsp->data, 1, data_size, fp) != data_size) {
+ lprintf(LOG_ERR, "Sun OEM getfile write failed: %d", rsp->ccode);
+ fclose(fp);
+ return (-1);
+ }
+
+ block_num++;
+ } while (getfile_rsp->eof == 0);
+
+ fclose(fp);
+
+ return (0);
+}
+
+/*
+ * Query BMC for capability/behavior.
+ */
+
+#define CORE_TUNNEL_SUBCMD_GET_BEHAVIOR 15
+#define SUNOEM_BEHAVIORID_SIZE 32
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(push, 1)
+#endif
+typedef struct
+{
+ unsigned char cmd_code;
+ unsigned char behavior_id[SUNOEM_BEHAVIORID_SIZE];
+}__attribute__((packed)) getbehavior_req_t;
+
+typedef struct
+{
+ unsigned char enabled;
+}__attribute__((packed)) getbehavior_rsp_t;
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(pop)
+#endif
+
+static int
+ipmi_sunoem_getbehavior(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rq req;
+ struct ipmi_rs *rsp;
+ getbehavior_req_t getbehavior_req;
+ getbehavior_rsp_t *getbehavior_rsp;
+ supported_version_t supp_ver = IPMI_SUNOEM_GETBEHAVIOR_VERSION;
+
+ if (argc < 1) {
+ return (-1);
+ }
+
+ /*check if command is supported by this version of ilom*/
+ if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) {
+ ipmi_sunoem_print_required_version(&supp_ver);
+ return (-1);
+ }
+
+ /*
+ * Behavior ID is < SUNOEM_BEHAVIORID_SIZE.
+ * Save 1 byte for null terminated string
+ */
+ if (strlen(argv[0]) >= SUNOEM_BEHAVIORID_SIZE) {
+ lprintf(LOG_ERR, "Behavior ID >= %d characters",
+ SUNOEM_BEHAVIORID_SIZE);
+ return (-1);
+ }
+
+ memset(&getbehavior_req, 0, sizeof(getbehavior_req));
+ strncpy(getbehavior_req.behavior_id, argv[0], SUNOEM_BEHAVIORID_SIZE - 1);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_SUNOEM;
+ req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL;
+ req.msg.data = (uint8_t *) &getbehavior_req;
+ req.msg.data_len = sizeof(getbehavior_req_t);
+ getbehavior_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_BEHAVIOR;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Sun OEM getbehavior command failed.");
+ return (-1);
+ }
+
+ if (rsp->ccode != 0) {
+ lprintf(LOG_ERR, "Sun OEM getbehavior command failed: %d", rsp->ccode);
+ return (-1);
+ }
+
+ getbehavior_rsp = (getbehavior_rsp_t *) rsp->data;
+ printf("ILOM behavior %s %s enabled\n", getbehavior_req.behavior_id,
+ getbehavior_rsp->enabled ? "is" : "is not");
+
+ return (0);
+}
+
+int
+ipmi_sunoem_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int rc = 0;
+
+ if (argc == 0 || strcmp(argv[0], "help") == 0) {
+ ipmi_sunoem_usage();
+ return (0);
+ } /* if (argc == 0 || strcmp(argv[0], "help") == 0) */
+
+ if (strcmp(argv[0], "cli") == 0) {
+ rc = ipmi_sunoem_cli(intf, argc - 1, &argv[1]);
+ } else if ((strcmp(argv[0], "led") == 0) || (strcmp(argv[0], "sbled") == 0)) {
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+
+ if (strcmp(argv[1], "get") == 0) {
+ if (argc < 3) {
+ char * arg[] = { "all" };
+ rc = ipmi_sunoem_led_get(intf, 1, arg);
+ } else {
+ rc = ipmi_sunoem_led_get(intf, argc - 2, &(argv[2]));
+ }
+ } else if (strcmp(argv[1], "set") == 0) {
+ if (argc < 4) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_led_set(intf, argc - 2, &(argv[2]));
+ } else {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ } else if (strcmp(argv[0], "sshkey") == 0) {
+ uint8_t uid = 0;
+ if (argc < 3) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = str2uchar(argv[2], &uid);
+ if (rc == 0) {
+ /* conversion should be OK. */
+ } else if (rc == 2) {
+ lprintf(LOG_NOTICE, "Invalid interval given.");
+ return (-1);
+ } else {
+ /* defaults to rc = 3 */
+ lprintf(LOG_NOTICE, "Given interval is too big.");
+ return (-1);
+ }
+
+ if (strcmp(argv[1], "del") == 0) {
+ /* number of arguments, three, is already checked at this point */
+ rc = ipmi_sunoem_sshkey_del(intf, uid);
+ } else if (strcmp(argv[1], "set") == 0) {
+ if (argc < 4) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_sshkey_set(intf, uid, argv[3]);
+ } else {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ } else if (strcmp(argv[0], "ping") == 0) {
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_echo(intf, argc - 1, &(argv[1]));
+ } else if (strcmp(argv[0], "version") == 0) {
+ rc = ipmi_sunoem_version(intf);
+ } else if (strcmp(argv[0], "nacname") == 0) {
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_nacname(intf, argc - 1, &(argv[1]));
+ } else if (strcmp(argv[0], "getval") == 0) {
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_getval(intf, argc - 1, &(argv[1]));
+ } else if (strcmp(argv[0], "setval") == 0) {
+ if (argc < 3) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_setval(intf, argc - 1, &(argv[1]));
+ } else if (strcmp(argv[0], "getfile") == 0) {
+ if (argc < 3) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_getfile(intf, argc - 1, &(argv[1]));
+ } else if (strcmp(argv[0], "getbehavior") == 0) {
+ if (argc < 2) {
+ ipmi_sunoem_usage();
+ return (-1);
+ }
+ rc = ipmi_sunoem_getbehavior(intf, argc - 1, &(argv[1]));
+ } else {
+ lprintf(LOG_ERR, "Invalid sunoem command: %s", argv[0]);
+ return (-1);
+ } /* if (strcmp(argv[0], "cli") == 0) */
+
+ return (rc);
+}
diff --git a/lib/ipmi_tsol.c b/lib/ipmi_tsol.c
new file mode 100644
index 0000000..94ea284
--- /dev/null
+++ b/lib/ipmi_tsol.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2005 Tyan Computer Corp. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <signal.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#if defined(HAVE_TERMIOS_H)
+# include <termios.h>
+#elif defined (HAVE_SYS_TERMIOS_H)
+# include <sys/termios.h>
+#endif
+
+#include <ipmitool/log.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_tsol.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/bswap.h>
+
+static struct timeval _start_keepalive;
+static struct termios _saved_tio;
+static struct winsize _saved_winsize;
+static int _in_raw_mode = 0;
+static int _altterm = 0;
+
+extern int verbose;
+
+static int
+ipmi_tsol_command(struct ipmi_intf * intf, char *recvip, int port, unsigned char cmd)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ unsigned char data[6];
+ unsigned ip1, ip2, ip3, ip4;
+
+ if (sscanf(recvip, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4) {
+ lprintf(LOG_ERR, "Invalid IP address: %s", recvip);
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(struct ipmi_rq));
+ req.msg.netfn = IPMI_NETFN_TSOL;
+ req.msg.cmd = cmd;
+ req.msg.data_len = 6;
+ req.msg.data = data;
+
+ memset(data, 0, sizeof(data));
+ data[0] = ip1;
+ data[1] = ip2;
+ data[2] = ip3;
+ data[3] = ip4;
+ data[4] = (port & 0xff00) >> 8;
+ data[5] = (port & 0xff);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to perform TSOL command");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Unable to perform TSOL command: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ipmi_tsol_start(struct ipmi_intf * intf, char *recvip, int port)
+{
+ return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_START);
+}
+
+static int
+ipmi_tsol_stop(struct ipmi_intf * intf, char *recvip, int port)
+{
+ return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_STOP);
+}
+
+static int
+ipmi_tsol_send_keystroke(struct ipmi_intf * intf, char *buff, int length)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ unsigned char data[16];
+ static unsigned char keyseq = 0;
+
+ memset(&req, 0, sizeof(struct ipmi_rq));
+ req.msg.netfn = IPMI_NETFN_TSOL;
+ req.msg.cmd = IPMI_TSOL_CMD_SENDKEY;
+ req.msg.data_len = length + 2;
+ req.msg.data = data;
+
+ memset(data, 0, sizeof(data));
+ data[0] = length + 1;
+ memcpy(data + 1, buff, length);
+ data[length + 1] = keyseq++;
+
+ rsp = intf->sendrecv(intf, &req);
+ if (verbose) {
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Unable to send keystroke");
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Unable to send keystroke: %s",
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+ }
+
+ return length;
+}
+
+static int
+tsol_keepalive(struct ipmi_intf * intf)
+{
+ struct timeval end;
+
+ gettimeofday(&end, 0);
+
+ if (end.tv_sec - _start_keepalive.tv_sec <= 30)
+ return 0;
+
+ intf->keepalive(intf);
+
+ gettimeofday(&_start_keepalive, 0);
+
+ return 0;
+}
+
+static void
+print_escape_seq(struct ipmi_intf *intf)
+{
+ lprintf(LOG_NOTICE,
+ " %c. - terminate connection\n"
+ " %c^Z - suspend ipmitool\n"
+ " %c^X - suspend ipmitool, but don't restore tty on restart\n"
+ " %c? - this message\n"
+ " %c%c - send the escape character by typing it twice\n"
+ " (Note that escapes are only recognized immediately after newline.)",
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char,
+ intf->session->sol_escape_char);
+}
+
+static int
+leave_raw_mode(void)
+{
+ if (!_in_raw_mode)
+ return -1;
+ else if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+ lperror(LOG_ERR, "tcsetattr(stdin)");
+ else if (tcsetattr(fileno(stdout), TCSADRAIN, &_saved_tio) == -1)
+ lperror(LOG_ERR, "tcsetattr(stdout)");
+ else
+ _in_raw_mode = 0;
+
+ return 0;
+}
+
+static int
+enter_raw_mode(void)
+{
+ struct termios tio;
+
+ if (tcgetattr(fileno(stdout), &_saved_tio) < 0) {
+ lperror(LOG_ERR, "tcgetattr failed");
+ return -1;
+ }
+
+ tio = _saved_tio;
+
+ if (_altterm) {
+ tio.c_iflag &= (ISTRIP | IGNBRK );
+ tio.c_cflag &= ~(CSIZE | PARENB | IXON | IXOFF | IXANY);
+ tio.c_cflag |= (CS8 |CREAD) | (IXON|IXOFF|IXANY);
+ tio.c_lflag &= 0;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ } else {
+ tio.c_iflag |= IGNPAR;
+ tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
+ tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
+ tio.c_oflag &= ~OPOST;
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 0;
+ }
+
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0)
+ lperror(LOG_ERR, "tcsetattr(stdin)");
+ else if (tcsetattr(fileno(stdout), TCSADRAIN, &tio) < 0)
+ lperror(LOG_ERR, "tcsetattr(stdout)");
+ else
+ _in_raw_mode = 1;
+
+ return 0;
+}
+
+static void
+suspend_self(int restore_tty)
+{
+ leave_raw_mode();
+
+ kill(getpid(), SIGTSTP);
+
+ if (restore_tty)
+ enter_raw_mode();
+}
+
+static int
+do_inbuf_actions(struct ipmi_intf *intf, char *in_buff, int len)
+{
+ static int in_esc = 0;
+ static int last_was_cr = 1;
+ int i;
+
+ for(i = 0; i < len ;) {
+ if (!in_esc) {
+ if (last_was_cr &&
+ (in_buff[i] == intf->session->sol_escape_char)) {
+ in_esc = 1;
+ memmove(in_buff, in_buff + 1, len - i - 1);
+ len--;
+ continue;
+ }
+ }
+ if (in_esc) {
+ if (in_buff[i] == intf->session->sol_escape_char) {
+ in_esc = 0;
+ i++;
+ continue;
+ }
+
+ switch (in_buff[i]) {
+ case '.':
+ printf("%c. [terminated ipmitool]\n",
+ intf->session->sol_escape_char);
+ return -1;
+
+ case 'Z' - 64:
+ printf("%c^Z [suspend ipmitool]\n",
+ intf->session->sol_escape_char);
+ suspend_self(1); /* Restore tty back to raw */
+ break;
+
+ case 'X' - 64:
+ printf("%c^X [suspend ipmitool]\n",
+ intf->session->sol_escape_char);
+ suspend_self(0); /* Don't restore to raw mode */
+ break;
+
+ case '?':
+ printf("%c? [ipmitool help]\n",
+ intf->session->sol_escape_char);
+ print_escape_seq(intf);
+ break;
+ }
+
+ memmove(in_buff, in_buff + 1, len - i - 1);
+ len--;
+ in_esc = 0;
+
+ continue;
+ }
+
+ last_was_cr = (in_buff[i] == '\r' || in_buff[i] == '\n');
+
+ i++;
+ }
+
+ return len;
+}
+
+
+static void
+do_terminal_cleanup(void)
+{
+ if (_saved_winsize.ws_row > 0 && _saved_winsize.ws_col > 0)
+ ioctl(fileno(stdout), TIOCSWINSZ, &_saved_winsize);
+
+ leave_raw_mode();
+
+ if (errno)
+ lprintf(LOG_ERR, "Exiting due to error %d -> %s",
+ errno, strerror(errno));
+}
+
+static void
+set_terminal_size(int rows, int cols)
+{
+ struct winsize winsize;
+
+ if (rows <= 0 || cols <= 0)
+ return;
+
+ /* save initial winsize */
+ ioctl(fileno(stdout), TIOCGWINSZ, &_saved_winsize);
+
+ /* set new winsize */
+ winsize.ws_row = rows;
+ winsize.ws_col = cols;
+ ioctl(fileno(stdout), TIOCSWINSZ, &winsize);
+}
+
+static void
+print_tsol_usage(void)
+{
+ struct winsize winsize;
+
+ lprintf(LOG_NOTICE, "Usage: tsol [recvip] [port=NUM] [ro|rw] [rows=NUM] [cols=NUM] [altterm]");
+ lprintf(LOG_NOTICE, " recvip Receiver IP Address [default=local]");
+ lprintf(LOG_NOTICE, " port=NUM Receiver UDP Port [default=%d]",
+ IPMI_TSOL_DEF_PORT);
+ lprintf(LOG_NOTICE, " ro|rw Set Read-Only or Read-Write [default=rw]");
+
+ ioctl(fileno(stdout), TIOCGWINSZ, &winsize);
+ lprintf(LOG_NOTICE, " rows=NUM Set terminal rows [default=%d]",
+ winsize.ws_row);
+ lprintf(LOG_NOTICE, " cols=NUM Set terminal columns [default=%d]",
+ winsize.ws_col);
+
+ lprintf(LOG_NOTICE, " altterm Alternate terminal setup [default=off]");
+}
+
+int
+ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ struct pollfd fds_wait[3], fds_data_wait[3], *fds;
+ struct sockaddr_in sin, myaddr, *sa_in;
+ socklen_t mylen;
+ char *recvip = NULL;
+ char out_buff[IPMI_BUF_SIZE * 8], in_buff[IPMI_BUF_SIZE];
+ char buff[IPMI_BUF_SIZE + 4];
+ int fd_socket, result, i;
+ int out_buff_fill, in_buff_fill;
+ int ip1, ip2, ip3, ip4;
+ int read_only = 0, rows = 0, cols = 0;
+ int port = IPMI_TSOL_DEF_PORT;
+
+ if (strlen(intf->name) < 3 || strncmp(intf->name, "lan", 3) != 0) {
+ lprintf(LOG_ERR, "Error: Tyan SOL is only available over lan interface");
+ return -1;
+ }
+
+ for (i = 0; i<argc; i++) {
+ if (sscanf(argv[i], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4) {
+ /* not free'd ...*/
+ /* recvip = strdup(argv[i]); */
+ recvip = argv[i];
+ }
+ else if (sscanf(argv[i], "port=%d", &ip1) == 1)
+ port = ip1;
+ else if (sscanf(argv[i], "rows=%d", &ip1) == 1)
+ rows = ip1;
+ else if (sscanf(argv[i], "cols=%d", &ip1) == 1)
+ cols = ip1;
+ else if (strlen(argv[i]) == 2 && strncmp(argv[i], "ro", 2) == 0)
+ read_only = 1;
+ else if (strlen(argv[i]) == 2 && strncmp(argv[i], "rw", 2) == 0)
+ read_only = 0;
+ else if (strlen(argv[i]) == 7 && strncmp(argv[i], "altterm", 7) == 0)
+ _altterm = 1;
+ else if (strlen(argv[i]) == 4 && strncmp(argv[i], "help", 4) == 0) {
+ print_tsol_usage();
+ return 0;
+ }
+ else {
+ print_tsol_usage();
+ return 0;
+ }
+ }
+
+ /* create udp socket to receive the packet */
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+
+ sa_in = (struct sockaddr_in *)&intf->session->addr;
+ result = inet_pton(AF_INET, (const char *)intf->session->hostname,
+ &sa_in->sin_addr);
+
+ if (result <= 0) {
+ struct hostent *host = gethostbyname((const char *)intf->session->hostname);
+ if (host == NULL ) {
+ lprintf(LOG_ERR, "Address lookup for %s failed",
+ intf->session->hostname);
+ return -1;
+ }
+ if (host->h_addrtype != AF_INET) {
+ lprintf(LOG_ERR,
+ "Address lookup for %s failed. Got %s, expected IPv4 address.",
+ intf->session->hostname,
+ (host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown");
+ return (-1);
+ }
+ sa_in->sin_family = host->h_addrtype;
+ memcpy(&sa_in->sin_addr, host->h_addr, host->h_length);
+ }
+
+ fd_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fd_socket < 0) {
+ lprintf(LOG_ERR, "Can't open port %d", port);
+ return -1;
+ }
+ if (-1 == bind(fd_socket, (struct sockaddr *)&sin, sizeof(sin))) {
+ lprintf(LOG_ERR, "Failed to bind socket.");
+ close(fd_socket);
+ return -1;
+ }
+
+ /*
+ * retrieve local IP address if not supplied on command line
+ */
+ if (recvip == NULL) {
+ result = intf->open(intf); /* must connect first */
+ if (result < 0) {
+ close(fd_socket);
+ return -1;
+ }
+
+ mylen = sizeof(myaddr);
+ if (getsockname(intf->fd, (struct sockaddr *)&myaddr, &mylen) < 0) {
+ lperror(LOG_ERR, "getsockname failed");
+ close(fd_socket);
+ return -1;
+ }
+
+ recvip = inet_ntoa(myaddr.sin_addr);
+ if (recvip == NULL) {
+ lprintf(LOG_ERR, "Unable to find local IP address");
+ close(fd_socket);
+ return -1;
+ }
+ }
+
+ printf("[Starting %sSOL with receiving address %s:%d]\n",
+ read_only ? "Read-only " : "", recvip, port);
+
+ set_terminal_size(rows, cols);
+ enter_raw_mode();
+
+ /*
+ * talk to smdc to start Console redirect - IP address and port as parameter
+ * ipmitool -I lan -H 192.168.168.227 -U Administrator raw 0x30 0x06 0xC0 0xA8 0xA8 0x78 0x1A 0x0A
+ */
+ result = ipmi_tsol_start(intf, recvip, port);
+ if (result < 0) {
+ lprintf(LOG_ERR, "Error starting SOL");
+ close(fd_socket);
+ return -1;
+ }
+
+ printf("[SOL Session operational. Use %c? for help]\n",
+ intf->session->sol_escape_char);
+
+ gettimeofday(&_start_keepalive, 0);
+
+ fds_wait[0].fd = fd_socket;
+ fds_wait[0].events = POLLIN;
+ fds_wait[0].revents = 0;
+ fds_wait[1].fd = fileno(stdin);
+ fds_wait[1].events = POLLIN;
+ fds_wait[1].revents = 0;
+ fds_wait[2].fd = -1;
+ fds_wait[2].events = 0;
+ fds_wait[2].revents = 0;
+
+ fds_data_wait[0].fd = fd_socket;
+ fds_data_wait[0].events = POLLIN | POLLOUT;
+ fds_data_wait[0].revents = 0;
+ fds_data_wait[1].fd = fileno(stdin);
+ fds_data_wait[1].events = POLLIN;
+ fds_data_wait[1].revents = 0;
+ fds_data_wait[2].fd = fileno(stdout);
+ fds_data_wait[2].events = POLLOUT;
+ fds_data_wait[2].revents = 0;
+
+ out_buff_fill = 0;
+ in_buff_fill = 0;
+ fds = fds_wait;
+
+ for (;;) {
+ result = poll(fds, 3, 15*1000);
+ if (result < 0)
+ break;
+
+ /* send keepalive packet */
+ tsol_keepalive(intf);
+
+ if ((fds[0].revents & POLLIN) && (sizeof(out_buff) > out_buff_fill)){
+ socklen_t sin_len = sizeof(sin);
+ result = recvfrom(fd_socket, buff, sizeof(out_buff) - out_buff_fill + 4, 0,
+ (struct sockaddr *)&sin, &sin_len);
+
+ /* read the data from udp socket, skip some bytes in the head */
+ if((result - 4) > 0 ){
+ int length = result - 4;
+#if 1
+ length = (unsigned char)buff[2] & 0xff;
+ length *= 256;
+ length += ((unsigned char)buff[3] & 0xff);
+ if ((length <= 0) || (length > (result - 4)))
+ length = result - 4;
+#endif
+ memcpy(out_buff + out_buff_fill, buff + 4, length);
+ out_buff_fill += length;
+ }
+ }
+ if ((fds[1].revents & POLLIN) && (sizeof(in_buff) > in_buff_fill)) {
+ result = read(fileno(stdin), in_buff + in_buff_fill,
+ sizeof(in_buff) - in_buff_fill); // read from keyboard
+ if (result > 0) {
+ int bytes;
+ bytes = do_inbuf_actions(intf, in_buff + in_buff_fill, result);
+ if(bytes < 0) {
+ result = ipmi_tsol_stop(intf, recvip, port);
+ do_terminal_cleanup();
+ return result;
+ }
+ if (read_only)
+ bytes = 0;
+ in_buff_fill += bytes;
+ }
+ }
+ if ((fds[2].revents & POLLOUT) && out_buff_fill) {
+ result = write(fileno(stdout), out_buff, out_buff_fill); // to screen
+ if (result > 0) {
+ out_buff_fill -= result;
+ if (out_buff_fill) {
+ memmove(out_buff, out_buff + result, out_buff_fill);
+ }
+ }
+ }
+ if ((fds[0].revents & POLLOUT) && in_buff_fill) {
+ /*
+ * translate key and send that to SMDC using IPMI
+ * ipmitool -I lan -H 192.168.168.227 -U Administrator raw 0x30 0x03 0x04 0x1B 0x5B 0x43
+ */
+ result = ipmi_tsol_send_keystroke(intf, in_buff, __min(in_buff_fill,14));
+ if (result > 0) {
+ gettimeofday(&_start_keepalive, 0);
+ in_buff_fill -= result;
+ if (in_buff_fill) {
+ memmove(in_buff, in_buff + result, in_buff_fill);
+ }
+ }
+ }
+ fds = (in_buff_fill || out_buff_fill )?
+ fds_data_wait : fds_wait;
+ }
+
+ return 0;
+}
diff --git a/lib/ipmi_user.c b/lib/ipmi_user.c
new file mode 100644
index 0000000..d7e5890
--- /dev/null
+++ b/lib/ipmi_user.c
@@ -0,0 +1,836 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/ipmi_user.h>
+#include <ipmitool/ipmi_constants.h>
+#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/bswap.h>
+
+
+extern int verbose;
+extern int csv_output;
+
+
+#define IPMI_PASSWORD_DISABLE_USER 0x00
+#define IPMI_PASSWORD_ENABLE_USER 0x01
+#define IPMI_PASSWORD_SET_PASSWORD 0x02
+#define IPMI_PASSWORD_TEST_PASSWORD 0x03
+
+/*
+ * ipmi_get_user_access
+ *
+ * param intf [in]
+ * param channel_number [in]
+ * param user_id [in]
+ * param user_access [out]
+ *
+ * return 0 on succes
+ * 1 on failure
+ */
+static int
+ipmi_get_user_access(
+ struct ipmi_intf *intf,
+ uint8_t channel_number,
+ uint8_t user_id,
+ struct user_access_rsp *user_access)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[2];
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */
+ req.msg.cmd = IPMI_GET_USER_ACCESS; /* 0x44 */
+ req.msg.data = msg_data;
+ req.msg.data_len = 2;
+
+
+ /* The channel number will remain constant throughout this function */
+ msg_data[0] = channel_number;
+ msg_data[1] = user_id;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get User Access command failed "
+ "(channel %d, user %d)", channel_number, user_id);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Get User Access command failed "
+ "(channel %d, user %d): %s", channel_number, user_id,
+ val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(user_access,
+ rsp->data,
+ sizeof(struct user_access_rsp));
+
+ return 0;
+}
+
+
+
+/*
+ * ipmi_get_user_name
+ *
+ * param intf [in]
+ * param channel_number [in]
+ * param user_id [in]
+ * param user_name [out]
+ *
+ * return 0 on succes
+ * 1 on failure
+ */
+static int
+ipmi_get_user_name(
+ struct ipmi_intf *intf,
+ uint8_t user_id,
+ char *user_name)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[1];
+
+ memset(user_name, 0, 17);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */
+ req.msg.cmd = IPMI_GET_USER_NAME; /* 0x45 */
+ req.msg.data = msg_data;
+ req.msg.data_len = 1;
+
+ msg_data[0] = user_id;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Get User Name command failed (user %d)",
+ user_id);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ if (rsp->ccode == 0xcc)
+ return 0;
+ lprintf(LOG_ERR, "Get User Name command failed (user %d): %s",
+ user_id, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ memcpy(user_name, rsp->data, 16);
+
+ return 0;
+}
+
+
+
+
+static void
+dump_user_access(
+ uint8_t user_id,
+ const char * user_name,
+ struct user_access_rsp * user_access)
+{
+ static int printed_header = 0;
+
+ if (! printed_header)
+ {
+ printf("ID Name Callin Link Auth IPMI Msg "
+ "Channel Priv Limit\n");
+ printed_header = 1;
+ }
+
+ printf("%-4d%-17s%-8s%-11s%-11s%-s\n",
+ user_id,
+ user_name,
+ user_access->no_callin_access? "false": "true ",
+ user_access->link_auth_access? "true ": "false",
+ user_access->ipmi_messaging_access? "true ": "false",
+ val2str(user_access->channel_privilege_limit,
+ ipmi_privlvl_vals));
+}
+
+
+
+static void
+dump_user_access_csv(
+ uint8_t user_id,
+ const char *user_name,
+ struct user_access_rsp *user_access)
+{
+ printf("%d,%s,%s,%s,%s,%s\n",
+ user_id,
+ user_name,
+ user_access->no_callin_access? "false": "true",
+ user_access->link_auth_access? "true": "false",
+ user_access->ipmi_messaging_access? "true": "false",
+ val2str(user_access->channel_privilege_limit,
+ ipmi_privlvl_vals));
+}
+
+static int
+ipmi_print_user_list(
+ struct ipmi_intf *intf,
+ uint8_t channel_number)
+{
+ /* This is where you were! */
+ char user_name[17];
+ struct user_access_rsp user_access;
+ uint8_t current_user_id = 1;
+
+
+ do
+ {
+ if (ipmi_get_user_access(intf,
+ channel_number,
+ current_user_id,
+ &user_access))
+ return -1;
+
+
+ if (ipmi_get_user_name(intf,
+ current_user_id,
+ user_name))
+ return -1;
+
+ if ((current_user_id == 0) ||
+ user_access.link_auth_access ||
+ user_access.ipmi_messaging_access ||
+ strcmp("", user_name))
+ {
+ if (csv_output)
+ dump_user_access_csv(current_user_id,
+ user_name, &user_access);
+ else
+ dump_user_access(current_user_id,
+ user_name,
+ &user_access);
+ }
+
+
+ ++current_user_id;
+ } while((current_user_id <= user_access.maximum_ids) &&
+ (current_user_id <= IPMI_UID_MAX)); /* Absolute maximum allowed by spec */
+
+
+ return 0;
+}
+
+
+
+static int
+ipmi_print_user_summary(
+ struct ipmi_intf * intf,
+ uint8_t channel_number)
+{
+ struct user_access_rsp user_access;
+
+ if (ipmi_get_user_access(intf,
+ channel_number,
+ 1,
+ &user_access))
+ return -1;
+
+ if (csv_output)
+ {
+ printf("%d,%d,%d\n",
+ user_access.maximum_ids,
+ user_access.enabled_user_count,
+ user_access.fixed_name_count);
+ }
+ else
+ {
+ printf("Maximum IDs : %d\n",
+ user_access.maximum_ids);
+ printf("Enabled User Count : %d\n",
+ user_access.enabled_user_count);
+ printf("Fixed Name Count : %d\n",
+ user_access.fixed_name_count);
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * ipmi_user_set_username
+ */
+static int
+ipmi_user_set_username(
+ struct ipmi_intf *intf,
+ uint8_t user_id,
+ const char *name)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[17];
+
+ /*
+ * Ensure there is space for the name in the request message buffer
+ */
+ if (strlen(name) >= sizeof(msg_data)) {
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */
+ req.msg.cmd = IPMI_SET_USER_NAME; /* 0x45 */
+ req.msg.data = msg_data;
+ req.msg.data_len = sizeof(msg_data);
+ memset(msg_data, 0, sizeof(msg_data));
+
+ /* The channel number will remain constant throughout this function */
+ msg_data[0] = user_id;
+ strncpy((char *)(msg_data + 1), name, strlen(name));
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set User Name command failed (user %d, name %s)",
+ user_id, name);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set User Name command failed (user %d, name %s): %s",
+ user_id, name, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ipmi_user_set_userpriv(
+ struct ipmi_intf *intf,
+ uint8_t channel,
+ uint8_t user_id,
+ const unsigned char privLevel)
+{
+ struct ipmi_rs *rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[4] = {0, 0, 0, 0};
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */
+ req.msg.cmd = IPMI_SET_USER_ACCESS; /* 0x43 */
+ req.msg.data = msg_data;
+ req.msg.data_len = 4;
+
+ /* The channel number will remain constant throughout this function */
+ msg_data[0] = (channel & 0x0f);
+ msg_data[1] = (user_id & 0x3f);
+ msg_data[2] = (privLevel & 0x0f);
+ msg_data[3] = 0;
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL)
+ {
+ lprintf(LOG_ERR, "Set Privilege Level command failed (user %d)",
+ user_id);
+ return -1;
+ }
+ if (rsp->ccode > 0)
+ {
+ lprintf(LOG_ERR, "Set Privilege Level command failed (user %d): %s",
+ user_id, val2str(rsp->ccode, completion_code_vals));
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * ipmi_user_set_password
+ *
+ * This function is responsible for 4 things
+ * Enabling/Disabling users
+ * Setting/Testing passwords
+ */
+static int
+ipmi_user_set_password(
+ struct ipmi_intf * intf,
+ uint8_t user_id,
+ uint8_t operation,
+ const char *password,
+ int is_twenty_byte_password)
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req;
+ uint8_t msg_data[22];
+
+ int password_length = (is_twenty_byte_password? 20 : 16);
+
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_APP; /* 0x06 */
+ req.msg.cmd = IPMI_SET_USER_PASSWORD; /* 0x47 */
+ req.msg.data = msg_data;
+ req.msg.data_len = password_length + 2;
+
+
+ /* The channel number will remain constant throughout this function */
+ msg_data[0] = user_id;
+
+ if (is_twenty_byte_password)
+ msg_data[0] |= 0x80;
+
+ msg_data[1] = operation;
+
+ memset(msg_data + 2, 0, password_length);
+
+ if (password != NULL)
+ strncpy((char *)(msg_data + 2), password, password_length);
+
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp == NULL) {
+ lprintf(LOG_ERR, "Set User Password command failed (user %d)",
+ user_id);
+ return -1;
+ }
+ if (rsp->ccode > 0) {
+ lprintf(LOG_ERR, "Set User Password command failed (user %d): %s",
+ user_id, val2str(rsp->ccode, completion_code_vals));
+ return rsp->ccode;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * ipmi_user_test_password
+ *
+ * Call ipmi_user_set_password, and interpret the result
+ */
+static int
+ipmi_user_test_password(
+ struct ipmi_intf * intf,
+ uint8_t user_id,
+ const char * password,
+ int is_twenty_byte_password)
+{
+ int ret;
+
+ ret = ipmi_user_set_password(intf,
+ user_id,
+ IPMI_PASSWORD_TEST_PASSWORD,
+ password,
+ is_twenty_byte_password);
+
+ switch (ret) {
+ case 0:
+ printf("Success\n");
+ break;
+ case 0x80:
+ printf("Failure: password incorrect\n");
+ break;
+ case 0x81:
+ printf("Failure: wrong password size\n");
+ break;
+ default:
+ printf("Unknown error\n");
+ }
+
+ return ((ret == 0) ? 0 : -1);
+}
+
+
+/*
+ * print_user_usage
+ */
+static void
+print_user_usage(void)
+{
+ lprintf(LOG_NOTICE, "User Commands:");
+ lprintf(LOG_NOTICE, " summary [<channel number>]");
+ lprintf(LOG_NOTICE, " list [<channel number>]");
+ lprintf(LOG_NOTICE, " set name <user id> <username>");
+ lprintf(LOG_NOTICE, " set password <user id> [<password>]");
+ lprintf(LOG_NOTICE, " disable <user id>");
+ lprintf(LOG_NOTICE, " enable <user id>");
+ lprintf(LOG_NOTICE,
+ " priv <user id> <privilege level> [<channel number>]");
+ lprintf(LOG_NOTICE, " test <user id> <16|20> [<password]>\n");
+}
+
+
+const char *
+ipmi_user_build_password_prompt(uint8_t user_id)
+{
+ static char prompt[128];
+ memset(prompt, 0, 128);
+ snprintf(prompt, 128, "Password for user %d: ", user_id);
+ return prompt;
+}
+
+
+/*
+ * ipmi_user_main
+ *
+ * Upon entry to this function argv should contain our arguments
+ * specific to this subcommand
+ */
+int
+ipmi_user_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+ int retval = 0;
+
+ /*
+ * Help
+ */
+ if (argc == 0 || strncmp(argv[0], "help", 4) == 0)
+ {
+ print_user_usage();
+ }
+
+ /*
+ * Summary
+ */
+ else if (strncmp(argv[0], "summary", 7) == 0)
+ {
+ uint8_t channel;
+
+ if (argc == 1)
+ channel = 0x0E; /* Ask about the current channel */
+ else if (argc == 2)
+ {
+ if (str2uchar(argv[1], &channel) != 0)
+ {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[1]);
+ return (-1);
+ }
+ }
+ else
+ {
+ print_user_usage();
+ return -1;
+ }
+
+ retval = ipmi_print_user_summary(intf, channel);
+ }
+
+
+ /*
+ * List
+ */
+ else if (strncmp(argv[0], "list", 4) == 0)
+ {
+ uint8_t channel;
+
+ if (argc == 1)
+ channel = 0x0E; /* Ask about the current channel */
+ else if (argc == 2)
+ {
+ if (str2uchar(argv[1], &channel) != 0)
+ {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[1]);
+ return (-1);
+ }
+ }
+ else
+ {
+ print_user_usage();
+ return -1;
+ }
+
+ retval = ipmi_print_user_list(intf, channel);
+ }
+
+
+
+ /*
+ * Test
+ */
+ else if (strncmp(argv[0], "test", 4) == 0)
+ {
+ // a little irritating, isn't it
+ if (argc == 3 || argc == 4)
+ {
+ char * password = NULL;
+ int password_length = 0;
+ uint8_t user_id = 0;
+ if (is_ipmi_user_id(argv[1], &user_id)) {
+ return (-1);
+ }
+ if (str2int(argv[2], &password_length) != 0
+ || (password_length != 16 && password_length != 20)) {
+ lprintf(LOG_ERR,
+ "Given password length '%s' is invalid.",
+ argv[2]);
+ lprintf(LOG_ERR, "Expected value is either 16 or 20.");
+ return (-1);
+ }
+
+ if (argc == 3)
+ {
+ /* We need to prompt for a password */
+
+ char * tmp;
+ const char * password_prompt =
+ ipmi_user_build_password_prompt(user_id);
+# ifdef HAVE_GETPASSPHRASE
+ tmp = getpassphrase (password_prompt);
+# else
+ tmp = (char*)getpass (password_prompt);
+# endif
+ if (tmp != NULL) {
+ password = strdup(tmp);
+ tmp = NULL;
+ }
+ if (password == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+ }
+ else {
+ password = strdup(argv[3]);
+ }
+
+
+ retval = ipmi_user_test_password(intf,
+ user_id,
+ password,
+ password_length == 20);
+ if (password != NULL) {
+ free(password);
+ password = NULL;
+ }
+ }
+ else
+ {
+ print_user_usage();
+ return -1;
+ }
+ }
+
+ /*
+ * Set
+ */
+ else if (strncmp(argv[0], "set", 3) == 0)
+ {
+ /*
+ * Set Password
+ */
+ if ((argc >= 3) &&
+ (strncmp("password", argv[1], 8) == 0))
+ {
+ char * password = NULL;
+ uint8_t user_id = 0;
+ if (is_ipmi_user_id(argv[2], &user_id)) {
+ return (-1);
+ }
+
+ if (argc == 3)
+ {
+ /* We need to prompt for a password */
+ char * tmp;
+ const char * password_prompt =
+ ipmi_user_build_password_prompt(user_id);
+# ifdef HAVE_GETPASSPHRASE
+ tmp = getpassphrase (password_prompt);
+# else
+ tmp = (char*)getpass (password_prompt);
+# endif
+ if (tmp != NULL) {
+ password = strdup(tmp);
+ tmp = NULL;
+ }
+ if (password == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return -1;
+ }
+# ifdef HAVE_GETPASSPHRASE
+ tmp = getpassphrase (password_prompt);
+# else
+ tmp = (char*)getpass (password_prompt);
+# endif
+ if (tmp == NULL) {
+ lprintf(LOG_ERR, "ipmitool: malloc failure");
+ return (-1);
+ }
+ if (strlen(password) != strlen(tmp)
+ || strncmp(password, tmp, strlen(tmp))) {
+ lprintf(LOG_ERR, "Passwords do not match.");
+ free(password);
+ password = NULL;
+ return -1;
+ }
+ tmp = NULL;
+ } else {
+ password = strdup(argv[3]);
+ }
+
+ if (password == NULL) {
+ lprintf(LOG_ERR, "Unable to parse password argument.");
+ return -1;
+ }
+ else if (strlen(password) > 20)
+ {
+ lprintf(LOG_ERR, "Password is too long (> 20 bytes)");
+ return -1;
+ }
+
+ retval = ipmi_user_set_password(intf,
+ user_id,
+ IPMI_PASSWORD_SET_PASSWORD,
+ password,
+ strlen(password) > 16);
+ if (password != NULL) {
+ free(password);
+ password = NULL;
+ }
+ }
+
+ /*
+ * Set Name
+ */
+ else if ((argc >= 2) &&
+ (strncmp("name", argv[1], 4) == 0))
+ {
+ uint8_t user_id = 0;
+ if (argc != 4)
+ {
+ print_user_usage();
+ return -1;
+ }
+ if (is_ipmi_user_id(argv[2], &user_id)) {
+ return (-1);
+ }
+
+ if (strlen(argv[3]) > 16)
+ {
+ lprintf(LOG_ERR, "Username is too long (> 16 bytes)");
+ return -1;
+ }
+
+ retval = ipmi_user_set_username(intf, user_id, argv[3]);
+ }
+ else
+ {
+ print_user_usage();
+ return -1;
+ }
+ }
+
+ else if (strncmp(argv[0], "priv", 4) == 0)
+ {
+ uint8_t user_id;
+ uint8_t priv_level;
+ uint8_t channel = 0x0e; /* Use channel running on */
+
+ if (argc != 3 && argc != 4)
+ {
+ print_user_usage();
+ return -1;
+ }
+
+ if (argc == 4)
+ {
+ if (str2uchar(argv[3], &channel) != 0)
+ {
+ lprintf(LOG_ERR, "Invalid channel: %s", argv[3]);
+ return (-1);
+ }
+ channel = (channel & 0x0f);
+ }
+
+ if (str2uchar(argv[2], &priv_level) != 0)
+ {
+ lprintf(LOG_ERR, "Invalid privilege level: %s", argv[2]);
+ return (-1);
+ }
+ priv_level = (priv_level & 0x0f);
+
+ if (is_ipmi_user_id(argv[1], &user_id)) {
+ return (-1);
+ }
+
+ retval = ipmi_user_set_userpriv(intf,channel,user_id,priv_level);
+ }
+
+ /*
+ * Disable / Enable
+ */
+ else if ((strncmp(argv[0], "disable", 7) == 0) ||
+ (strncmp(argv[0], "enable", 6) == 0))
+ {
+ uint8_t user_id;
+ uint8_t operation;
+ char null_password[16]; /* Not used, but required */
+
+ memset(null_password, 0, sizeof(null_password));
+
+ if (argc != 2)
+ {
+ print_user_usage();
+ return -1;
+ }
+
+ if (is_ipmi_user_id(argv[1], &user_id)) {
+ return (-1);
+ }
+
+ operation = (strncmp(argv[0], "disable", 7) == 0) ?
+ IPMI_PASSWORD_DISABLE_USER : IPMI_PASSWORD_ENABLE_USER;
+
+ retval = ipmi_user_set_password(intf,
+ user_id,
+ operation,
+ null_password,
+ 0); /* This field is ignored */
+ }
+ else
+ {
+ retval = -1;
+ lprintf(LOG_ERR, "Invalid user command: '%s'\n", argv[0]);
+ print_user_usage();
+ }
+
+ return retval;
+}
diff --git a/lib/log.c b/lib/log.c
new file mode 100644
index 0000000..bc80542
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <ipmitool/log.h>
+
+struct logpriv_s {
+ char * name;
+ int daemon;
+ int level;
+};
+struct logpriv_s *logpriv;
+
+static void log_reinit(void)
+{
+ log_init(NULL, 0, 0);
+}
+
+void lprintf(int level, const char * format, ...)
+{
+ static char logmsg[LOG_MSG_LENGTH];
+ va_list vptr;
+
+ if (!logpriv)
+ log_reinit();
+
+ if (logpriv->level < level)
+ return;
+
+ va_start(vptr, format);
+ vsnprintf(logmsg, LOG_MSG_LENGTH, format, vptr);
+ va_end(vptr);
+
+ if (logpriv->daemon)
+ syslog(level, "%s", logmsg);
+ else
+ fprintf(stderr, "%s\n", logmsg);
+ return;
+}
+
+void lperror(int level, const char * format, ...)
+{
+ static char logmsg[LOG_MSG_LENGTH];
+ va_list vptr;
+
+ if (!logpriv)
+ log_reinit();
+
+ if (logpriv->level < level)
+ return;
+
+ va_start(vptr, format);
+ vsnprintf(logmsg, LOG_MSG_LENGTH, format, vptr);
+ va_end(vptr);
+
+ if (logpriv->daemon)
+ syslog(level, "%s: %s", logmsg, strerror(errno));
+ else
+ fprintf(stderr, "%s: %s\n", logmsg, strerror(errno));
+ return;
+}
+
+/*
+ * open connection to syslog if daemon
+ */
+void log_init(const char * name, int isdaemon, int verbose)
+{
+ if (logpriv)
+ return;
+
+ logpriv = malloc(sizeof(struct logpriv_s));
+ if (!logpriv)
+ return;
+
+ if (name != NULL)
+ logpriv->name = strdup(name);
+ else
+ logpriv->name = strdup(LOG_NAME_DEFAULT);
+
+ if (logpriv->name == NULL)
+ fprintf(stderr, "ipmitool: malloc failure\n");
+
+ logpriv->daemon = isdaemon;
+ logpriv->level = verbose + LOG_NOTICE;
+
+ if (logpriv->daemon)
+ openlog(logpriv->name, LOG_CONS, LOG_LOCAL4);
+}
+
+/*
+ * stop syslog logging if daemon mode,
+ * free used memory that stored log service
+ */
+void log_halt(void)
+{
+ if (!logpriv)
+ return;
+
+ if (logpriv->name) {
+ free(logpriv->name);
+ logpriv->name = NULL;
+ }
+
+ if (logpriv->daemon)
+ closelog();
+
+ free(logpriv);
+ logpriv = NULL;
+}
+
+int log_level_get(void)
+{
+ return logpriv->level;
+}
+
+void log_level_set(int level)
+{
+ logpriv->level = level;
+}
+