mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-07-02 02:33:37 +00:00
Compare commits
7 Commits
cleanup/nm
...
feature/ad
Author | SHA1 | Date | |
---|---|---|---|
ef92ab51e3 | |||
994d47b415 | |||
90131f19fa | |||
9bc1143e96 | |||
69a44963d0 | |||
ca3a80fef8 | |||
80350a744f |
@ -473,36 +473,94 @@ Force boot into BIOS Setup.
|
|||||||
|
|
||||||
Force boot from Floppy/primary removable media.
|
Force boot from Floppy/primary removable media.
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fIbootparam\fP
|
\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 \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
|
.RS
|
||||||
.TP
|
.IP \fIforce_pxe\fP
|
||||||
\fIforce_pxe\fP
|
|
||||||
|
|
||||||
Force PXE boot
|
Force PXE boot
|
||||||
.TP
|
.IP \fIforce_disk\fP
|
||||||
\fIforce_disk\fP
|
|
||||||
|
|
||||||
Force boot from default Hard-drive
|
Force boot from default Hard-drive
|
||||||
.TP
|
.IP \fIforce_safe\fP
|
||||||
\fIforce_safe\fP
|
|
||||||
|
|
||||||
Force boot from default Hard-drive, request Safe Mode
|
Force boot from default Hard-drive, request Safe Mode
|
||||||
.TP
|
.IP \fIforce_diag\fP
|
||||||
\fIforce_diag\fP
|
|
||||||
|
|
||||||
Force boot from Diagnostic Partition
|
Force boot from Diagnostic Partition
|
||||||
.TP
|
.IP \fIforce_cdrom\fP
|
||||||
\fIforce_cdrom\fP
|
|
||||||
|
|
||||||
Force boot from CD/DVD
|
Force boot from CD/DVD
|
||||||
.TP
|
.IP \fIforce_bios\fP
|
||||||
\fIforce_bios\fP
|
|
||||||
|
|
||||||
Force boot into BIOS Setup
|
Force boot into BIOS Setup
|
||||||
|
|
||||||
|
.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
|
.RE
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fIselftest\fP
|
\fIselftest\fP
|
||||||
|
|
||||||
|
Get the chassis self-test results
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
\fIdcmi\fP
|
\fIdcmi\fP
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h> /* For free() */
|
#include <stdlib.h> /* For free() */
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
|
||||||
@ -79,6 +80,10 @@ struct oemvalstr {
|
|||||||
const char * str;
|
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 * val2str(uint16_t val, const struct valstr * vs);
|
||||||
const char * oemval2str(uint32_t oem,uint16_t val, const struct oemvalstr * 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 str2char(const char * str, int8_t * chr_ptr);
|
||||||
int str2uchar(const char * str, uint8_t * uchr_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 eval_ccode(const int ccode);
|
||||||
|
|
||||||
int is_fru_id(const char *argv_ptr, uint8_t *fru_id_ptr);
|
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;
|
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)
|
static inline uint32_t ipmi32toh(void *ipmi32)
|
||||||
{
|
{
|
||||||
uint8_t *ipmi = ipmi32;
|
uint8_t *ipmi = ipmi32;
|
||||||
|
101
lib/helper.c
101
lib/helper.c
@ -319,26 +319,74 @@ mac2str(const uint8_t *buf)
|
|||||||
return buf2str_extended(buf, 6, ":");
|
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];
|
if (vs) {
|
||||||
int i;
|
for (off_t i = 0; vs[i].str; ++i) {
|
||||||
|
if (vs[i].val == val) {
|
||||||
for (i = 0; vs[i].str; i++) {
|
return i;
|
||||||
if (vs[i].val == val)
|
}
|
||||||
return vs[i].str;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
memset(un_str, 0, 32);
|
||||||
snprintf(un_str, 32, "Unknown (0x%02X)", val);
|
snprintf(un_str, 32, "Unknown (0x%02X)", val);
|
||||||
|
|
||||||
return un_str;
|
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 char * oemval2str(uint32_t oem, uint16_t val,
|
||||||
const struct oemvalstr *vs)
|
const struct oemvalstr *vs)
|
||||||
{
|
{
|
||||||
static char un_str[32];
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; vs[i].oem != 0xffffff && vs[i].str; 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);
|
return unknown_val_str(val);
|
||||||
snprintf(un_str, 32, "Unknown (0x%X)", val);
|
|
||||||
|
|
||||||
return un_str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* str2double - safely convert string to double
|
/* str2double - safely convert string to double
|
||||||
@ -1080,3 +1125,35 @@ ipmi_get_oem_id(struct ipmi_intf *intf)
|
|||||||
|
|
||||||
return oem_id;
|
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 <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include <ipmitool/bswap.h>
|
#include <ipmitool/bswap.h>
|
||||||
#include <ipmitool/helper.h>
|
#include <ipmitool/helper.h>
|
||||||
@ -44,8 +46,40 @@
|
|||||||
#include <ipmitool/ipmi_chassis.h>
|
#include <ipmitool/ipmi_chassis.h>
|
||||||
#include <ipmitool/ipmi_time.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;
|
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
|
int
|
||||||
ipmi_chassis_power_status(struct ipmi_intf * intf)
|
ipmi_chassis_power_status(struct ipmi_intf * intf)
|
||||||
{
|
{
|
||||||
@ -446,61 +480,166 @@ ipmi_chassis_selftest(struct ipmi_intf * intf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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_rs * rsp;
|
||||||
struct ipmi_rq req;
|
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 = malloc(msgsize);
|
||||||
msg_data[0] = param & 0x7f;
|
if (!msg_data) {
|
||||||
memcpy(msg_data+1, data, len);
|
goto out;
|
||||||
|
}
|
||||||
|
memset(msg_data, 0, msgsize);
|
||||||
|
|
||||||
|
msg_data->param = param & BOOTPARAM_MASK;
|
||||||
|
memcpy(msg_data->data, data, len);
|
||||||
|
|
||||||
memset(&req, 0, sizeof(req));
|
memset(&req, 0, sizeof(req));
|
||||||
req.msg.netfn = IPMI_NETFN_CHASSIS;
|
req.msg.netfn = IPMI_NETFN_CHASSIS;
|
||||||
req.msg.cmd = 0x8;
|
req.msg.cmd = 0x8;
|
||||||
req.msg.data = msg_data;
|
req.msg.data = (uint8_t *)msg_data;
|
||||||
req.msg.data_len = len + 1;
|
req.msg.data_len = msgsize;
|
||||||
|
|
||||||
rsp = intf->sendrecv(intf, &req);
|
rsp = intf->sendrecv(intf, &req);
|
||||||
if (!rsp) {
|
if (!rsp) {
|
||||||
lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param);
|
lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (rsp->ccode) {
|
|
||||||
|
rc = rsp->ccode;
|
||||||
|
if (rc) {
|
||||||
if (param != 0) {
|
if (param != 0) {
|
||||||
lprintf(LOG_ERR, "Set Chassis Boot Parameter %d failed: %s",
|
lprintf(LOG_ERR,
|
||||||
param, val2str(rsp->ccode, completion_code_vals));
|
"Set Chassis Boot Parameter %d failed: %s",
|
||||||
|
param,
|
||||||
|
specific_val2str(rsp->ccode,
|
||||||
|
set_bootparam_cc_vals,
|
||||||
|
completion_code_vals));
|
||||||
}
|
}
|
||||||
return rsp->ccode;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len));
|
lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len));
|
||||||
return IPMI_CC_OK;
|
|
||||||
|
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
|
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_rs * rsp;
|
||||||
struct ipmi_rq req;
|
struct ipmi_rq req;
|
||||||
uint8_t msg_data[3];
|
uint8_t msg_data[3];
|
||||||
uint8_t param_id = 0;
|
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)
|
if (argc < 1 || !argv[0]) {
|
||||||
return -1;
|
goto out;
|
||||||
|
|
||||||
if (str2uchar(arg, ¶m_id) != 0) {
|
|
||||||
lprintf(LOG_ERR, "Invalid parameter '%s' given instead of bootparam.",
|
|
||||||
arg);
|
|
||||||
return (-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
memset(msg_data, 0, 3);
|
||||||
|
|
||||||
msg_data[0] = param_id & 0x7f;
|
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));
|
memset(&req, 0, sizeof(req));
|
||||||
req.msg.netfn = IPMI_NETFN_CHASSIS;
|
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);
|
rsp = intf->sendrecv(intf, &req);
|
||||||
if (!rsp) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
if (rsp->ccode) {
|
if (rsp->ccode) {
|
||||||
lprintf(LOG_ERR, "Get Chassis Boot Parameter %s failed: %s",
|
lprintf(LOG_ERR,
|
||||||
arg, val2str(rsp->ccode, completion_code_vals));
|
"Get Chassis Boot Parameter %" PRIu8 " failed: %s",
|
||||||
|
msg_data[0],
|
||||||
|
specific_val2str(rsp->ccode,
|
||||||
|
get_bootparam_cc_vals,
|
||||||
|
completion_code_vals));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,10 +673,17 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
|
|||||||
param_id = 0;
|
param_id = 0;
|
||||||
param_id = (rsp->data[1] & 0x7f);
|
param_id = (rsp->data[1] & 0x7f);
|
||||||
|
|
||||||
printf("Boot parameter version: %d\n", rsp->data[0]);
|
if (!skip_generic) {
|
||||||
printf("Boot parameter %d is %s\n", rsp->data[1] & 0x7f,
|
printf("Boot parameter version: %d\n", rsp->data[0]);
|
||||||
(rsp->data[1] & 0x80) ? "invalid/locked" : "valid/unlocked");
|
printf("Boot parameter %d is %s\n", rsp->data[1] & 0x7f,
|
||||||
printf("Boot parameter data: %s\n", buf2str(rsp->data+2, rsp->data_len - 2));
|
(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)
|
switch(param_id)
|
||||||
{
|
{
|
||||||
@ -716,17 +871,18 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
{
|
chassis_bootmailbox_parse(rsp->data + 2,
|
||||||
printf(" Selector : %d\n", rsp->data[2] );
|
rsp->data_len - 2,
|
||||||
printf(" Block Data : %s\n", buf2str(rsp->data+3, rsp->data_len - 2));
|
flags);
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
printf(" Undefined byte\n");
|
printf(" Unsupported parameter %" PRIu8 "\n", param_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
rc = IPMI_CC_OK;
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -832,7 +988,10 @@ ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
|
|||||||
}
|
}
|
||||||
if (rsp->ccode) {
|
if (rsp->ccode) {
|
||||||
lprintf(LOG_ERR, "Get Chassis Boot Parameter %d failed: %s",
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1001,6 +1160,296 @@ out:
|
|||||||
return rc;
|
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
|
static int
|
||||||
ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy)
|
ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy)
|
||||||
{
|
{
|
||||||
@ -1111,7 +1560,10 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if ((argc == 0) || (strncmp(argv[0], "help", 4) == 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) {
|
else if (strncmp(argv[0], "status", 6) == 0) {
|
||||||
rc = ipmi_chassis_status(intf);
|
rc = ipmi_chassis_status(intf);
|
||||||
@ -1199,7 +1651,10 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (strncmp(argv[1], "get", 3) == 0) {
|
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) {
|
else if (strncmp(argv[1], "set", 3) == 0) {
|
||||||
unsigned char set_flag=0;
|
unsigned char set_flag=0;
|
||||||
@ -1339,6 +1794,9 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
|
|||||||
rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
|
rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(argv[0], "bootmbox")) {
|
||||||
|
rc = chassis_bootmailbox(intf, argc -1, argv + 1);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
lprintf(LOG_ERR, "Invalid chassis command: %s", argv[0]);
|
lprintf(LOG_ERR, "Invalid chassis command: %s", argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
Reference in New Issue
Block a user