mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-07-01 10:13:35 +00:00
Compare commits
20 Commits
codefactor
...
feature/ad
Author | SHA1 | Date | |
---|---|---|---|
ef92ab51e3 | |||
994d47b415 | |||
90131f19fa | |||
9bc1143e96 | |||
69a44963d0 | |||
ca3a80fef8 | |||
80350a744f | |||
619a02cf5d | |||
e65a96b38d | |||
9fa01f1a54 | |||
432ea31804 | |||
12e2f5da63 | |||
d818c2ff85 | |||
cdd9d51c5f | |||
95038ba01b | |||
b0d84e0f15 | |||
1b636434a6 | |||
400622760f | |||
b7b455a38c | |||
fa8e2ced19 |
39
.travis.yml
39
.travis.yml
@ -1,10 +1,37 @@
|
||||
language: C
|
||||
sudo: enabled
|
||||
before_install:
|
||||
- sudo apt-get install -y libssl-dev
|
||||
before_script:
|
||||
- ./bootstrap
|
||||
script:
|
||||
- ./configure --enable-intf-dummy
|
||||
- make
|
||||
- sudo make install
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libssl-dev
|
||||
homebrew:
|
||||
packages:
|
||||
- openssl
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libsystemd-dev
|
||||
script:
|
||||
- ./configure --enable-intf-dummy --enable-intf-dbus
|
||||
- make
|
||||
- sudo make install
|
||||
- os: linux
|
||||
dist: trusty
|
||||
script:
|
||||
- ./configure --enable-intf-dummy
|
||||
- make
|
||||
- sudo make install
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
script:
|
||||
- ./configure --enable-intf-dummy
|
||||
- make
|
||||
- sudo make install
|
||||
|
32
INSTALL
32
INSTALL
@ -9,17 +9,33 @@ are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
This project requires at least gcc 4.8.1 as it uses some GNU
|
||||
extensions and some C11 features. For `lanplus` interface the OpenSSL
|
||||
library and development headers are required. As of April 2019, the
|
||||
project is tested automatically to build cleanly for the following
|
||||
64-bit operating systems:
|
||||
|
||||
- Ubuntu 14.04 Trusty
|
||||
- Ubuntu 16.04 Xenial
|
||||
- MacOS X 10.14 (Xcode 10.2)
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell command `./configure && make && make install'
|
||||
should configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
Briefly, the followong shell command should configure, build, and
|
||||
install this package:
|
||||
`./bootstrap && ./configure && make && make install`
|
||||
|
||||
The following more-detailed instructions are generic; see the
|
||||
`README' file for instructions specific to this package. Some
|
||||
packages provide this `INSTALL' file but do not implement all of the
|
||||
features documented below. The lack of an optional feature in a given
|
||||
package is not necessarily a bug. More recommendations for GNU
|
||||
packages can be found in *note Makefile Conventions:
|
||||
(standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
|
51
configure.ac
51
configure.ac
@ -59,6 +59,7 @@ dnl
|
||||
|
||||
xenable_all_options=yes
|
||||
xenable_intf_bmc=no
|
||||
xenable_intf_dbus=no
|
||||
xenable_intf_dummy=no
|
||||
xenable_intf_imb=yes
|
||||
xenable_intf_lipmi=yes
|
||||
@ -191,6 +192,14 @@ AC_CHECK_LIB([crypto], [MD2_Init],
|
||||
fi],
|
||||
[], [-lcrypto])
|
||||
|
||||
dnl check for libsystemd in case dbus-intf is requested
|
||||
AC_CHECK_LIB([systemd], [sd_bus_default],
|
||||
[
|
||||
LIBS="$LIBS -lsystemd"
|
||||
have_systemd=yes
|
||||
],
|
||||
[ have_systemd=no],[])
|
||||
|
||||
dnl enable IPMIv1.5 LAN interface
|
||||
AC_ARG_ENABLE([intf-lan],
|
||||
[AC_HELP_STRING([--enable-intf-lan],
|
||||
@ -554,6 +563,25 @@ if test "x$xenable_intf_bmc" = "xyes"; then
|
||||
IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB bmc/libintf_bmc.la"
|
||||
fi
|
||||
|
||||
dnl enable IPMI dbus interface
|
||||
AC_ARG_ENABLE([intf-dbus],
|
||||
[AC_HELP_STRING([--enable-intf-dbus],
|
||||
[enable IPMI dbus interface [default=no]])],
|
||||
[xenable_intf_dbus=$enableval],
|
||||
[xenable_intf_dbus=no])
|
||||
if test "x$xenable_intf_dbus" != "xno"; then
|
||||
if test "x$have_systemd" != "xyes"; then
|
||||
AC_MSG_ERROR([** Unable to find libsystemd required by dbus-intf.])
|
||||
xenable_intf_dbus=no
|
||||
fi
|
||||
fi
|
||||
if test "x$xenable_intf_dbus" = "xyes"; then
|
||||
AC_DEFINE(IPMI_INTF_DBUS, [1], [Define to 1 to enable dbus interface.])
|
||||
AC_SUBST(INTF_DBUS, [dbus])
|
||||
AC_SUBST(INTF_DBUS_LIB, [libintf_dbus.la])
|
||||
IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB dbus/libintf_dbus.la"
|
||||
fi
|
||||
|
||||
dnl enable Dummy interface for testing
|
||||
AC_ARG_ENABLE([intf-dummy],
|
||||
[AC_HELP_STRING([--enable-intf-dummy],
|
||||
@ -643,6 +671,25 @@ AC_TRY_COMPILE([],[
|
||||
[Define to 1 if you need to use #pragma pack instead of __attribute__ ((packed))])]
|
||||
)
|
||||
|
||||
dnl if no environment variable is set, set the default value for the default intf
|
||||
if test "${xenable_intf_open}" = "xyes"; then
|
||||
DEFAULT_INTF_NO_ENV=open
|
||||
else dnl macOS does not build open interface, it defaults to lan
|
||||
DEFAULT_INTF_NO_ENV=lan
|
||||
fi
|
||||
dnl allow for a default interface to be set on configure
|
||||
AC_ARG_VAR(DEFAULT_INTF, [Set the default interface to use (default=${DEFAULT_INTF_NO_ENV})])
|
||||
|
||||
dnl set the default value for the default interface environment variable
|
||||
if test "x${DEFAULT_INTF}" == "x"; then
|
||||
echo "DEFAULT_INTF not found in environment; setting to ${DEFAULT_INTF_NO_ENV}"
|
||||
DEFAULT_INTF=${DEFAULT_INTF_NO_ENV}
|
||||
fi
|
||||
|
||||
xdefault_intf_is_enabled="xenable_intf_${DEFAULT_INTF}"
|
||||
if test "x${!xdefault_intf_is_enabled}" != "xyes"; then
|
||||
AC_MSG_ERROR([** Cannot set ${DEFAULT_INTF} as default; ${DEFAULT_INTF} is not enabled. :${!xdefault_intf_is_enabled}:])
|
||||
fi
|
||||
|
||||
dnl Generate files for build
|
||||
AC_CONFIG_FILES([Makefile
|
||||
@ -664,6 +711,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/plugins/free/Makefile
|
||||
src/plugins/imb/Makefile
|
||||
src/plugins/bmc/Makefile
|
||||
src/plugins/dbus/Makefile
|
||||
src/plugins/usb/Makefile
|
||||
src/plugins/lipmi/Makefile
|
||||
src/plugins/serial/Makefile
|
||||
@ -674,13 +722,14 @@ AC_OUTPUT
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([ipmitool $VERSION])
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([Interfaces])
|
||||
AC_MSG_RESULT([Interfaces (default=$DEFAULT_INTF)])
|
||||
AC_MSG_RESULT([ lan : $xenable_intf_lan])
|
||||
AC_MSG_RESULT([ lanplus : $xenable_intf_lanplus])
|
||||
AC_MSG_RESULT([ open : $xenable_intf_open])
|
||||
AC_MSG_RESULT([ free : $xenable_intf_free])
|
||||
AC_MSG_RESULT([ imb : $xenable_intf_imb])
|
||||
AC_MSG_RESULT([ bmc : $xenable_intf_bmc])
|
||||
AC_MSG_RESULT([ dbus : $xenable_intf_dbus])
|
||||
AC_MSG_RESULT([ usb : $xenable_intf_usb])
|
||||
AC_MSG_RESULT([ lipmi : $xenable_intf_lipmi])
|
||||
AC_MSG_RESULT([ serial : $xenable_intf_serial])
|
||||
|
@ -1,7 +1,8 @@
|
||||
[Unit]
|
||||
Description=Exchange Information between BMC and OS
|
||||
After=ipmi.service network.target
|
||||
Requires=ipmi.service
|
||||
After=network.target
|
||||
AssertFileIsExecutable=/usr/bin/ipmitool
|
||||
AssertPathExistsGlob=/dev/ipmi*
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
172
doc/ipmitool.1
172
doc/ipmitool.1
@ -384,39 +384,23 @@ application (ipmi or sol) on the given channel.
|
||||
\fIstatus\fP
|
||||
|
||||
Status information related to power, buttons, cooling, drives and faults.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIpower\fP
|
||||
.RS
|
||||
.TP
|
||||
\fIstatus\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIon\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIoff\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIcycle\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIreset\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIdiag\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIsoft\fP
|
||||
.RS
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
\fIidentify\fP [<seconds>|force]
|
||||
@ -428,8 +412,6 @@ Default is 15 seconds.
|
||||
0 - Off
|
||||
.br
|
||||
force - To turn on indefinitely
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIpolicy\fP
|
||||
|
||||
@ -439,34 +421,22 @@ What to do when power is restored.
|
||||
\fIlist\fP
|
||||
|
||||
Show available options.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIalways-on\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIprevious\fP
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIalways-off\fP
|
||||
.RS
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.TP
|
||||
\fIrestart_cause\fP
|
||||
|
||||
Last restart cause.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIpoh\fP
|
||||
|
||||
Get power on hours.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIbootdev\fP
|
||||
.RS
|
||||
@ -474,95 +444,123 @@ Get power on hours.
|
||||
\fInone\fP
|
||||
|
||||
Do not change boot device order.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIpxe\fP
|
||||
|
||||
Force PXE boot.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIdisk\fP
|
||||
|
||||
Force boot from default Hard-drive.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIsafe\fP
|
||||
|
||||
Force boot from default Hard-drive, request Safe Mode.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIdiag\fP
|
||||
|
||||
Force boot from Diagnostic Partition.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIcdrom\fP
|
||||
|
||||
Force boot from CD/DVD.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIbios\fP
|
||||
|
||||
Force boot into BIOS Setup.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIfloppy\fP
|
||||
|
||||
Force boot from Floppy/primary removable media.
|
||||
.RS
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.TP
|
||||
\fIbootmbox\fP \fIget\fP [text] [block <\fBblock#\fP>]
|
||||
|
||||
Read the Boot Initiator Mailbox in hex dump or in text mode.
|
||||
|
||||
By default the whole mailbox is read. If block number is specified,
|
||||
that particular block is read. For block 0 or when the whole
|
||||
mailbox is read, the Boot Initiator IANA Enterprise Number and
|
||||
the corresponding enterprise name are printed.
|
||||
|
||||
.TP
|
||||
\fIbootmbox\fP \fIset\fP text [block <\fBblock#\fP>] <\fBIANA_PEN\fP> "<\fBdata_string\fP>"
|
||||
|
||||
Write the specified <block> or the entire Boot Initiator Mailbox in text mode.
|
||||
It is required to specify a decimal IANA Enterprise Number recognized
|
||||
by the boot initiator on the target system. Refer to your target system
|
||||
manufacturer for details. The rest of the arguments are a text string.
|
||||
|
||||
When single block write is requested, the total length of <data> may not
|
||||
exceed 13 bytes for block 0, or 16 bytes otherwise.
|
||||
|
||||
.TP
|
||||
\fIbootmbox\fP \fIset\fP [block <\fBblock#\fP>] <\fBIANA_PEN\fP> <\fBdata_byte\fP> [<\fBdata_byte\fP> ...]
|
||||
|
||||
Same as above, but the arguments after IANA PEN are separate
|
||||
data byte values separated by spaces.
|
||||
|
||||
.TP
|
||||
\fIbootparam\fP
|
||||
\fIbootparam\fP \fIget\fP <\fBopt_id\fR> [<\fBopt_param\fR>]
|
||||
|
||||
Get value of system boot option number <\fBopt_id\fR>. Some boot
|
||||
options (e.g. option 7) can also take an optional numeric parameter.
|
||||
|
||||
.TP
|
||||
\fIbootparam\fP \fIset\fP bootflag <\fBdevice\fR> [options=...]
|
||||
|
||||
Set a boot flag. Valid devices are:
|
||||
|
||||
.RS
|
||||
.TP
|
||||
\fIforce_pxe\fP
|
||||
.IP \fIforce_pxe\fP
|
||||
|
||||
Force PXE boot
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIforce_disk\fP
|
||||
.IP \fIforce_disk\fP
|
||||
|
||||
Force boot from default Hard-drive
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIforce_safe\fP
|
||||
.IP \fIforce_safe\fP
|
||||
|
||||
Force boot from default Hard-drive, request Safe Mode
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIforce_diag\fP
|
||||
.IP \fIforce_diag\fP
|
||||
|
||||
Force boot from Diagnostic Partition
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIforce_cdrom\fP
|
||||
.IP \fIforce_cdrom\fP
|
||||
|
||||
Force boot from CD/DVD
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIforce_bios\fP
|
||||
.IP \fIforce_bios\fP
|
||||
|
||||
Force boot into BIOS Setup
|
||||
.RS
|
||||
.RE
|
||||
|
||||
.PP
|
||||
Valid options are:
|
||||
|
||||
.IP \fIPEF\fP
|
||||
|
||||
Clear valid bit on reset/power cycle cause by PEF
|
||||
|
||||
.IP \fItimeout\fP
|
||||
|
||||
Automatically clear boot flag valid bit on timeout
|
||||
|
||||
.IP \fIwatchdog\fP
|
||||
|
||||
Clear valid bit on reset/power cycle cause by watchdog
|
||||
|
||||
.IP \fIreset\fP
|
||||
|
||||
Clear valid bit on push button reset/soft reset
|
||||
|
||||
.IP \fIpower\fP
|
||||
|
||||
Clear valid bit on power up via power push button or wake event
|
||||
.RE
|
||||
|
||||
.TP
|
||||
\fIselftest\fP
|
||||
.RS
|
||||
.RE
|
||||
|
||||
Get the chassis self-test results
|
||||
|
||||
.RE
|
||||
.TP
|
||||
\fIdcmi\fP
|
||||
@ -957,8 +955,6 @@ Shows Extended SD Card information.
|
||||
\fIecho\fP
|
||||
|
||||
For echoing lines to stdout in scripts.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIekanalyzer\fP <\fBcommand\fR> <\fBxx=filename1\fR> <\fBxx=filename2\fR> [<\fBrc=filename3\fR>] \fB...\fR
|
||||
.RS
|
||||
@ -1510,20 +1506,14 @@ Show firmware upgrade log.
|
||||
\fIlist\fP
|
||||
|
||||
List All Generic Device Locators.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIread\fP <\fBsdr name\fR> <\fBfile\fR>
|
||||
|
||||
Read to file eeprom specify by Generic Device Locators.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIwrite\fP <\fBsdr name\fR> <\fBfile\fR>
|
||||
|
||||
Write from file eeprom specify by Generic Device Locators
|
||||
.RS
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
\fIhpm\fP
|
||||
@ -3150,50 +3140,34 @@ or by using the keyword `all' to specify all sessions.
|
||||
\fIhostname\fP <\fBhost\fR>
|
||||
|
||||
Session hostname.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIusername\fP <\fBuser\fR>
|
||||
|
||||
Session username.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIpassword\fP <\fBpass\fR>
|
||||
|
||||
Session password.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIprivlvl\fP <\fBlevel\fR>
|
||||
|
||||
Session privilege level force.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIauthtype\fP <\fBtype\fR>
|
||||
|
||||
Authentication type force.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIlocaladdr\fP <\fBaddr\fR>
|
||||
|
||||
Local IPMB address.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fItargetaddr\fP <\fBaddr\fR>
|
||||
|
||||
Remote target IPMB address.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIport\fP <\fBport\fR>
|
||||
|
||||
Remote RMCP port.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIcsv\fP [\fBlevel\fR]
|
||||
|
||||
@ -3201,14 +3175,10 @@ Enable output in comma separated format.
|
||||
Affects following commands:
|
||||
\fIuser\fP, \fIchannel\fP, \fIisol\fP, \fIsunoem\fP,
|
||||
\fIsol\fP, \fIsensor\fP, \fIsdr\fP, \fIsel\fP, \fIsession\fP.
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
\fIverbose\fP [\fBverbose\fR]
|
||||
|
||||
Verbosity level.
|
||||
.RS
|
||||
.RE
|
||||
.RE
|
||||
.TP
|
||||
\fIshell\fP
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* For free() */
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
@ -79,6 +80,10 @@ struct oemvalstr {
|
||||
const char * str;
|
||||
};
|
||||
|
||||
const char *
|
||||
specific_val2str(uint16_t val,
|
||||
const struct valstr *specific,
|
||||
const struct valstr *generic);
|
||||
const char * val2str(uint16_t val, const struct valstr * vs);
|
||||
const char * oemval2str(uint32_t oem,uint16_t val, const struct oemvalstr * vs);
|
||||
|
||||
@ -92,6 +97,8 @@ int str2ushort(const char * str, uint16_t * ushrt_ptr);
|
||||
int str2char(const char * str, int8_t * chr_ptr);
|
||||
int str2uchar(const char * str, uint8_t * uchr_ptr);
|
||||
|
||||
bool args2buf(int argc, char *argv[], uint8_t *out, size_t len);
|
||||
|
||||
int eval_ccode(const int ccode);
|
||||
|
||||
int is_fru_id(const char *argv_ptr, uint8_t *fru_id_ptr);
|
||||
@ -166,6 +173,13 @@ static inline uint32_t ipmi24toh(void *ipmi24)
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline void htoipmi24(uint32_t h, uint8_t *ipmi)
|
||||
{
|
||||
ipmi[0] = h & 0xFF; /* LSB */
|
||||
ipmi[1] = (h >> 8) & 0xFF;
|
||||
ipmi[2] = (h >> 16) & 0xFF; /* MSB */
|
||||
}
|
||||
|
||||
static inline uint32_t ipmi32toh(void *ipmi32)
|
||||
{
|
||||
uint8_t *ipmi = ipmi32;
|
||||
|
@ -37,6 +37,7 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <ipmitool/bswap.h>
|
||||
@ -381,6 +382,29 @@ struct sdr_record_common_sensor {
|
||||
|
||||
struct sdr_record_mask mask;
|
||||
|
||||
/* IPMI 2.0, Table 43-1, byte 21[7:6] Analog (numeric) Data Format */
|
||||
#define SDR_UNIT_FMT_UNSIGNED 0 /* unsigned */
|
||||
#define SDR_UNIT_FMT_1S_COMPL 1 /* 1's complement (signed) */
|
||||
#define SDR_UNIT_FMT_2S_COMPL 2 /* 2's complement (signed) */
|
||||
#define SDR_UNIT_FMT_NA 3 /* does not return analog (numeric) reading */
|
||||
/* IPMI 2.0, Table 43-1, byte 21[5:3] Rate */
|
||||
#define SDR_UNIT_RATE_NONE 0 /* none */
|
||||
#define SDR_UNIT_RATE_MICROSEC 1 /* per us */
|
||||
#define SDR_UNIT_RATE_MILLISEC 2 /* per ms */
|
||||
#define SDR_UNIT_RATE_SEC 3 /* per s */
|
||||
#define SDR_UNIT_RATE_MIN 4 /* per min */
|
||||
#define SDR_UNIT_RATE_HR 5 /* per hour */
|
||||
#define SDR_UNIT_RATE_DAY 6 /* per day */
|
||||
#define SDR_UNIT_RATE_RSVD 7 /* reserved */
|
||||
/* IPMI 2.0, Table 43-1, byte 21[2:1] Modifier Unit */
|
||||
#define SDR_UNIT_MOD_NONE 0 /* none */
|
||||
#define SDR_UNIT_MOD_DIV 1 /* Basic Unit / Modifier Unit */
|
||||
#define SDR_UNIT_MOD_MUL 2 /* Basic Unit * Mofifier Unit */
|
||||
#define SDR_UNIT_MOD_RSVD 3 /* Reserved */
|
||||
/* IPMI 2.0, Table 43-1, byte 21[0] Percentage */
|
||||
#define SDR_UNIT_PCT_NO 0
|
||||
#define SDR_UNIT_PCT_YES 1
|
||||
|
||||
struct {
|
||||
#if WORDS_BIGENDIAN
|
||||
uint8_t analog:2;
|
||||
@ -394,8 +418,8 @@ struct sdr_record_common_sensor {
|
||||
uint8_t analog:2;
|
||||
#endif
|
||||
struct {
|
||||
uint8_t base;
|
||||
uint8_t modifier;
|
||||
uint8_t base; /* Base unit type code per IPMI 2.0 Table 43-15 */
|
||||
uint8_t modifier; /* Modifier unit type code per Table 43-15 */
|
||||
} ATTRIBUTE_PACKING type;
|
||||
} ATTRIBUTE_PACKING unit;
|
||||
} ATTRIBUTE_PACKING;
|
||||
@ -833,8 +857,8 @@ void ipmi_sdr_print_sensor_hysteresis(struct sdr_record_common_sensor *sensor,
|
||||
struct sdr_record_full_sensor *full,
|
||||
uint8_t hysteresis_value,
|
||||
const char *hdrstr);
|
||||
const char *ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type,
|
||||
uint8_t base, uint8_t modifier);
|
||||
const char *ipmi_sdr_get_unit_string(bool pct, uint8_t type,
|
||||
uint8_t base, uint8_t modifier);
|
||||
struct sensor_reading *
|
||||
ipmi_sdr_read_sensor_value(struct ipmi_intf *intf,
|
||||
struct sdr_record_common_sensor *sensor,
|
||||
|
@ -67,7 +67,9 @@ parse_pen_list() {
|
||||
}
|
||||
|
||||
END {
|
||||
print "{ " PEN ", \"" ENTERPRISE "\" },"
|
||||
if(PEN) {
|
||||
print "{ " PEN ", \"" ENTERPRISE "\" },"
|
||||
}
|
||||
}'
|
||||
}
|
||||
|
||||
|
101
lib/helper.c
101
lib/helper.c
@ -319,26 +319,74 @@ mac2str(const uint8_t *buf)
|
||||
return buf2str_extended(buf, 6, ":");
|
||||
}
|
||||
|
||||
const char * val2str(uint16_t val, const struct valstr *vs)
|
||||
/**
|
||||
* Find the index of value in a valstr array
|
||||
*
|
||||
* @param[in] val The value to search for
|
||||
* @param[in] vs The valstr array to search in
|
||||
* @return >=0 The index into \p vs
|
||||
* @return -1 Error: value \p val was not found in \p vs
|
||||
*/
|
||||
static
|
||||
inline
|
||||
off_t find_val_idx(uint16_t val, const struct valstr *vs)
|
||||
{
|
||||
static char un_str[32];
|
||||
int i;
|
||||
|
||||
for (i = 0; vs[i].str; i++) {
|
||||
if (vs[i].val == val)
|
||||
return vs[i].str;
|
||||
if (vs) {
|
||||
for (off_t i = 0; vs[i].str; ++i) {
|
||||
if (vs[i].val == val) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a statically allocated 'Unknown' string for the provided value.
|
||||
* The function is not thread-safe (as most of ipmitool).
|
||||
*
|
||||
* @param[in] val The value to put into the string
|
||||
* @returns A pointer to a statically allocated string
|
||||
*/
|
||||
static
|
||||
inline
|
||||
const char *unknown_val_str(uint16_t val)
|
||||
{
|
||||
static char un_str[32];
|
||||
memset(un_str, 0, 32);
|
||||
snprintf(un_str, 32, "Unknown (0x%02X)", val);
|
||||
|
||||
return un_str;
|
||||
}
|
||||
|
||||
const char *
|
||||
specific_val2str(uint16_t val,
|
||||
const struct valstr *specific,
|
||||
const struct valstr *generic)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (0 <= (i = find_val_idx(val, specific))) {
|
||||
return specific[i].str;
|
||||
}
|
||||
|
||||
if (0 <= (i = find_val_idx(val, generic))) {
|
||||
return generic[i].str;
|
||||
}
|
||||
|
||||
return unknown_val_str(val);
|
||||
}
|
||||
|
||||
const char * val2str(uint16_t val, const struct valstr *vs)
|
||||
{
|
||||
return specific_val2str(val, NULL, vs);
|
||||
}
|
||||
|
||||
|
||||
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; i++) {
|
||||
@ -349,10 +397,7 @@ const char * oemval2str(uint32_t oem, uint16_t val,
|
||||
}
|
||||
}
|
||||
|
||||
memset(un_str, 0, 32);
|
||||
snprintf(un_str, 32, "Unknown (0x%X)", val);
|
||||
|
||||
return un_str;
|
||||
return unknown_val_str(val);
|
||||
}
|
||||
|
||||
/* str2double - safely convert string to double
|
||||
@ -1080,3 +1125,35 @@ ipmi_get_oem_id(struct ipmi_intf *intf)
|
||||
|
||||
return oem_id;
|
||||
}
|
||||
|
||||
/** Parse command line arguments as numeric byte values (dec or hex)
|
||||
* and store them in a \p len sized buffer \p out.
|
||||
*
|
||||
* @param[in] argc Number of arguments
|
||||
* @param[in] argv Array of arguments
|
||||
* @param[out] out The output buffer
|
||||
* @param[in] len Length of the output buffer in bytes (no null-termination
|
||||
* is assumed, the input data is treated as raw byte values,
|
||||
* not as a string.
|
||||
*
|
||||
* @returns A success status indicator
|
||||
* @return false Error
|
||||
* @return true Success
|
||||
*/
|
||||
bool
|
||||
args2buf(int argc, char *argv[], uint8_t *out, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len && i < (size_t)argc; ++i) {
|
||||
uint8_t byte;
|
||||
|
||||
if (str2uchar(argv[i], &byte)) {
|
||||
lprintf(LOG_ERR, "Bad byte value: %s", argv[i]);
|
||||
return false;
|
||||
}
|
||||
|
||||
out[i] = byte;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <ipmitool/bswap.h>
|
||||
#include <ipmitool/helper.h>
|
||||
@ -44,8 +46,40 @@
|
||||
#include <ipmitool/ipmi_chassis.h>
|
||||
#include <ipmitool/ipmi_time.h>
|
||||
|
||||
#define CHASSIS_BOOT_MBOX_IANA_SZ 3
|
||||
#define CHASSIS_BOOT_MBOX_BLOCK_SZ 16
|
||||
#define CHASSIS_BOOT_MBOX_BLOCK0_SZ \
|
||||
(CHASSIS_BOOT_MBOX_BLOCK_SZ - CHASSIS_BOOT_MBOX_IANA_SZ)
|
||||
#define CHASSIS_BOOT_MBOX_MAX_BLOCK 0xFF
|
||||
#define CHASSIS_BOOT_MBOX_MAX_BLOCKS (CHASSIS_BOOT_MBOX_MAX_BLOCK + 1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t iana[CHASSIS_BOOT_MBOX_IANA_SZ];
|
||||
uint8_t data[CHASSIS_BOOT_MBOX_BLOCK0_SZ];
|
||||
} mbox_b0_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t block;
|
||||
union {
|
||||
uint8_t data[CHASSIS_BOOT_MBOX_BLOCK_SZ];
|
||||
mbox_b0_data_t b0;
|
||||
};
|
||||
} mbox_t;
|
||||
|
||||
extern int verbose;
|
||||
|
||||
static const struct valstr get_bootparam_cc_vals[] = {
|
||||
{ 0x80, "Unsupported parameter" },
|
||||
{ 0x00, NULL }
|
||||
};
|
||||
|
||||
static const struct valstr set_bootparam_cc_vals[] = {
|
||||
{ 0x80, "Unsupported parameter" },
|
||||
{ 0x81, "Attempt to set 'in progress' while not in 'complete' state" },
|
||||
{ 0x82, "Parameter is read-only" },
|
||||
{ 0x00, NULL }
|
||||
};
|
||||
|
||||
int
|
||||
ipmi_chassis_power_status(struct ipmi_intf * intf)
|
||||
{
|
||||
@ -446,61 +480,166 @@ ipmi_chassis_selftest(struct ipmi_intf * intf)
|
||||
}
|
||||
|
||||
static int
|
||||
ipmi_chassis_set_bootparam(struct ipmi_intf * intf, uint8_t param, uint8_t * data, int len)
|
||||
ipmi_chassis_set_bootparam(struct ipmi_intf * intf,
|
||||
uint8_t param, void *data, int len)
|
||||
{
|
||||
struct ipmi_rs * rsp;
|
||||
struct ipmi_rq req;
|
||||
uint8_t msg_data[16];
|
||||
struct {
|
||||
uint8_t param;
|
||||
uint8_t data[];
|
||||
} *msg_data;
|
||||
int rc = -1;
|
||||
size_t msgsize = 1 + len; /* Single-byte parameter plus the data */
|
||||
static const uint8_t BOOTPARAM_MASK = 0x7F;
|
||||
|
||||
memset(msg_data, 0, 16);
|
||||
msg_data[0] = param & 0x7f;
|
||||
memcpy(msg_data+1, data, len);
|
||||
msg_data = malloc(msgsize);
|
||||
if (!msg_data) {
|
||||
goto out;
|
||||
}
|
||||
memset(msg_data, 0, msgsize);
|
||||
|
||||
msg_data->param = param & BOOTPARAM_MASK;
|
||||
memcpy(msg_data->data, 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;
|
||||
req.msg.data = (uint8_t *)msg_data;
|
||||
req.msg.data_len = msgsize;
|
||||
|
||||
rsp = intf->sendrecv(intf, &req);
|
||||
if (!rsp) {
|
||||
lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param);
|
||||
return -1;
|
||||
}
|
||||
if (rsp->ccode) {
|
||||
|
||||
rc = rsp->ccode;
|
||||
if (rc) {
|
||||
if (param != 0) {
|
||||
lprintf(LOG_ERR, "Set Chassis Boot Parameter %d failed: %s",
|
||||
param, val2str(rsp->ccode, completion_code_vals));
|
||||
lprintf(LOG_ERR,
|
||||
"Set Chassis Boot Parameter %d failed: %s",
|
||||
param,
|
||||
specific_val2str(rsp->ccode,
|
||||
set_bootparam_cc_vals,
|
||||
completion_code_vals));
|
||||
}
|
||||
return -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len));
|
||||
return 0;
|
||||
|
||||
out:
|
||||
free_n(&msg_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Flags to ipmi_chassis_get_bootparam() */
|
||||
typedef enum {
|
||||
PARAM_NO_GENERIC_INFO, /* Do not print generic boot parameter info */
|
||||
PARAM_NO_DATA_DUMP, /* Do not dump parameter data */
|
||||
PARAM_NO_RANGE_ERROR, /* Do not report out of range info to user */
|
||||
PARAM_SPECIFIC /* Parameter-specific flags start with this */
|
||||
} chassis_bootparam_flags_t;
|
||||
|
||||
/* Flags to ipmi_chassis_get_bootparam() for Boot Mailbox parameter (7) */
|
||||
typedef enum {
|
||||
MBOX_PARSE_USE_TEXT = PARAM_SPECIFIC, /* Use text output vs. hex */
|
||||
MBOX_PARSE_ALLBLOCKS /* Parse all blocks, not just one */
|
||||
} chassis_bootmbox_parse_t;
|
||||
|
||||
#define BP_FLAG(x) (1 << (x))
|
||||
|
||||
static
|
||||
void
|
||||
chassis_bootmailbox_parse(void *buf, size_t len, int flags)
|
||||
{
|
||||
void *blockdata;
|
||||
size_t datalen;
|
||||
bool use_text = flags & BP_FLAG(MBOX_PARSE_USE_TEXT);
|
||||
bool all_blocks = flags & BP_FLAG(MBOX_PARSE_ALLBLOCKS);
|
||||
|
||||
mbox_t *mbox;
|
||||
|
||||
if (!buf || !len) {
|
||||
return;
|
||||
}
|
||||
|
||||
mbox = buf;
|
||||
blockdata = mbox->data;
|
||||
datalen = len - sizeof(mbox->block);
|
||||
if (!all_blocks) {
|
||||
/* Print block selector only if a single block is printed */
|
||||
printf(" Selector : %d\n", mbox->block);
|
||||
}
|
||||
if (!mbox->block) {
|
||||
uint32_t iana = ipmi24toh(mbox->b0.iana);
|
||||
/* For block zero print the IANA Private Enterprise Number */
|
||||
printf(" IANA PEN : %" PRIu32 " [%s]\n",
|
||||
iana,
|
||||
val2str(iana, ipmi_oem_info));
|
||||
blockdata = mbox->b0.data;
|
||||
datalen -= sizeof(mbox->b0.iana);
|
||||
}
|
||||
|
||||
printf(" Block ");
|
||||
if (all_blocks) {
|
||||
printf("%3" PRIu8 " Data : ", mbox->block);
|
||||
}
|
||||
else {
|
||||
printf("Data : ");
|
||||
}
|
||||
if (use_text) {
|
||||
/* Ensure the data string is null-terminated */
|
||||
unsigned char text[CHASSIS_BOOT_MBOX_BLOCK_SZ + 1] = { 0 };
|
||||
memcpy(text, blockdata, datalen);
|
||||
printf("'%s'\n", text);
|
||||
}
|
||||
else {
|
||||
printf("%s\n", buf2str(blockdata, datalen));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
|
||||
ipmi_chassis_get_bootparam(struct ipmi_intf * intf,
|
||||
int argc, char *argv[], int flags)
|
||||
{
|
||||
struct ipmi_rs * rsp;
|
||||
struct ipmi_rq req;
|
||||
uint8_t msg_data[3];
|
||||
uint8_t param_id = 0;
|
||||
bool skip_generic = flags & BP_FLAG(PARAM_NO_GENERIC_INFO);
|
||||
bool skip_data = flags & BP_FLAG(PARAM_NO_DATA_DUMP);
|
||||
bool skip_range = flags & BP_FLAG(PARAM_NO_RANGE_ERROR);
|
||||
int rc = -1;
|
||||
|
||||
if (!arg)
|
||||
return -1;
|
||||
|
||||
if (str2uchar(arg, ¶m_id) != 0) {
|
||||
lprintf(LOG_ERR, "Invalid parameter '%s' given instead of bootparam.",
|
||||
arg);
|
||||
return (-1);
|
||||
if (argc < 1 || !argv[0]) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (str2uchar(argv[0], ¶m_id)) {
|
||||
lprintf(LOG_ERR,
|
||||
"Invalid parameter '%s' given instead of bootparam.",
|
||||
argv[0]);
|
||||
goto out;
|
||||
}
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
|
||||
memset(msg_data, 0, 3);
|
||||
|
||||
msg_data[0] = param_id & 0x7f;
|
||||
msg_data[1] = 0;
|
||||
msg_data[2] = 0;
|
||||
|
||||
if (argc) {
|
||||
if (str2uchar(argv[0], &msg_data[1])) {
|
||||
lprintf(LOG_ERR,
|
||||
"Invalid argument '%s' given to"
|
||||
" bootparam %" PRIu8,
|
||||
argv[0], msg_data[1]);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.msg.netfn = IPMI_NETFN_CHASSIS;
|
||||
@ -510,12 +649,21 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
|
||||
|
||||
rsp = intf->sendrecv(intf, &req);
|
||||
if (!rsp) {
|
||||
lprintf(LOG_ERR, "Error Getting Chassis Boot Parameter %s", arg);
|
||||
lprintf(LOG_ERR,
|
||||
"Error Getting Chassis Boot Parameter %" PRIu8,
|
||||
msg_data[0]);
|
||||
return -1;
|
||||
}
|
||||
if (IPMI_CC_PARAM_OUT_OF_RANGE == rsp->ccode && skip_range) {
|
||||
return -1;
|
||||
}
|
||||
if (rsp->ccode) {
|
||||
lprintf(LOG_ERR, "Get Chassis Boot Parameter %s failed: %s",
|
||||
arg, val2str(rsp->ccode, completion_code_vals));
|
||||
lprintf(LOG_ERR,
|
||||
"Get Chassis Boot Parameter %" PRIu8 " failed: %s",
|
||||
msg_data[0],
|
||||
specific_val2str(rsp->ccode,
|
||||
get_bootparam_cc_vals,
|
||||
completion_code_vals));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -525,10 +673,17 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
|
||||
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));
|
||||
if (!skip_generic) {
|
||||
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");
|
||||
if (!skip_data) {
|
||||
printf("Boot parameter data: %s\n",
|
||||
buf2str(rsp->data+2, rsp->data_len - 2));
|
||||
}
|
||||
}
|
||||
|
||||
switch(param_id)
|
||||
{
|
||||
@ -716,17 +871,18 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
{
|
||||
printf(" Selector : %d\n", rsp->data[2] );
|
||||
printf(" Block Data : %s\n", buf2str(rsp->data+3, rsp->data_len - 2));
|
||||
}
|
||||
break;
|
||||
chassis_bootmailbox_parse(rsp->data + 2,
|
||||
rsp->data_len - 2,
|
||||
flags);
|
||||
break;
|
||||
default:
|
||||
printf(" Undefined byte\n");
|
||||
printf(" Unsupported parameter %" PRIu8 "\n", param_id);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
rc = IPMI_CC_OK;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -832,7 +988,10 @@ ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
|
||||
}
|
||||
if (rsp->ccode) {
|
||||
lprintf(LOG_ERR, "Get Chassis Boot Parameter %d failed: %s",
|
||||
param_id, val2str(rsp->ccode, completion_code_vals));
|
||||
param_id,
|
||||
specific_val2str(rsp->ccode,
|
||||
get_bootparam_cc_vals,
|
||||
completion_code_vals));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -842,77 +1001,97 @@ ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
|
||||
return(rsp->data[2]);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
SET_COMPLETE,
|
||||
SET_IN_PROGRESS,
|
||||
COMMIT_WRITE,
|
||||
RESERVED
|
||||
} progress_t;
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
chassis_bootparam_set_in_progress(struct ipmi_intf *intf, progress_t progress)
|
||||
{
|
||||
/*
|
||||
* By default try to set/clear set-in-progress parameter before/after
|
||||
* changing any boot parameters. If setting fails, the code will set
|
||||
* this flag to false and stop trying to fiddle with it for future
|
||||
* requests.
|
||||
*/
|
||||
static bool use_progress = true;
|
||||
uint8_t flag = progress;
|
||||
int rc;
|
||||
|
||||
if (!use_progress) {
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ipmi_chassis_set_bootparam(intf,
|
||||
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
|
||||
&flag, 1);
|
||||
|
||||
/*
|
||||
* Only disable future checks if set in progress status setting failed.
|
||||
* Setting of other statuses may fail legitimately.
|
||||
*/
|
||||
if (rc && SET_IN_PROGRESS == progress) {
|
||||
use_progress = false;
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
BIOS_POST_ACK = 1 << 0,
|
||||
OS_LOADER_ACK = 1 << 1,
|
||||
OS_SERVICE_PARTITION_ACK = 1 << 2,
|
||||
SMS_ACK = 1 << 3,
|
||||
OEM_ACK = 1 << 4,
|
||||
RESERVED_ACK_MASK = 7 << 5
|
||||
} bootinfo_ack_t;
|
||||
|
||||
static
|
||||
int
|
||||
chassis_bootparam_clear_ack(struct ipmi_intf *intf, bootinfo_ack_t flag)
|
||||
{
|
||||
uint8_t flags[2] = { flag & ~RESERVED_ACK_MASK,
|
||||
flag & ~RESERVED_ACK_MASK };
|
||||
|
||||
return ipmi_chassis_set_bootparam(intf,
|
||||
IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
|
||||
flags, 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;
|
||||
uint8_t flags[2];
|
||||
int rc;
|
||||
|
||||
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;
|
||||
}
|
||||
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS);
|
||||
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK);
|
||||
|
||||
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 (rc) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
lprintf(LOG_ERR, "Failed to read boot valid flag");
|
||||
rc = bootvalid;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
rc = ipmi_chassis_set_bootparam(intf,
|
||||
IPMI_CHASSIS_BOOTPARAM_FLAG_VALID,
|
||||
flags, 1);
|
||||
if (IPMI_CC_OK == rc) {
|
||||
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE);
|
||||
}
|
||||
|
||||
out:
|
||||
chassis_bootparam_set_in_progress(intf, SET_COMPLETE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -920,38 +1099,17 @@ 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;
|
||||
int rc;
|
||||
|
||||
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);
|
||||
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS);
|
||||
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK);
|
||||
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!iflags)
|
||||
memset(flags, 0, 5);
|
||||
memset(flags, 0, sizeof(flags));
|
||||
else
|
||||
memcpy(flags, iflags, sizeof (flags));
|
||||
|
||||
@ -982,45 +1140,316 @@ ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags)
|
||||
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;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
rc = ipmi_chassis_set_bootparam(intf,
|
||||
IPMI_CHASSIS_BOOTPARAM_BOOT_FLAGS,
|
||||
flags, 5);
|
||||
if (IPMI_CC_OK == rc) {
|
||||
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE);
|
||||
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);
|
||||
out:
|
||||
chassis_bootparam_set_in_progress(intf, SET_COMPLETE);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void chassis_bootmailbox_help()
|
||||
{
|
||||
lprintf(LOG_NOTICE,
|
||||
"bootmbox get [text] [block <block>]\n"
|
||||
" Read the entire Boot Initiator Mailbox or the specified <block>.\n"
|
||||
" If 'text' option is specified, the data is output as plain text, otherwise\n"
|
||||
" hex dump mode is used.\n"
|
||||
"\n"
|
||||
"bootmbox set text [block <block>] <IANA_PEN> \"<data_string>\"\n"
|
||||
"bootmbox set [block <block>] <IANA_PEN> <data_byte> [<data_byte> ...]\n"
|
||||
" Write the specified <block> or the entire Boot Initiator Mailbox.\n"
|
||||
" It is required to specify a decimal IANA Enterprise Number recognized\n"
|
||||
" by the boot initiator on the target system. Refer to your target system\n"
|
||||
" manufacturer for details. The rest of the arguments are either separate\n"
|
||||
" data byte values separated by spaces, or a single text string argument.\n"
|
||||
"\n"
|
||||
" When single block write is requested, the total length of <data> may not\n"
|
||||
" exceed 13 bytes for block 0, or 16 bytes otherwise.\n"
|
||||
"\n"
|
||||
"bootmbox help\n"
|
||||
" Show this help.");
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
chassis_set_bootmailbox(struct ipmi_intf *intf, int16_t block, bool use_text,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
int rc = -1;
|
||||
int32_t iana = 0;
|
||||
size_t blocks = 0;
|
||||
size_t datasize = 0;
|
||||
off_t string_offset = 0;
|
||||
|
||||
lprintf(LOG_INFO, "Writing Boot Mailbox...");
|
||||
|
||||
if (argc < 1 || str2int(argv[0], &iana)) {
|
||||
lprintf(LOG_ERR,
|
||||
"No valid IANA PEN specified!\n");
|
||||
chassis_bootmailbox_help();
|
||||
goto out;
|
||||
}
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
if (argc < 1) {
|
||||
lprintf(LOG_ERR,
|
||||
"No data provided!\n");
|
||||
chassis_bootmailbox_help();
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the data size. For text mode it is just the
|
||||
* single argument string length plus one byte for \0 termination.
|
||||
* For byte mode the length is the number of byte arguments without
|
||||
* any additional termination.
|
||||
*/
|
||||
if (!use_text) {
|
||||
datasize = argc;
|
||||
}
|
||||
else {
|
||||
datasize = strlen(argv[0]) + 1; /* Include the terminator */
|
||||
}
|
||||
|
||||
lprintf(LOG_INFO, "Data size: %u", datasize);
|
||||
|
||||
/* Decide how many blocks we will be writing */
|
||||
if (block >= 0) {
|
||||
blocks = 1;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* We need to write all data, so calculate the data
|
||||
* size in blocks and set the starting block to zero.
|
||||
*/
|
||||
blocks = datasize;
|
||||
blocks += CHASSIS_BOOT_MBOX_BLOCK_SZ - 1;
|
||||
blocks /= CHASSIS_BOOT_MBOX_BLOCK_SZ;
|
||||
|
||||
block = 0;
|
||||
}
|
||||
|
||||
lprintf(LOG_INFO, "Blocks to write: %d", blocks);
|
||||
|
||||
if (blocks > CHASSIS_BOOT_MBOX_MAX_BLOCKS) {
|
||||
lprintf(LOG_ERR,
|
||||
"Data size %zu exceeds maximum (%d)",
|
||||
datasize,
|
||||
(CHASSIS_BOOT_MBOX_BLOCK_SZ
|
||||
* CHASSIS_BOOT_MBOX_MAX_BLOCKS)
|
||||
- CHASSIS_BOOT_MBOX_IANA_SZ);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Indicate that we're touching the boot parameters */
|
||||
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS);
|
||||
|
||||
for (size_t bindex = 0;
|
||||
datasize > 0 && bindex < blocks;
|
||||
++bindex, ++block)
|
||||
{
|
||||
/* The request data structure */
|
||||
mbox_t mbox = { .block = block, {{0}} };
|
||||
|
||||
/* Destination for input data */
|
||||
uint8_t *data = mbox.data;
|
||||
|
||||
/* The maximum amount of data this block may hold */
|
||||
size_t maxblocksize = sizeof(mbox.data);
|
||||
|
||||
/* The actual amount of data in this block */
|
||||
size_t blocksize;
|
||||
off_t unused = 0;
|
||||
|
||||
/* Block 0 needs special care as it has IANA PEN specifier */
|
||||
if (!block) {
|
||||
data = mbox.b0.data;
|
||||
maxblocksize = sizeof(mbox.b0.data);
|
||||
htoipmi24(iana, mbox.b0.iana);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out how many bytes we are going to write to this
|
||||
* block.
|
||||
*/
|
||||
if (datasize > maxblocksize) {
|
||||
blocksize = maxblocksize;
|
||||
}
|
||||
else {
|
||||
blocksize = datasize;
|
||||
}
|
||||
|
||||
/* Remember how much data remains */
|
||||
datasize -= blocksize;
|
||||
|
||||
if (!use_text) {
|
||||
args2buf(argc, argv, data, blocksize);
|
||||
argc -= blocksize;
|
||||
argv += blocksize;
|
||||
}
|
||||
else {
|
||||
memcpy(data, argv[0] + string_offset, blocksize);
|
||||
string_offset += blocksize;
|
||||
}
|
||||
|
||||
lprintf(LOG_INFO, "Block %3" PRId16 ": %s", block,
|
||||
buf2str_extended(data, blocksize, " "));
|
||||
|
||||
unused = maxblocksize - blocksize;
|
||||
rc = ipmi_chassis_set_bootparam(intf,
|
||||
IPMI_CHASSIS_BOOTPARAM_INIT_MBOX,
|
||||
&mbox,
|
||||
sizeof(mbox) - unused);
|
||||
if (IPMI_CC_PARAM_OUT_OF_RANGE == rc) {
|
||||
lprintf(LOG_ERR,
|
||||
"Hit end of mailbox writing block %" PRId16,
|
||||
block);
|
||||
}
|
||||
if (rc) {
|
||||
goto complete;
|
||||
}
|
||||
}
|
||||
|
||||
lprintf(LOG_INFO,
|
||||
"Wrote %zu blocks of Boot Initiator Mailbox",
|
||||
blocks);
|
||||
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE);
|
||||
|
||||
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK | OS_LOADER_ACK);
|
||||
|
||||
complete:
|
||||
chassis_bootparam_set_in_progress(intf, SET_COMPLETE);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
chassis_get_bootmailbox(struct ipmi_intf *intf,
|
||||
int16_t block, bool use_text)
|
||||
{
|
||||
int rc = IPMI_CC_UNSPECIFIED_ERROR;
|
||||
char param_str[2]; /* Max "7" */
|
||||
char block_str[4]; /* Max "255" */
|
||||
char *bpargv[] = { param_str, block_str };
|
||||
int flags;
|
||||
|
||||
flags = use_text ? BP_FLAG(MBOX_PARSE_USE_TEXT) : 0;
|
||||
|
||||
snprintf(param_str, sizeof(param_str),
|
||||
"%" PRIu8, IPMI_CHASSIS_BOOTPARAM_INIT_MBOX);
|
||||
|
||||
if (block >= 0) {
|
||||
snprintf(block_str, sizeof(block_str),
|
||||
"%" PRIu8, (uint8_t)block);
|
||||
|
||||
rc = ipmi_chassis_get_bootparam(intf,
|
||||
ARRAY_SIZE(bpargv),
|
||||
bpargv,
|
||||
flags);
|
||||
}
|
||||
else {
|
||||
int currblk;
|
||||
|
||||
flags |= BP_FLAG(MBOX_PARSE_ALLBLOCKS);
|
||||
for (currblk = 0; currblk <= UCHAR_MAX; ++currblk) {
|
||||
snprintf(block_str, sizeof(block_str),
|
||||
"%" PRIu8, (uint8_t)currblk);
|
||||
|
||||
if (currblk) {
|
||||
/*
|
||||
* If block 0 succeeded, we don't want to
|
||||
* print generic info for each next block,
|
||||
* and we don't want range error to be
|
||||
* reported when we hit the end of blocks.
|
||||
*/
|
||||
flags |= BP_FLAG(PARAM_NO_GENERIC_INFO);
|
||||
flags |= BP_FLAG(PARAM_NO_RANGE_ERROR);
|
||||
}
|
||||
|
||||
rc = ipmi_chassis_get_bootparam(intf,
|
||||
ARRAY_SIZE(bpargv),
|
||||
bpargv,
|
||||
flags);
|
||||
|
||||
if (rc) {
|
||||
if (currblk) {
|
||||
rc = IPMI_CC_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
chassis_bootmailbox(struct ipmi_intf *intf, int argc, char *argv[])
|
||||
{
|
||||
int rc = IPMI_CC_UNSPECIFIED_ERROR;
|
||||
bool use_text = false; /* Default to data dump I/O mode */
|
||||
int16_t block = -1; /* By default print all blocks */
|
||||
const char *cmd;
|
||||
|
||||
if ((argc < 1) || !strcmp(argv[0], "help")) {
|
||||
chassis_bootmailbox_help();
|
||||
goto out;
|
||||
} else {
|
||||
cmd = argv[0];
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
if (argc > 0 && !strcmp(argv[0], "text")) {
|
||||
use_text = true;
|
||||
++argv;
|
||||
--argc;
|
||||
}
|
||||
|
||||
if (argc > 0 && !strcmp(argv[0], "block")) {
|
||||
if (argc < 2) {
|
||||
chassis_bootmailbox_help();
|
||||
goto out;
|
||||
}
|
||||
if(str2short(argv[1], &block)) {
|
||||
lprintf(LOG_ERR,
|
||||
"Invalid block %s", argv[1]);
|
||||
goto out;
|
||||
}
|
||||
argv += 2;
|
||||
argc -= 2;
|
||||
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "get")) {
|
||||
rc = chassis_get_bootmailbox(intf, block, use_text);
|
||||
}
|
||||
else if (!strcmp(cmd, "set")) {
|
||||
rc = chassis_set_bootmailbox(intf, block, use_text,
|
||||
argc, argv);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy)
|
||||
{
|
||||
@ -1131,7 +1560,10 @@ 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");
|
||||
lprintf(LOG_NOTICE, "Chassis Commands:\n"
|
||||
" status, power, policy, restart_cause\n"
|
||||
" poh, identify, selftest,\n"
|
||||
" bootdev, bootparam, bootmbox");
|
||||
}
|
||||
else if (strncmp(argv[0], "status", 6) == 0) {
|
||||
rc = ipmi_chassis_status(intf);
|
||||
@ -1219,7 +1651,10 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||
}
|
||||
else {
|
||||
if (strncmp(argv[1], "get", 3) == 0) {
|
||||
rc = ipmi_chassis_get_bootparam(intf, argv[2]);
|
||||
rc = ipmi_chassis_get_bootparam(intf,
|
||||
argc - 2,
|
||||
argv + 2,
|
||||
0);
|
||||
}
|
||||
else if (strncmp(argv[1], "set", 3) == 0) {
|
||||
unsigned char set_flag=0;
|
||||
@ -1359,6 +1794,9 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
|
||||
rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(argv[0], "bootmbox")) {
|
||||
rc = chassis_bootmailbox(intf, argc -1, argv + 1);
|
||||
}
|
||||
else {
|
||||
lprintf(LOG_ERR, "Invalid chassis command: %s", argv[0]);
|
||||
return -1;
|
||||
|
@ -1486,6 +1486,7 @@ ipmi_pef2_get_info(struct ipmi_intf *intf)
|
||||
ipmi_pef_print_guid(guid_ptr);
|
||||
}
|
||||
ipmi_pef_print_flags(&pef_b2s_actions, P_SUPP, pcap.actions);
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1537,6 +1538,7 @@ ipmi_pef2_get_status(struct ipmi_intf *intf)
|
||||
return (-1);
|
||||
}
|
||||
ipmi_pef_print_flags(&pef_b2s_actions, P_ACTV, rsp->data[1]);
|
||||
putchar('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,9 @@ 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;
|
||||
|
||||
/* unit description codes (IPMI v1.5 section 37.16) */
|
||||
#define UNIT_MAX 0x90
|
||||
/* IPMI 2.0 Table 43-15, Sensor Unit Type Codes */
|
||||
#define UNIT_TYPE_MAX 92 /* This is the ID of "grams" */
|
||||
#define UNIT_TYPE_LONGEST_NAME 19 /* This is the length of "color temp deg K" */
|
||||
static const char *unit_desc[] = {
|
||||
"unspecified",
|
||||
"degrees C",
|
||||
@ -161,7 +162,9 @@ static const char *unit_desc[] = {
|
||||
"characters",
|
||||
"error",
|
||||
"correctable error",
|
||||
"uncorrectable error"
|
||||
"uncorrectable error",
|
||||
"fatal error",
|
||||
"grams"
|
||||
};
|
||||
|
||||
/* sensor type codes (IPMI v1.5 table 36.3)
|
||||
@ -220,35 +223,60 @@ void printf_sdr_usage();
|
||||
uint16_t
|
||||
ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf);
|
||||
|
||||
/* ipmi_sdr_get_unit_string - return units for base/modifier
|
||||
/** ipmi_sdr_get_unit_string - return units for base/modifier
|
||||
*
|
||||
* @pct: units are a percentage
|
||||
* @type: unit type
|
||||
* @base: base
|
||||
* @modifier: modifier
|
||||
* @param[in] pct Indicates that units are a percentage
|
||||
* @param[in] relation Modifier unit to base unit relation
|
||||
* (SDR_UNIT_MOD_NONE, SDR_UNIT_MOD_MUL,
|
||||
* or SDR_UNIT_MOD_DIV)
|
||||
* @param[in] base The base unit type id
|
||||
* @param[in] modifier The modifier unit type id
|
||||
*
|
||||
* returns pointer to static string
|
||||
* @returns a pointer to static string
|
||||
*/
|
||||
const char *
|
||||
ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifier)
|
||||
ipmi_sdr_get_unit_string(bool pct, uint8_t relation,
|
||||
uint8_t base, uint8_t modifier)
|
||||
{
|
||||
static char unitstr[16];
|
||||
/*
|
||||
* Twice as long as the longest possible unit name, plus
|
||||
* two characters for '%' and relation (either '*' or '/'),
|
||||
* plus the terminating null-byte.
|
||||
*/
|
||||
static char unitstr[2 * UNIT_TYPE_LONGEST_NAME + 2 + 1];
|
||||
|
||||
/*
|
||||
* 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]);
|
||||
const char *pctstr = pct ? "% " : "";
|
||||
const char *basestr;
|
||||
const char *modstr;
|
||||
|
||||
if (base <= UNIT_TYPE_MAX) {
|
||||
basestr = unit_desc[base];
|
||||
}
|
||||
else {
|
||||
basestr = "invalid";
|
||||
}
|
||||
|
||||
if (modifier <= UNIT_TYPE_MAX) {
|
||||
modstr = unit_desc[base];
|
||||
}
|
||||
else {
|
||||
modstr = "invalid";
|
||||
}
|
||||
|
||||
switch (relation) {
|
||||
case SDR_UNIT_MOD_MUL:
|
||||
snprintf(unitstr, sizeof (unitstr), "%s%s*%s",
|
||||
pctstr, basestr, modstr);
|
||||
break;
|
||||
case 1:
|
||||
case SDR_UNIT_MOD_DIV:
|
||||
snprintf(unitstr, sizeof (unitstr), "%s%s/%s",
|
||||
pctstr, unit_desc[base], unit_desc[modifier]);
|
||||
pctstr, basestr, modstr);
|
||||
break;
|
||||
case 0:
|
||||
case SDR_UNIT_MOD_NONE:
|
||||
default:
|
||||
/*
|
||||
* Display the text "percent" only when the Base unit is
|
||||
@ -257,8 +285,8 @@ ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifi
|
||||
if (base == 0 && pct) {
|
||||
snprintf(unitstr, sizeof(unitstr), "percent");
|
||||
} else {
|
||||
snprintf(unitstr, sizeof (unitstr), "%s%s",
|
||||
pctstr, unit_desc[base]);
|
||||
snprintf(unitstr, sizeof (unitstr), "%s%s",
|
||||
pctstr, basestr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -249,6 +249,7 @@ const struct oemvalstr ipmi_oem_product_info[] = {
|
||||
|
||||
/* YADRO */
|
||||
{ IPMI_OEM_YADRO, 0x0001, "VESNIN BMC" },
|
||||
{ IPMI_OEM_YADRO, 0x000A, "TATLIN Storage Controller BMC" },
|
||||
|
||||
{ 0xffffff , 0xffff , NULL },
|
||||
};
|
||||
|
@ -32,11 +32,12 @@ MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ @INTF_USB@
|
||||
DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy usb
|
||||
SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ @INTF_USB@ @INTF_DBUS@
|
||||
DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy usb dbus
|
||||
|
||||
noinst_LTLIBRARIES = libintf.la
|
||||
libintf_la_SOURCES = ipmi_intf.c
|
||||
libintf_la_CFLAGS = -DDEFAULT_INTF='"@DEFAULT_INTF@"'
|
||||
libintf_la_LDFLAGS = -export-dynamic
|
||||
libintf_la_LIBADD = @IPMITOOL_INTF_LIB@
|
||||
libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@
|
||||
|
41
src/plugins/dbus/Makefile.am
Normal file
41
src/plugins/dbus/Makefile.am
Normal file
@ -0,0 +1,41 @@
|
||||
#
|
||||
# Copyright (c) 2015 IBM Corporation
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification,are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. 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.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder 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 HOLDER 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.
|
||||
#
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include
|
||||
|
||||
EXTRA_LTLIBRARIES = libintf_dbus.la
|
||||
noinst_LTLIBRARIES = @INTF_DBUS_LIB@
|
||||
libintf_dbus_la_LDFLAGS = -lsystemd
|
||||
libintf_dbus_la_LIBADD = $(top_builddir)/lib/libipmitool.la
|
||||
libintf_dbus_la_SOURCES = dbus.c
|
||||
|
241
src/plugins/dbus/dbus.c
Normal file
241
src/plugins/dbus/dbus.c
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2015 IBM Corporation
|
||||
* Copyright (c) 2019 Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder 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 HOLDER 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.
|
||||
*/
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
#include <ipmitool/log.h>
|
||||
#include <ipmitool/ipmi.h>
|
||||
#include <ipmitool/ipmi_intf.h>
|
||||
|
||||
static sd_bus *bus;
|
||||
|
||||
static
|
||||
struct ipmi_rs *
|
||||
ipmi_dbus_sendrecv(struct ipmi_intf *intf,
|
||||
struct ipmi_rq *req)
|
||||
{
|
||||
static const char *destination = "xyz.openbmc_project.Ipmi.Host";
|
||||
static const char *object_path = "/xyz/openbmc_project/Ipmi";
|
||||
static const char *interface = "xyz.openbmc_project.Ipmi.Server";
|
||||
static const char *method_name = "execute";
|
||||
static const char SD_BUS_TYPE_3_BYTES[] = {
|
||||
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, 0
|
||||
};
|
||||
static const char SD_BUS_TYPE_4_BYTES[] = {
|
||||
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
|
||||
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, 0
|
||||
};
|
||||
static const char SD_BUS_TYPE_DICT_OF_VARIANTS[] = {
|
||||
SD_BUS_TYPE_ARRAY,
|
||||
SD_BUS_TYPE_DICT_ENTRY_BEGIN,
|
||||
SD_BUS_TYPE_STRING, SD_BUS_TYPE_VARIANT,
|
||||
SD_BUS_TYPE_DICT_ENTRY_END, 0
|
||||
};
|
||||
static const char SD_BUS_TYPE_IPMI_RESPONSE[] = {
|
||||
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
|
||||
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
|
||||
SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_BYTE, 0
|
||||
};
|
||||
|
||||
sd_bus_message *request = NULL;
|
||||
int rc;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus_message* reply = NULL;
|
||||
uint8_t recv_netfn;
|
||||
uint8_t recv_lun;
|
||||
uint8_t recv_cmd;
|
||||
uint8_t recv_cc;
|
||||
const void *data;
|
||||
size_t data_len;
|
||||
static struct ipmi_rs rsp;
|
||||
struct ipmi_rs *ipmi_response = NULL;
|
||||
|
||||
if (!intf->opened || !bus)
|
||||
{
|
||||
goto out_no_free;
|
||||
}
|
||||
|
||||
rsp.ccode = IPMI_CC_UNSPECIFIED_ERROR;
|
||||
rsp.data_len = 0;
|
||||
memset(rsp.data, 0, sizeof(rsp.data));
|
||||
|
||||
/* The D-Bus xyz.openbmc_project.Ipmi.Server.execute interface
|
||||
* looks like this:
|
||||
*
|
||||
* Request:
|
||||
* byte: net function
|
||||
* byte: lun
|
||||
* byte: command
|
||||
* byte array: data (possibly zero length)
|
||||
* array of (string,variant): options
|
||||
* Response:
|
||||
* byte: net function
|
||||
* byte: lun
|
||||
* byte: command
|
||||
* byte: completion code
|
||||
* byte array: response data (possibly zero length)
|
||||
*/
|
||||
rc = sd_bus_message_new_method_call(bus, &request, destination,
|
||||
object_path, interface,
|
||||
method_name);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to create message: %s\n",
|
||||
__func__, strerror(-rc));
|
||||
goto out_no_free;
|
||||
}
|
||||
/* pack the header: netfn, lun, cmd */
|
||||
rc = sd_bus_message_append(request, SD_BUS_TYPE_3_BYTES, req->msg.netfn,
|
||||
req->msg.lun, req->msg.cmd);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to append parameters\n", __func__);
|
||||
goto out_free_request;
|
||||
}
|
||||
/* pack the variable length data */
|
||||
rc = sd_bus_message_append_array(request, SD_BUS_TYPE_BYTE,
|
||||
req->msg.data, req->msg.data_len);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to append body\n", __func__);
|
||||
goto out_free_request;
|
||||
}
|
||||
|
||||
/* Options are only needed for session-based channels, but
|
||||
* in order to fulfill the correct signature, an empty array
|
||||
* must be packed */
|
||||
rc = sd_bus_message_append(request, SD_BUS_TYPE_DICT_OF_VARIANTS,
|
||||
NULL, 0);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to append options\n", __func__);
|
||||
goto out_free_request;
|
||||
}
|
||||
|
||||
rc = sd_bus_call(bus, request, 0, &error, &reply);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to send dbus message (%s)\n",
|
||||
__func__, error.message);
|
||||
goto out_free_request;
|
||||
}
|
||||
|
||||
/* unpack the response; check that it has the expected types */
|
||||
rc = sd_bus_message_enter_container(reply, SD_BUS_TYPE_STRUCT,
|
||||
SD_BUS_TYPE_IPMI_RESPONSE);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to parse reply\n", __func__);
|
||||
goto out_free_reply;
|
||||
}
|
||||
/* read the header: CC netfn lun cmd */
|
||||
rc = sd_bus_message_read(reply, SD_BUS_TYPE_4_BYTES, &recv_netfn,
|
||||
&recv_lun, &recv_cmd, &recv_cc);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to read reply\n", __func__);
|
||||
goto out_free_reply;
|
||||
}
|
||||
/* read the variable length data */
|
||||
rc = sd_bus_message_read_array(reply, SD_BUS_TYPE_BYTE,
|
||||
&data, &data_len);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: failed to read reply data\n", __func__);
|
||||
goto out_free_reply;
|
||||
}
|
||||
rc = sd_bus_message_exit_container(reply);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "%s: final unpack of message failed\n",
|
||||
__func__);
|
||||
goto out_free_reply;
|
||||
}
|
||||
|
||||
if (data_len > sizeof(rsp.data)) {
|
||||
lprintf(LOG_ERR, "%s: data too long!\n", __func__);
|
||||
goto out_free_reply;
|
||||
}
|
||||
|
||||
/* At this point, all the parts are available for a response
|
||||
* other than unspecified error. */
|
||||
rsp.ccode = recv_cc;
|
||||
rsp.data_len = data_len;
|
||||
memcpy(rsp.data, data, data_len);
|
||||
ipmi_response = &rsp;
|
||||
|
||||
out_free_reply:
|
||||
/* message unref will free resources owned by the message */
|
||||
sd_bus_message_unref(reply);
|
||||
out_free_request:
|
||||
sd_bus_message_unref(request);
|
||||
out_no_free:
|
||||
return ipmi_response;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
ipmi_dbus_setup(struct ipmi_intf *intf)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = sd_bus_default_system(&bus);
|
||||
if (rc < 0) {
|
||||
lprintf(LOG_ERR, "Can't connect to session bus: %s\n",
|
||||
strerror(-rc));
|
||||
return -1;
|
||||
}
|
||||
intf->opened = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ipmi_dbus_close(struct ipmi_intf *intf)
|
||||
{
|
||||
if (intf->opened)
|
||||
{
|
||||
sd_bus_close(bus);
|
||||
}
|
||||
intf->opened = 0;
|
||||
}
|
||||
|
||||
struct ipmi_intf ipmi_dbus_intf = {
|
||||
.name = "dbus",
|
||||
.desc = "OpenBMC D-Bus interface",
|
||||
.setup = ipmi_dbus_setup,
|
||||
.close = ipmi_dbus_close,
|
||||
.sendrecv = ipmi_dbus_sendrecv,
|
||||
};
|
||||
|
||||
|
@ -86,6 +86,9 @@ extern struct ipmi_intf ipmi_dummy_intf;
|
||||
#ifdef IPMI_INTF_USB
|
||||
extern struct ipmi_intf ipmi_usb_intf;
|
||||
#endif
|
||||
#ifdef IPMI_INTF_DBUS
|
||||
extern struct ipmi_intf ipmi_dbus_intf;
|
||||
#endif
|
||||
|
||||
struct ipmi_intf * ipmi_intf_table[] = {
|
||||
#ifdef IPMI_INTF_OPEN
|
||||
@ -118,10 +121,33 @@ struct ipmi_intf * ipmi_intf_table[] = {
|
||||
#endif
|
||||
#ifdef IPMI_INTF_USB
|
||||
&ipmi_usb_intf,
|
||||
#endif
|
||||
#ifdef IPMI_INTF_DBUS
|
||||
&ipmi_dbus_intf,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
/* get_default_interface - return the interface that was chosen by configure
|
||||
*
|
||||
* returns a valid interface pointer
|
||||
*/
|
||||
static struct ipmi_intf *get_default_interface(void)
|
||||
{
|
||||
static const char *default_intf_name = DEFAULT_INTF;
|
||||
struct ipmi_intf ** intf;
|
||||
for (intf = ipmi_intf_table; intf && *intf; intf++) {
|
||||
if (!strcmp(default_intf_name, (*intf)->name)) {
|
||||
return *intf;
|
||||
}
|
||||
}
|
||||
/* code should never reach this because the configure script checks
|
||||
* to see that the default interface is actually enabled, but we have
|
||||
* to return some valid value here, so the first entry works
|
||||
*/
|
||||
return ipmi_intf_table[0];
|
||||
}
|
||||
|
||||
/* ipmi_intf_print - Print list of interfaces
|
||||
*
|
||||
* no meaningful return code
|
||||
@ -129,10 +155,11 @@ struct ipmi_intf * ipmi_intf_table[] = {
|
||||
void ipmi_intf_print(struct ipmi_intf_support * intflist)
|
||||
{
|
||||
struct ipmi_intf ** intf;
|
||||
struct ipmi_intf *def_intf;
|
||||
struct ipmi_intf_support * sup;
|
||||
int def = 1;
|
||||
int found;
|
||||
|
||||
def_intf = get_default_interface();
|
||||
lprintf(LOG_NOTICE, "Interfaces:");
|
||||
|
||||
for (intf = ipmi_intf_table; intf && *intf; intf++) {
|
||||
@ -151,8 +178,7 @@ void ipmi_intf_print(struct ipmi_intf_support * intflist)
|
||||
|
||||
lprintf(LOG_NOTICE, "\t%-12s %s %s",
|
||||
(*intf)->name, (*intf)->desc,
|
||||
def ? "[default]" : "");
|
||||
def = 0;
|
||||
def_intf == (*intf) ? "[default]" : "");
|
||||
}
|
||||
lprintf(LOG_NOTICE, "");
|
||||
}
|
||||
@ -171,7 +197,7 @@ struct ipmi_intf * ipmi_intf_load(char * name)
|
||||
struct ipmi_intf * i;
|
||||
|
||||
if (!name) {
|
||||
i = ipmi_intf_table[0];
|
||||
i = get_default_interface();
|
||||
if (i->setup && (i->setup(i) < 0)) {
|
||||
lprintf(LOG_ERR, "Unable to setup "
|
||||
"interface %s", name);
|
||||
|
Reference in New Issue
Block a user