From 6c00d448d58ecbad7725a0430b9c804e4c09cb45 Mon Sep 17 00:00:00 2001 From: Alexander Amelkin Date: Sun, 17 Jun 2018 01:09:58 +0300 Subject: [PATCH] mc: watchdog get: Update to match IPMI 2.0 spec * Add output of "don't log" and "pre-timeout interrupt" fields * Display timers with 100ms precision * List timer use expiration flags as text, not just numerically Signed-off-by: Alexander Amelkin --- include/ipmitool/helper.h | 15 ++++++++++++++ include/ipmitool/ipmi_mc.h | 33 +++++++++++++++++++++++-------- lib/ipmi_mc.c | 40 +++++++++++++++++++++++++++++--------- 3 files changed, 71 insertions(+), 17 deletions(-) diff --git a/include/ipmitool/helper.h b/include/ipmitool/helper.h index bfaf284..7d81e92 100644 --- a/include/ipmitool/helper.h +++ b/include/ipmitool/helper.h @@ -109,6 +109,21 @@ FILE * ipmi_open_file(const char * file, int rw); void ipmi_start_daemon(struct ipmi_intf *intf); uint16_t ipmi_get_oem_id(struct ipmi_intf *intf); +#define IS_SET(v, b) ((v) & (1 << (b))) + +/* le16toh() doesn't exist for Windows or Apple */ +/* For portability, let's simply define our own version of it here */ +static inline uint16_t ipmi16toh(uint16_t le) +{ + uint8_t *data = (uint8_t *)≤ + uint16_t h; + + h = data[1] << 8; /* MSB */ + h |= data[0]; /* LSB */ + + return h; +} + #define ipmi_open_file_read(file) ipmi_open_file(file, 0) #define ipmi_open_file_write(file) ipmi_open_file(file, 1) diff --git a/include/ipmitool/ipmi_mc.h b/include/ipmitool/ipmi_mc.h index 0918f22..902b42c 100644 --- a/include/ipmitool/ipmi_mc.h +++ b/include/ipmitool/ipmi_mc.h @@ -34,6 +34,7 @@ #define IPMI_MC_H #include +#include #define BMC_GET_DEVICE_ID 0x01 #define BMC_COLD_RESET 0x02 @@ -138,14 +139,24 @@ struct ipm_selftest_rsp { #pragma pack(1) #endif struct ipm_get_watchdog_rsp { - unsigned char timer_use; - unsigned char timer_actions; + unsigned char use; + unsigned char intr_action; unsigned char pre_timeout; - unsigned char timer_use_exp; - unsigned char initial_countdown_lsb; - unsigned char initial_countdown_msb; - unsigned char present_countdown_lsb; - unsigned char present_countdown_msb; + unsigned char exp_flags; + union { + struct { + unsigned char initial_countdown_lsb; + unsigned char initial_countdown_msb; + }; + uint16_t init_cnt_le; + }; + union { + struct { + unsigned char present_countdown_lsb; + unsigned char present_countdown_msb; + }; + uint16_t pres_cnt_le; + }; } ATTRIBUTE_PACKING; #ifdef HAVE_PRAGMA_PACK #pragma pack(0) @@ -172,7 +183,9 @@ struct ipm_get_watchdog_rsp { /* Use */ #define IPMI_WDT_USE_NOLOG_SHIFT 7 -#define IPMI_WDT_USE_DONTSTOP_SHIFT 6 +#define IPMI_WDT_USE_DONTSTOP_SHIFT 6 /* For 'set' */ +#define IPMI_WDT_USE_RUNNING_SHIFT 6 /* For 'get' */ +#define IPMI_WDT_USE_SHIFT 0 #define IPMI_WDT_USE_MASK 0x07 /* Pre-timeout interrupt type */ @@ -180,8 +193,12 @@ struct ipm_get_watchdog_rsp { #define IPMI_WDT_INTR_MASK 0x07 /* Apply to the intr value, not to the data byte */ /* Action */ +#define IPMI_WDT_ACTION_SHIFT 0 #define IPMI_WDT_ACTION_MASK 0x07 +#define IPMI_WDT_GET(b, s) (((b) >> (IPMI_WDT_##s##_SHIFT)) & (IPMI_WDT_##s##_MASK)) + +#define IS_WDT_BIT(b, s) IS_SET((b), IPMI_WDT_##s##_SHIFT) /* IPMI 2.0 command for system information*/ #define IPMI_SET_SYS_INFO 0x58 diff --git a/lib/ipmi_mc.c b/lib/ipmi_mc.c index 78fba9a..2f8d19a 100644 --- a/lib/ipmi_mc.c +++ b/lib/ipmi_mc.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -720,6 +721,9 @@ ipmi_mc_get_watchdog(struct ipmi_intf * intf) struct ipmi_rs * rsp; struct ipmi_rq req; struct ipm_get_watchdog_rsp * wdt_res; + double init_cnt; + double pres_cnt; + int i; memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_APP; @@ -740,18 +744,36 @@ ipmi_mc_get_watchdog(struct ipmi_intf * intf) wdt_res = (struct ipm_get_watchdog_rsp *) rsp->data; + /* Convert 100ms intervals to seconds */ + init_cnt = (double)ipmi16toh(wdt_res->init_cnt_le) / 10.0; + pres_cnt = (double)ipmi16toh(wdt_res->pres_cnt_le) / 10.0; + printf("Watchdog Timer Use: %s (0x%02x)\n", - wdt_use[(wdt_res->timer_use & 0x07 )]->get, wdt_res->timer_use); + wdt_use[IPMI_WDT_GET(wdt_res->use, USE)]->get, wdt_res->use); printf("Watchdog Timer Is: %s\n", - wdt_res->timer_use & 0x40 ? "Started/Running" : "Stopped"); - printf("Watchdog Timer Actions: %s (0x%02x)\n", - wdt_action[(wdt_res->timer_actions&0x07)]->get, wdt_res->timer_actions); + IS_WDT_BIT(wdt_res->use, USE_RUNNING) + ? "Started/Running" + : "Stopped"); + printf("Watchdog Timer Logging: %s\n", + IS_WDT_BIT(wdt_res->use, USE_NOLOG) + ? "Off" + : "On"); + printf("Watchdog Timer Action: %s (0x%02x)\n", + wdt_action[IPMI_WDT_GET(wdt_res->intr_action, ACTION)]->get, + wdt_res->intr_action); + printf("Pre-timeout interrupt: %s\n", + wdt_int[IPMI_WDT_GET(wdt_res->intr_action, INTR)]->get); printf("Pre-timeout interval: %d seconds\n", wdt_res->pre_timeout); - printf("Timer Expiration Flags: 0x%02x\n", wdt_res->timer_use_exp); - printf("Initial Countdown: %i sec\n", - ((wdt_res->initial_countdown_msb << 8) | wdt_res->initial_countdown_lsb)/10); - printf("Present Countdown: %i sec\n", - (((wdt_res->present_countdown_msb << 8) | wdt_res->present_countdown_lsb)) / 10); + printf("Timer Expiration Flags: %s(0x%02x)\n", + wdt_res->exp_flags ? "" : "None ", + wdt_res->exp_flags); + for (i = 0; i < sizeof(wdt_res->exp_flags) * CHAR_BIT; ++i) { + if (IS_SET(wdt_res->exp_flags, i)) { + printf(" * %s\n", wdt_use[i]->get); + } + } + printf("Initial Countdown: %0.1f sec\n", init_cnt); + printf("Present Countdown: %0.1f sec\n", pres_cnt); return 0; }