mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-07-01 18:23:36 +00:00
Compare commits
7 Commits
master
...
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.
|
||||
.RE
|
||||
|
||||
.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
|
||||
.TP
|
||||
\fIforce_pxe\fP
|
||||
.IP \fIforce_pxe\fP
|
||||
|
||||
Force PXE boot
|
||||
.TP
|
||||
\fIforce_disk\fP
|
||||
.IP \fIforce_disk\fP
|
||||
|
||||
Force boot from default Hard-drive
|
||||
.TP
|
||||
\fIforce_safe\fP
|
||||
.IP \fIforce_safe\fP
|
||||
|
||||
Force boot from default Hard-drive, request Safe Mode
|
||||
.TP
|
||||
\fIforce_diag\fP
|
||||
.IP \fIforce_diag\fP
|
||||
|
||||
Force boot from Diagnostic Partition
|
||||
.TP
|
||||
\fIforce_cdrom\fP
|
||||
.IP \fIforce_cdrom\fP
|
||||
|
||||
Force boot from CD/DVD
|
||||
.TP
|
||||
\fIforce_bios\fP
|
||||
.IP \fIforce_bios\fP
|
||||
|
||||
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
|
||||
|
||||
.TP
|
||||
\fIselftest\fP
|
||||
|
||||
Get the chassis self-test results
|
||||
|
||||
.RE
|
||||
.TP
|
||||
\fIdcmi\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;
|
||||
|
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 rsp->ccode;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
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");
|
||||
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)
|
||||
{
|
||||
@ -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));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1001,6 +1160,296 @@ out:
|
||||
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)
|
||||
{
|
||||
@ -1111,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);
|
||||
@ -1199,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;
|
||||
@ -1339,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;
|
||||
|
Reference in New Issue
Block a user