diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:00 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:00 +0200 |
commit | b32d92e890caac903491116e9d817aa780c0323b (patch) | |
tree | 5a135c37eaa9ac94772819a28ce5beedd18e5c4a /lib/ipmi_mc.c | |
parent | c3445516ecd58e97de483cf4b7fafcc1104890d7 (diff) |
Imported Upstream version 1.8.14upstream/1.8.14
Diffstat (limited to 'lib/ipmi_mc.c')
-rw-r--r-- | lib/ipmi_mc.c | 1112 |
1 files changed, 1112 insertions, 0 deletions
diff --git a/lib/ipmi_mc.c b/lib/ipmi_mc.c new file mode 100644 index 0000000..2890c90 --- /dev/null +++ b/lib/ipmi_mc.c @@ -0,0 +1,1112 @@ +/* + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <time.h> + +#include <ipmitool/helper.h> +#include <ipmitool/log.h> +#include <ipmitool/bswap.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_mc.h> +#include <ipmitool/ipmi_strings.h> + +extern int verbose; + +static int ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv, + int is_set); +static void printf_sysinfo_usage(int full_help); + +/* ipmi_mc_reset - attempt to reset an MC + * + * @intf: ipmi interface + * @cmd: reset command to send + * BMC_WARM_RESET or + * BMC_COLD_RESET + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_mc_reset(struct ipmi_intf * intf, int cmd) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + + if( !intf->opened ) + intf->open(intf); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = cmd; + req.msg.data_len = 0; + + if (cmd == BMC_COLD_RESET) + intf->noanswer = 1; + + rsp = intf->sendrecv(intf, &req); + + if (cmd == BMC_COLD_RESET) + intf->abort = 1; + + if (cmd == BMC_COLD_RESET && rsp == NULL) { + /* This is expected. See 20.2 Cold Reset Command, p.243, IPMIv2.0 rev1.0 */ + } else if (rsp == NULL) { + lprintf(LOG_ERR, "MC reset command failed."); + return (-1); + } else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "MC reset command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return (-1); + } + + printf("Sent %s reset command to MC\n", + (cmd == BMC_WARM_RESET) ? "warm" : "cold"); + + return 0; +} + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct bmc_enables_data { +#if WORDS_BIGENDIAN + uint8_t oem2 : 1; + uint8_t oem1 : 1; + uint8_t oem0 : 1; + uint8_t __reserved : 1; + uint8_t system_event_log : 1; + uint8_t event_msgbuf : 1; + uint8_t event_msgbuf_intr : 1; + uint8_t receive_msg_intr : 1; +#else + uint8_t receive_msg_intr : 1; + uint8_t event_msgbuf_intr : 1; + uint8_t event_msgbuf : 1; + uint8_t system_event_log : 1; + uint8_t __reserved : 1; + uint8_t oem0 : 1; + uint8_t oem1 : 1; + uint8_t oem2 : 1; +#endif +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +struct bitfield_data { + const char * name; + const char * desc; + uint32_t mask; +}; + +struct bitfield_data mc_enables_bf[] = { + { + name: "recv_msg_intr", + desc: "Receive Message Queue Interrupt", + mask: 1<<0, + }, + { + name: "event_msg_intr", + desc: "Event Message Buffer Full Interrupt", + mask: 1<<1, + }, + { + name: "event_msg", + desc: "Event Message Buffer", + mask: 1<<2, + }, + { + name: "system_event_log", + desc: "System Event Logging", + mask: 1<<3, + }, + { + name: "oem0", + desc: "OEM 0", + mask: 1<<5, + }, + { + name: "oem1", + desc: "OEM 1", + mask: 1<<6, + }, + { + name: "oem2", + desc: "OEM 2", + mask: 1<<7, + }, + { NULL }, +}; + +static void +printf_mc_reset_usage(void) +{ + lprintf(LOG_NOTICE, "usage: mc reset <warm|cold>"); +} /* printf_mc_reset_usage(void) */ + +static void +printf_mc_usage(void) +{ + struct bitfield_data * bf; + lprintf(LOG_NOTICE, "MC Commands:"); + lprintf(LOG_NOTICE, " reset <warm|cold>"); + lprintf(LOG_NOTICE, " guid"); + lprintf(LOG_NOTICE, " info"); + lprintf(LOG_NOTICE, " watchdog <get|reset|off>"); + lprintf(LOG_NOTICE, " selftest"); + lprintf(LOG_NOTICE, " getenables"); + lprintf(LOG_NOTICE, " setenables <option=on|off> ..."); + for (bf = mc_enables_bf; bf->name != NULL; bf++) { + lprintf(LOG_NOTICE, " %-20s %s", bf->name, bf->desc); + } + printf_sysinfo_usage(0); +} + +static void +printf_sysinfo_usage(int full_help) +{ + if (full_help != 0) + lprintf(LOG_NOTICE, "usage:"); + + lprintf(LOG_NOTICE, " getsysinfo <argument>"); + + if (full_help != 0) { + lprintf(LOG_NOTICE, + " Retrieves system info from BMC for given argument"); + } + + lprintf(LOG_NOTICE, " setsysinfo <argument> <string>"); + + if (full_help != 0) { + lprintf(LOG_NOTICE, + " Stores system info string for given argument to BMC"); + lprintf(LOG_NOTICE, ""); + lprintf(LOG_NOTICE, " Valid arguments are:"); + } + lprintf(LOG_NOTICE, + " primary_os_name Primary operating system name"); + lprintf(LOG_NOTICE, " os_name Operating system name"); + lprintf(LOG_NOTICE, + " system_name System Name of server(vendor dependent)"); + lprintf(LOG_NOTICE, + " delloem_os_version Running version of operating system"); + lprintf(LOG_NOTICE, " delloem_url URL of BMC webserver"); + lprintf(LOG_NOTICE, ""); +} + +static void +print_watchdog_usage(void) +{ + lprintf(LOG_NOTICE, "usage: watchdog <command>:"); + lprintf(LOG_NOTICE, " get : Get Current Watchdog settings"); + lprintf(LOG_NOTICE, " reset : Restart Watchdog timer based on most recent settings"); + lprintf(LOG_NOTICE, " off : Shut off a running Watchdog timer"); +} + +/* ipmi_mc_get_enables - print out MC enables + * + * @intf: ipmi inteface + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_mc_get_enables(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct bitfield_data * bf; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_GLOBAL_ENABLES; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get Global Enables command failed"); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get Global Enables command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + for (bf = mc_enables_bf; bf->name != NULL; bf++) { + printf("%-40s : %sabled\n", bf->desc, + rsp->data[0] & bf->mask ? "en" : "dis"); + } + + return 0; +} + +/* ipmi_mc_set_enables - set MC enable flags + * + * @intf: ipmi inteface + * @argc: argument count + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_mc_set_enables(struct ipmi_intf * intf, int argc, char ** argv) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct bitfield_data * bf; + uint8_t en; + int i; + + if (argc < 1) { + printf_mc_usage(); + return (-1); + } + else if (strncmp(argv[0], "help", 4) == 0) { + printf_mc_usage(); + return 0; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_GLOBAL_ENABLES; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get Global Enables command failed"); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get Global Enables command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + en = rsp->data[0]; + + for (i = 0; i < argc; i++) { + for (bf = mc_enables_bf; bf->name != NULL; bf++) { + int nl = strlen(bf->name); + if (strncmp(argv[i], bf->name, nl) != 0) + continue; + if (strncmp(argv[i]+nl+1, "off", 3) == 0) { + printf("Disabling %s\n", bf->desc); + en &= ~bf->mask; + } + else if (strncmp(argv[i]+nl+1, "on", 2) == 0) { + printf("Enabling %s\n", bf->desc); + en |= bf->mask; + } + else { + lprintf(LOG_ERR, "Unrecognized option: %s", argv[i]); + } + } + } + + if (en == rsp->data[0]) { + printf("\nNothing to change...\n"); + ipmi_mc_get_enables(intf); + return 0; + } + + req.msg.cmd = BMC_SET_GLOBAL_ENABLES; + req.msg.data = &en; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Set Global Enables command failed"); + return -1; + } + else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Global Enables command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + printf("\nVerifying...\n"); + ipmi_mc_get_enables(intf); + + return 0; +} + +/* IPM Device, Get Device ID Command - Additional Device Support */ +const char *ipm_dev_adtl_dev_support[8] = { + "Sensor Device", /* bit 0 */ + "SDR Repository Device", /* bit 1 */ + "SEL Device", /* bit 2 */ + "FRU Inventory Device", /* ... */ + "IPMB Event Receiver", + "IPMB Event Generator", + "Bridge", + "Chassis Device" /* bit 7 */ +}; + +/* ipmi_mc_get_deviceid - print information about this MC + * + * @intf: ipmi interface + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_mc_get_deviceid(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipm_devid_rsp *devid; + int i; + const char *product=NULL; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_DEVICE_ID; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get Device ID command failed"); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get Device ID command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + devid = (struct ipm_devid_rsp *) rsp->data; + printf("Device ID : %i\n", + devid->device_id); + printf("Device Revision : %i\n", + devid->device_revision & IPM_DEV_DEVICE_ID_REV_MASK); + printf("Firmware Revision : %u.%02x\n", + devid->fw_rev1 & IPM_DEV_FWREV1_MAJOR_MASK, + devid->fw_rev2); + printf("IPMI Version : %x.%x\n", + IPM_DEV_IPMI_VERSION_MAJOR(devid->ipmi_version), + IPM_DEV_IPMI_VERSION_MINOR(devid->ipmi_version)); + printf("Manufacturer ID : %lu\n", + (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id)); + printf("Manufacturer Name : %s\n", + val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id), + ipmi_oem_info) ); + + printf("Product ID : %u (0x%02x%02x)\n", + buf2short((uint8_t *)(devid->product_id)), + devid->product_id[1], devid->product_id[0]); + + product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id), + (devid->product_id[1]<<8)+devid->product_id[0], + ipmi_oem_product_info); + + if (product!=NULL) { + printf("Product Name : %s\n", product); + } + + printf("Device Available : %s\n", + (devid->fw_rev1 & IPM_DEV_FWREV1_AVAIL_MASK) ? + "no" : "yes"); + printf("Provides Device SDRs : %s\n", + (devid->device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) ? + "yes" : "no"); + printf("Additional Device Support :\n"); + for (i = 0; i < IPM_DEV_ADTL_SUPPORT_BITS; i++) { + if (devid->adtl_device_support & (1 << i)) { + printf(" %s\n", ipm_dev_adtl_dev_support[i]); + } + } + if (rsp->data_len == sizeof(*devid)) { + printf("Aux Firmware Rev Info : \n"); + /* These values could be looked-up by vendor if documented, + * so we put them on individual lines for better treatment later + */ + printf(" 0x%02x\n 0x%02x\n 0x%02x\n 0x%02x\n", + devid->aux_fw_rev[0], + devid->aux_fw_rev[1], + devid->aux_fw_rev[2], + devid->aux_fw_rev[3]); + } + return 0; +} + +/* Structure follow the IPMI V.2 Rev 1.0 + * See Table 20-10 */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif + +struct ipmi_guid { + uint32_t time_low; /* timestamp low field */ + uint16_t time_mid; /* timestamp middle field */ + uint16_t time_hi_and_version; /* timestamp high field and version number */ + uint8_t clock_seq_hi_variant;/* clock sequence high field and variant */ + uint8_t clock_seq_low; /* clock sequence low field */ + uint8_t node[6]; /* node */ +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +/* ipmi_mc_get_guid - print this MC GUID + * + * @intf: ipmi interface + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_mc_get_guid(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipmi_guid guid; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_GUID; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get GUID command failed"); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get GUID command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + if (rsp->data_len == sizeof(struct ipmi_guid)) { + char tbuf[40]; + time_t s; + memset(tbuf, 0, 40); + memset(&guid, 0, sizeof(struct ipmi_guid)); + memcpy(&guid, rsp->data, rsp->data_len); + + /* Kipp - changed order of last field (node) to follow specification */ + printf("System GUID : %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n", + guid.time_low, guid.time_mid, guid.time_hi_and_version, + guid.clock_seq_hi_variant << 8 | guid.clock_seq_low, + guid.node[0], guid.node[1], guid.node[2], + guid.node[3], guid.node[4], guid.node[5]); + + s = (time_t)guid.time_low; /* Kipp - removed the BSWAP_32, it was not needed here */ + strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", localtime(&s)); + printf("Timestamp : %s\n", tbuf); + } + else { + lprintf(LOG_ERR, "Invalid GUID length %d", rsp->data_len); + } + + return 0; +} + +/* ipmi_mc_get_selftest - returns and print selftest results + * + * @intf: ipmi interface + */ +static int ipmi_mc_get_selftest(struct ipmi_intf * intf) +{ + int rv = 0; + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipm_selftest_rsp *sft_res; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_SELF_TEST; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (!rsp) { + lprintf(LOG_ERR, "No response from devices\n"); + return -1; + } + + if (rsp->ccode) { + lprintf(LOG_ERR, "Bad response: (%s)", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + sft_res = (struct ipm_selftest_rsp *) rsp->data; + + if (sft_res->code == IPM_SFT_CODE_OK) { + printf("Selftest: passed\n"); + rv = 0; + } + + else if (sft_res->code == IPM_SFT_CODE_NOT_IMPLEMENTED) { + printf("Selftest: not implemented\n"); + rv = -1; + } + + else if (sft_res->code == IPM_SFT_CODE_DEV_CORRUPTED) { + printf("Selftest: device corrupted\n"); + rv = -1; + + if (sft_res->test & IPM_SELFTEST_SEL_ERROR) { + printf(" -> SEL device not accessible\n"); + } + if (sft_res->test & IPM_SELFTEST_SDR_ERROR) { + printf(" -> SDR repository not accesible\n"); + } + if (sft_res->test & IPM_SELFTEST_FRU_ERROR) { + printf("FRU device not accessible\n"); + } + if (sft_res->test & IPM_SELFTEST_IPMB_ERROR) { + printf("IPMB signal lines do not respond\n"); + } + if (sft_res->test & IPM_SELFTEST_SDRR_EMPTY) { + printf("SDR repository empty\n"); + } + if (sft_res->test & IPM_SELFTEST_INTERNAL_USE) { + printf("Internal Use Area corrupted\n"); + } + if (sft_res->test & IPM_SELFTEST_FW_BOOTBLOCK) { + printf("Controller update boot block corrupted\n"); + } + if (sft_res->test & IPM_SELFTEST_FW_CORRUPTED) { + printf("controller operational firmware corrupted\n"); + } + } + + else if (sft_res->code == IPM_SFT_CODE_FATAL_ERROR) { + printf("Selftest : fatal error\n"); + printf("Failure code : %02x\n", sft_res->test); + rv = -1; + } + + else if (sft_res->code == IPM_SFT_CODE_RESERVED) { + printf("Selftest: N/A"); + rv = -1; + } + + else { + printf("Selftest : device specific (%02Xh)\n", sft_res->code); + printf("Failure code : %02Xh\n", sft_res->test); + rv = 0; + } + + return rv; +} + +/* ipmi_mc_get_watchdog + * + * @intf: ipmi interface + * + * returns 0 on success + * returns -1 on error + */ + +const char *wdt_use_string[8] = { + "Reserved", + "BIOS FRB2", + "BIOS/POST", + "OS Load", + "SMS/OS", + "OEM", + "Reserved", + "Reserved" +}; + +const char *wdt_action_string[8] = { + "No action", + "Hard Reset", + "Power Down", + "Power Cycle", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +static int +ipmi_mc_get_watchdog(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipm_get_watchdog_rsp * wdt_res; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_WATCHDOG_TIMER; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get Watchdog Timer command failed"); + return -1; + } + + if (rsp->ccode) { + lprintf(LOG_ERR, "Get Watchdog Timer command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + wdt_res = (struct ipm_get_watchdog_rsp *) rsp->data; + + printf("Watchdog Timer Use: %s (0x%02x)\n", + wdt_use_string[(wdt_res->timer_use & 0x07 )], wdt_res->timer_use); + printf("Watchdog Timer Is: %s\n", + wdt_res->timer_use & 0x40 ? "Started/Running" : "Stopped"); + printf("Watchdog Timer Actions: %s (0x%02x)\n", + wdt_action_string[(wdt_res->timer_actions&0x07)], wdt_res->timer_actions); + printf("Pre-timeout interval: %d seconds\n", wdt_res->pre_timeout); + printf("Timer Expiration Flags: 0x%02x\n", wdt_res->timer_use_exp); + printf("Initial Countdown: %i sec\n", + ((wdt_res->initial_countdown_msb << 8) | wdt_res->initial_countdown_lsb)/10); + printf("Present Countdown: %i sec\n", + (((wdt_res->present_countdown_msb << 8) | wdt_res->present_countdown_lsb)) / 10); + + return 0; +} + +/* ipmi_mc_shutoff_watchdog + * + * @intf: ipmi interface + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_mc_shutoff_watchdog(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_SET_WATCHDOG_TIMER; + req.msg.data = msg_data; + req.msg.data_len = 6; + + /* + * The only set cmd we're allowing is to shut off the timer. + * Turning on the timer should be the job of the ipmi watchdog driver. + * See 'modinfo ipmi_watchdog' for more info. (NOTE: the reset + * command will restart the timer if it's already been initialized.) + * + * Out-of-band watchdog set commands can still be sent via the raw + * command interface but this is a very dangerous thing to do since + * a periodic "poke"/reset over a network is unreliable. This is + * not a recommended way to use the IPMI watchdog commands. + */ + + msg_data[0] = IPM_WATCHDOG_SMS_OS; + msg_data[1] = IPM_WATCHDOG_NO_ACTION; + msg_data[2] = 0x00; /* pretimeout interval */ + msg_data[3] = IPM_WATCHDOG_CLEAR_SMS_OS; + msg_data[4] = 0xb8; /* countdown lsb (100 ms/count) */ + msg_data[5] = 0x0b; /* countdown msb - 5 mins */ + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed!"); + return -1; + } + + if (rsp->ccode) { + lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed! %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + printf("Watchdog Timer Shutoff successful -- timer stopped\n"); + return 0; +} + + +/* ipmi_mc_rst_watchdog + * + * @intf: ipmi interface + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_mc_rst_watchdog(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_RESET_WATCHDOG_TIMER; + req.msg.data_len = 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Reset Watchdog Timer command failed!"); + return -1; + } + + if (rsp->ccode) { + lprintf(LOG_ERR, "Reset Watchdog Timer command failed: %s", + (rsp->ccode == IPM_WATCHDOG_RESET_ERROR) ? + "Attempt to reset unitialized watchdog" : + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + printf("IPMI Watchdog Timer Reset - countdown restarted!\n"); + return 0; +} + +/* ipmi_mc_main - top-level handler for MC functions + * + * @intf: ipmi interface + * @argc: number of arguments + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +int +ipmi_mc_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + int rc = 0; + + if (argc < 1) { + lprintf(LOG_ERR, "Not enough parameters given."); + printf_mc_usage(); + rc = (-1); + } + else if (strncmp(argv[0], "help", 4) == 0) { + printf_mc_usage(); + rc = 0; + } + else if (strncmp(argv[0], "reset", 5) == 0) { + if (argc < 2) { + lprintf(LOG_ERR, "Not enough parameters given."); + printf_mc_reset_usage(); + rc = (-1); + } + else if (strncmp(argv[1], "help", 4) == 0) { + printf_mc_reset_usage(); + rc = 0; + } + else if (strncmp(argv[1], "cold", 4) == 0) { + rc = ipmi_mc_reset(intf, BMC_COLD_RESET); + } + else if (strncmp(argv[1], "warm", 4) == 0) { + rc = ipmi_mc_reset(intf, BMC_WARM_RESET); + } + else { + lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]); + printf_mc_reset_usage(); + rc = (-1); + } + } + else if (strncmp(argv[0], "info", 4) == 0) { + rc = ipmi_mc_get_deviceid(intf); + } + else if (strncmp(argv[0], "guid", 4) == 0) { + rc = ipmi_mc_get_guid(intf); + } + else if (strncmp(argv[0], "getenables", 10) == 0) { + rc = ipmi_mc_get_enables(intf); + } + else if (strncmp(argv[0], "setenables", 10) == 0) { + rc = ipmi_mc_set_enables(intf, argc-1, &(argv[1])); + } + else if (!strncmp(argv[0], "selftest", 8)) { + rc = ipmi_mc_get_selftest(intf); + } + else if (!strncmp(argv[0], "watchdog", 8)) { + if (argc < 2) { + lprintf(LOG_ERR, "Not enough parameters given."); + print_watchdog_usage(); + rc = (-1); + } + else if (strncmp(argv[1], "help", 4) == 0) { + print_watchdog_usage(); + rc = 0; + } + else if (strncmp(argv[1], "get", 3) == 0) { + rc = ipmi_mc_get_watchdog(intf); + } + else if(strncmp(argv[1], "off", 3) == 0) { + rc = ipmi_mc_shutoff_watchdog(intf); + } + else if(strncmp(argv[1], "reset", 5) == 0) { + rc = ipmi_mc_rst_watchdog(intf); + } + else { + lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]); + print_watchdog_usage(); + rc = (-1); + } + } + else if (strncmp(argv[0], "getsysinfo", 10) == 0) { + rc = ipmi_sysinfo_main(intf, argc, argv, 0); + } + else if (strncmp(argv[0], "setsysinfo", 10) == 0) { + rc = ipmi_sysinfo_main(intf, argc, argv, 1); + } + else { + lprintf(LOG_ERR, "Invalid mc/bmc command: %s", argv[0]); + printf_mc_usage(); + rc = (-1); + } + return rc; +} + +/* + * sysinfo_param() - function converts sysinfo param to int + * + * @str - user input string + * @maxset - ? + * + * returns (-1) on error + * returns > 0 on success + */ +static int +sysinfo_param(const char *str, int *maxset) +{ + if (!str || !maxset) + return (-1); + + *maxset = 4; + if (!strcmp(str, "system_name")) + return IPMI_SYSINFO_HOSTNAME; + else if (!strcmp(str, "primary_os_name")) + return IPMI_SYSINFO_PRIMARY_OS_NAME; + else if (!strcmp(str, "os_name")) + return IPMI_SYSINFO_OS_NAME; + else if (!strcmp(str, "delloem_os_version")) + return IPMI_SYSINFO_DELL_OS_VERSION; + else if (!strcmp(str, "delloem_url")) { + *maxset = 2; + return IPMI_SYSINFO_DELL_URL; + } + + return (-1); +} + +/* + * ipmi_mc_getsysinfo() - function processes the IPMI Get System Info command + * + * @intf - ipmi interface + * @param - parameter eg. 0xC0..0xFF = OEM + * @block - number of block parameters + * @set - number of set parameters + * @len - length of buffer + * @buffer - pointer to buffer + * + * returns (-1) on failure + * returns 0 on success + * returns > 0 IPMI code + */ +int +ipmi_mc_getsysinfo(struct ipmi_intf * intf, int param, int block, int set, + int len, void *buffer) +{ + uint8_t data[4]; + struct ipmi_rs *rsp = NULL; + struct ipmi_rq req = {0}; + + memset(buffer, 0, len); + memset(data, 0, 4); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_GET_SYS_INFO; + req.msg.data_len = 4; + req.msg.data = data; + + if (verbose > 1) + printf("getsysinfo: %.2x/%.2x/%.2x\n", param, block, set); + + data[0] = 0; /* get/set */ + data[1] = param; + data[2] = block; + data[3] = set; + + /* + * Format of get output is: + * u8 param_rev + * u8 selector + * u8 encoding bit[0-3]; + * u8 length + * u8 data0[14] + */ + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) + return (-1); + + if (rsp->ccode == 0) { + if (len > rsp->data_len) + len = rsp->data_len; + if (len && buffer) + memcpy(buffer, rsp->data, len); + } + return rsp->ccode; +} + +/* + * ipmi_mc_setsysinfo() - function processes the IPMI Set System Info command + * + * @intf - ipmi interface + * @len - length of buffer + * @buffer - pointer to buffer + * + * returns (-1) on failure + * returns 0 on success + * returns > 0 IPMI code + */ +int +ipmi_mc_setsysinfo(struct ipmi_intf * intf, int len, void *buffer) +{ + struct ipmi_rs *rsp = NULL; + struct ipmi_rq req = {0}; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.lun = 0; + req.msg.cmd = IPMI_SET_SYS_INFO; + req.msg.data_len = len; + req.msg.data = buffer; + + /* + * Format of set input: + * u8 param rev + * u8 selector + * u8 data1[16] + */ + rsp = intf->sendrecv(intf, &req); + if (rsp != NULL) { + return rsp->ccode; + } + return -1; +} + +static int +ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv, int is_set) +{ + char *str; + unsigned char infostr[256]; + unsigned char paramdata[18]; + int len, maxset, param, pos, rc, set; + + if (argc == 2 && strcmp(argv[1], "help") == 0) { + printf_sysinfo_usage(1); + return 0; + } + else if (argc < 2 || (is_set == 1 && argc < 3)) { + lprintf(LOG_ERR, "Not enough parameters given."); + printf_sysinfo_usage(1); + return (-1); + } + + /* Get Parameters */ + if ((param = sysinfo_param(argv[1], &maxset)) < 0) { + lprintf(LOG_ERR, "Invalid mc/bmc %s command: %s", argv[0], argv[1]); + printf_sysinfo_usage(1); + return (-1); + } + + rc = 0; + if (is_set != 0) { + str = argv[2]; + set = pos = 0; + len = strlen(str); + + /* first block holds 14 bytes, all others hold 16 */ + if ((len + 2 + 15) / 16 >= maxset) + len = (maxset * 16) - 2; + + do { + memset(paramdata, 0, sizeof(paramdata)); + paramdata[0] = param; + paramdata[1] = set; + if (set == 0) { + /* First block is special case */ + paramdata[2] = 0; /* ascii encoding */ + paramdata[3] = len; /* length */ + strncpy(paramdata + 4, str + pos, IPMI_SYSINFO_SET0_SIZE); + pos += IPMI_SYSINFO_SET0_SIZE; + } + else { + strncpy(paramdata + 2, str + pos, IPMI_SYSINFO_SETN_SIZE); + pos += IPMI_SYSINFO_SETN_SIZE; + } + rc = ipmi_mc_setsysinfo(intf, 18, paramdata); + + if (rc) + break; + + set++; + } while (pos < len); + } + else { + memset(infostr, 0, sizeof(infostr)); + /* Read blocks of data */ + pos = 0; + for (set = 0; set < maxset; set++) { + rc = ipmi_mc_getsysinfo(intf, param, set, 0, 18, paramdata); + + if (rc) + break; + + if (set == 0) { + /* First block is special case */ + if ((paramdata[2] & 0xF) == 0) { + /* Determine max number of blocks to read */ + maxset = ((paramdata[3] + 2) + 15) / 16; + } + memcpy(infostr + pos, paramdata + 4, IPMI_SYSINFO_SET0_SIZE); + pos += IPMI_SYSINFO_SET0_SIZE; + } + else { + memcpy(infostr + pos, paramdata + 2, IPMI_SYSINFO_SETN_SIZE); + pos += IPMI_SYSINFO_SETN_SIZE; + } + } + printf("%s\n", infostr); + } + if (rc < 0) { + lprintf(LOG_ERR, "%s %s set %d command failed", argv[0], argv[1], set); + } + else if (rc == 0x80) { + lprintf(LOG_ERR, "%s %s parameter not supported", argv[0], argv[1]); + } + else if (rc > 0) { + lprintf(LOG_ERR, "%s command failed: %s", argv[0], + val2str(rc, completion_code_vals)); + } + return rc; +} |